Skip to content

Commit a0ae045

Browse files
jchampioJelteF
andauthored
Add tags to patches (#69)
A Tag is an arbitrary label for a patch in the Commitfest UI. Other than helping users identify patches of interest, it has no other semantic meaning to the CF application. This addresses #11 and #67. Tags are created using the administrator interface. They consist of a unique name and a background color. The color should be sent from compliant browsers in `#rrggbb` format, which is stored without backend validation; to avoid later CSS injection, any non-conforming values are replaced with black during rendering. It also includes some javascript to help admins pick colors that aren't completely eye-gouging, by putting up an (ignorable) warning if we don't meet baseline [WCAG recommendations](https://www.w3.org/WAI/WCAG22/Techniques/general/G18.html) on text contrast. ## Notes - To avoid putting a separate name+color copy of every tag into each row of the `patchlist` query, I instead grab the tag IDs and look them up in a map at render time. I think this requires `@transaction.atomic` to tie the map and patches together, which I've added across the entire view for simplicity. - Backend validation for the color didn't make a whole lot of sense to me, since only admins can create tags and we escape at time-of-use anyway. ## Screenshots Admin interface: ![image](https://github.com/user-attachments/assets/8061a2d1-1d5b-456b-99bb-4af5d6dc79fc) User interface: ![image](https://github.com/user-attachments/assets/9c95b307-c6e2-48c8-bd65-881c08429a96) --------- Co-authored-by: Jelte Fennema-Nio <[email protected]>
1 parent 58cdf34 commit a0ae045

File tree

16 files changed

+746
-21
lines changed

16 files changed

+746
-21
lines changed

biome.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"ignore": [],
1111
"include": [
1212
"media/commitfest/js/commitfest.js",
13+
"media/commitfest/js/change_tag.js",
1314
"media/commitfest/css/commitfest.css",
1415
"biome.json"
1516
]

media/commitfest/js/change_tag.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// An input validator for the color picker. Points out low-contrast tag color
2+
// choices.
3+
const inputs = document.getElementsByClassName("color-picker");
4+
for (let i = 0; i < inputs.length; i++) {
5+
inputs[i].addEventListener("change", (event) => {
6+
// Don't do anything if the color code doesn't pass default validity.
7+
const element = event.target;
8+
element.setCustomValidity("");
9+
if (!element.validity.valid) {
10+
return;
11+
}
12+
13+
// Break the #rrggbb color code into RGB components.
14+
color = Number.parseInt(element.value.substr(1), 16);
15+
red = ((color & 0xff0000) >> 16) / 255;
16+
green = ((color & 0x00ff00) >> 8) / 255;
17+
blue = (color & 0x0000ff) / 255;
18+
19+
// Compare the contrast ratio against white. All the magic math comes from
20+
// Web Content Accessibility Guidelines (WCAG) 2.2, Technique G18:
21+
//
22+
// https://www.w3.org/WAI/WCAG22/Techniques/general/G18.html
23+
//
24+
function l(val) {
25+
if (val <= 0.04045) {
26+
return val / 12.92;
27+
}
28+
return ((val + 0.055) / 1.055) ** 2.4;
29+
}
30+
31+
lum = 0.2126 * l(red) + 0.7152 * l(green) + 0.0722 * l(blue);
32+
contrast = (1 + 0.05) / (lum + 0.05);
33+
34+
// Complain if we're below WCAG 2.2 recommendations.
35+
if (contrast < 4.5) {
36+
element.setCustomValidity(
37+
`Consider choosing a darker color. (Tag text is small and white.)\n\nContrast ratio: ${Math.trunc(contrast * 10) / 10} (< 4.5)`,
38+
);
39+
40+
// The admin form uses novalidate, so manually display the browser's
41+
// validity popup. (The user can still ignore it if desired.)
42+
element.reportValidity();
43+
}
44+
});
45+
}

pgcommitfest/commitfest/admin.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
from django.contrib import admin
2+
from django.forms import widgets
23

34
from .models import (
45
CfbotBranch,
56
CfbotTask,
7+
ColorField,
68
CommitFest,
79
Committer,
810
MailThread,
911
MailThreadAttachment,
1012
Patch,
1113
PatchHistory,
1214
PatchOnCommitFest,
15+
Tag,
1316
TargetVersion,
1417
Topic,
1518
)
@@ -38,8 +41,26 @@ class MailThreadAttachmentAdmin(admin.ModelAdmin):
3841
)
3942

4043

44+
class ColorInput(widgets.Input):
45+
"""
46+
A color picker widget.
47+
"""
48+
49+
input_type = "color"
50+
template_name = "color_input.html"
51+
52+
53+
class TagAdmin(admin.ModelAdmin):
54+
# Customize the Tag form with a color picker and soft validation.
55+
change_form_template = "change_tag_form.html"
56+
formfield_overrides = {
57+
ColorField: {"widget": ColorInput},
58+
}
59+
60+
4161
admin.site.register(Committer, CommitterAdmin)
4262
admin.site.register(CommitFest)
63+
admin.site.register(Tag, TagAdmin)
4364
admin.site.register(Topic)
4465
admin.site.register(Patch, PatchAdmin)
4566
admin.site.register(PatchHistory)

0 commit comments

Comments
 (0)