From patchwork Sun Apr 15 22:54:02 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephen Finucane X-Patchwork-Id: 898339 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 40PRjm5DnPz9s1R for ; Mon, 16 Apr 2018 08:57:32 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=that.guru Authentication-Results: ozlabs.org; dkim=fail reason="key not found in DNS" (0-bit key; unprotected) header.d=that.guru header.i=@that.guru header.b="kfrOOaJc"; dkim-atps=neutral Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 40PRjm3d6czF1RM for ; Mon, 16 Apr 2018 08:57:32 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=that.guru Authentication-Results: lists.ozlabs.org; dkim=fail reason="key not found in DNS" (0-bit key; unprotected) header.d=that.guru header.i=@that.guru header.b="kfrOOaJc"; dkim-atps=neutral X-Original-To: patchwork@lists.ozlabs.org Delivered-To: patchwork@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=none (mailfrom) smtp.mailfrom=that.guru (client-ip=23.83.222.35; helo=chocolate.ash.relay.mailchannels.net; envelope-from=stephen@that.guru; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=that.guru Authentication-Results: lists.ozlabs.org; dkim=fail reason="key not found in DNS" (0-bit key; unprotected) header.d=that.guru header.i=@that.guru header.b="kfrOOaJc"; dkim-atps=neutral Received: from chocolate.ash.relay.mailchannels.net (chocolate.ash.relay.mailchannels.net [23.83.222.35]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 40PRfC46jfzF1sY for ; Mon, 16 Apr 2018 08:54:26 +1000 (AEST) X-Sender-Id: 5xi41l16bi|x-authuser|stephen@that.guru Received: from relay.mailchannels.net (localhost [127.0.0.1]) by relay.mailchannels.net (Postfix) with ESMTP id B5A2F121E9E for ; Sun, 15 Apr 2018 22:54:20 +0000 (UTC) Received: from one.mxroute.com (unknown [100.96.15.83]) (Authenticated sender: 5xi41l16bi) by relay.mailchannels.net (Postfix) with ESMTPA id 42E8D1220CE for ; Sun, 15 Apr 2018 22:54:20 +0000 (UTC) X-Sender-Id: 5xi41l16bi|x-authuser|stephen@that.guru Received: from one.mxroute.com (one-outgoing.mxroute.com [172.18.43.43]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384) by 0.0.0.0:2500 (trex/5.14.1); Sun, 15 Apr 2018 22:54:20 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: 5xi41l16bi|x-authuser|stephen@that.guru X-MailChannels-Auth-Id: 5xi41l16bi X-Cure-Stretch: 00f85c366a61f9e9_1523832860537_202848429 X-MC-Loop-Signature: 1523832860537:3522564242 X-MC-Ingress-Time: 1523832860537 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=that.guru; s=default; h=References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Sender:Reply-To:MIME-Version:Content-Type:Content-Transfer-Encoding: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=OVUc5HxxnMfp6+/AGkBRL1u8h686AP8O6mNZaUbHNxM=; b=kfrOOaJc58rmyvDeyIO5G5xAER C9IM7rzN8prrpyWAiwKKyieRtiHQsqLHSbP6bFPiZZ4hy0lWPBvriMcQdrswLu/Tbk21ZyecmvsCx fimv6lMv3b3mktzmwdgXA70kJPITPeZsU/SOVc1F8aeN5icdM4xqUGJfdD/kgDGJ+2hCaR1+RLuRw lOHnbfxMZNiI9WGjqnV1Pu+5IdgdiuYdq9lJ9Fhn5fAWfRFh0hiqOmXsouSuTpd0inD8f4kuWlfGM rcZA0+0vlz6KCbAWv/oYgGTCA6AmH6eiXRmA2co5qXbxXRErzifOBxr2cjKrdwdu6CJoVWYZk0IWY GWvGb4Jw==; From: Stephen Finucane To: patchwork@lists.ozlabs.org Subject: [PATCH 08/11] views: Add patch labels to web UI Date: Sun, 15 Apr 2018 23:54:02 +0100 Message-Id: <20180415225405.1354-9-stephen@that.guru> X-Mailer: git-send-email 2.14.3 In-Reply-To: <20180415225405.1354-1-stephen@that.guru> References: <20180415225405.1354-1-stephen@that.guru> X-AuthUser: stephen@that.guru X-BeenThere: patchwork@lists.ozlabs.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: Patchwork development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Patchwork" Nothing too complicated here. The forms we have for this need some serious cleanup/beautification, but that's a problem for another day. Signed-off-by: Stephen Finucane --- patchwork/forms.py | 17 ++++++++++++++++- patchwork/templates/patchwork/patch-list.html | 8 ++++++++ patchwork/templates/patchwork/submission.html | 7 +++++++ patchwork/templatetags/patch.py | 24 ++++++++++++++++++++++++ patchwork/views/__init__.py | 2 +- 5 files changed, 56 insertions(+), 2 deletions(-) diff --git a/patchwork/forms.py b/patchwork/forms.py index e8a4955e..2c425a81 100644 --- a/patchwork/forms.py +++ b/patchwork/forms.py @@ -26,6 +26,7 @@ from django.db.utils import ProgrammingError from patchwork.models import Bundle from patchwork.models import Patch +from patchwork.models import Label from patchwork.models import State from patchwork.models import UserProfile @@ -136,10 +137,14 @@ class PatchForm(forms.ModelForm): super(PatchForm, self).__init__(instance=instance, *args, **kwargs) self.fields['delegate'] = forms.ModelChoiceField( queryset=_get_delegate_qs(project, instance), required=False) + self.fields['labels'] = forms.ModelMultipleChoiceField( + queryset=Label.objects.filter( + Q(project=project) | Q(project=None)), + required=False) class Meta: model = Patch - fields = ['state', 'archived', 'delegate'] + fields = ['state', 'archived', 'delegate', 'labels'] class OptionalModelChoiceField(forms.ModelChoiceField): @@ -192,6 +197,10 @@ class MultiplePatchForm(forms.Form): super(MultiplePatchForm, self).__init__(*args, **kwargs) self.fields['delegate'] = OptionalModelChoiceField( queryset=_get_delegate_qs(project=project), required=False) + self.fields['labels'] = forms.ModelMultipleChoiceField( + queryset=Label.objects.filter( + Q(project=project) | Q(project=None)), + required=False) def save(self, instance, commit=True): opts = instance.__class__._meta @@ -213,6 +222,12 @@ class MultiplePatchForm(forms.Form): setattr(instance, f.name, data[f.name]) + for f in opts.many_to_many: + if f.name not in data: + continue + + setattr(instance, f.name, data[f.name]) + if commit: instance.save() return instance diff --git a/patchwork/templates/patchwork/patch-list.html b/patchwork/templates/patchwork/patch-list.html index 71c1ba92..2361170e 100644 --- a/patchwork/templates/patchwork/patch-list.html +++ b/patchwork/templates/patchwork/patch-list.html @@ -192,6 +192,7 @@ $(document).ready(function() { {{ patch.name|default:"[no subject]"|truncatechars:100 }} + {{ patch|patch_labels }} {% with patch.series.all.0 as series %} @@ -247,6 +248,13 @@ $(document).ready(function() { {{ patchform.archived.errors }} + + Label: + + {{ patchform.labels }} + {{ patchform.labels.errors }} + + diff --git a/patchwork/templates/patchwork/submission.html b/patchwork/templates/patchwork/submission.html index e817713f..538d35ee 100644 --- a/patchwork/templates/patchwork/submission.html +++ b/patchwork/templates/patchwork/submission.html @@ -152,6 +152,13 @@ function toggle_div(link_id, headers_id) {{ patchform.archived.errors }} + + Labels: + + {{ patchform.labels }} + {{ patchform.labels.errors }} + + diff --git a/patchwork/templatetags/patch.py b/patchwork/templatetags/patch.py index 4350e092..1dc96f95 100644 --- a/patchwork/templatetags/patch.py +++ b/patchwork/templatetags/patch.py @@ -57,6 +57,30 @@ def patch_checks(patch): ' '.join([str(counts[state]) for state in required]))) +@register.filter(name='patch_labels') +def patch_labels(patch): + + def text_color(hex_color): + """Generate the ideal text color given a background color. + + From https://www.w3.org/TR/AERT/#color-contrast + """ + red, green, blue = [ + int(hex_color.lstrip('#')[i:i + 2], 16) for i in (0, 2, 4)] + brightness = (red * 299 + green * 587 + blue * 114) / 1000 + + return '#000' if brightness >= 123 else '#fff' + + output = [] + for label in patch.labels.all(): + style = 'background-color: %s; color: %s' % ( + label.color, text_color(label.color)) + output.append('%s' % ( + style, label.name)) + + return mark_safe(''.join(output)) + + @register.filter(name='state_class') def state_class(state): return '-'.join(state.split()) diff --git a/patchwork/views/__init__.py b/patchwork/views/__init__.py index f8d23a38..654cf42f 100644 --- a/patchwork/views/__init__.py +++ b/patchwork/views/__init__.py @@ -288,7 +288,7 @@ def generic_list(request, project, view, view_args=None, filter_settings=None, patches = patches.select_related('state', 'submitter', 'delegate') # we also need checks and series - patches = patches.prefetch_related('check_set', 'series') + patches = patches.prefetch_related('check_set', 'series', 'labels') paginator = Paginator(request, patches)