commit cbee28a79efc1b88eed18dcb0ee499149d074d14 Author: Ben Rohlfs Date: Wed Sep 30 10:37:54 2020 +0200 Add comment icon to CR column of the dashboard Users would really like information about unresolved comments on the dashboard, but a dedicated column would take too much space. So let's just show a comment icon in the CR column, and don't even show the number of unresolved comments, just on hover. Also replaces the checkmark and x characters by icons. Screenshots: https://imgur.com/a/vcprgU9 Change-Id: Ib1b8584190b967b00ef3294b2c0daaa4a7a035b9 diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.ts b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.ts index 5d898bd..dec8cd8 100644 --- a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.ts +++ b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.ts @@ -49,13 +49,24 @@ import { } from '../../../types/common'; import {hasOwnProperty} from '../../../utils/common-util'; -enum CHANGE_SIZE { +enum ChangeSize { XS = 10, SMALL = 50, MEDIUM = 250, LARGE = 1000, } +// export for testing +export enum LabelCategory { + NOT_APPLICABLE = 'NOT_APPLICABLE', + APPROVED = 'APPROVED', + POSITIVE = 'POSITIVE', + NEUTRAL = 'NEUTRAL', + UNRESOLVED_COMMENTS = 'UNRESOLVED_COMMENTS', + NEGATIVE = 'NEGATIVE', + REJECTED = 'REJECTED', +} + // How many reviewers should be shown with an account-label? const PRIMARY_REVIEWERS_COUNT = 2; @@ -131,9 +142,15 @@ class GrChangeListItem extends ChangeTableMixin( _computeLabelTitle(change: ChangeInfo | undefined, labelName: string) { const label: QuickLabelInfo | undefined = change?.labels?.[labelName]; - if (!label) { + const category = this._computeLabelCategory(change, labelName); + if (!label || category === LabelCategory.NOT_APPLICABLE) { return 'Label not applicable'; } + if (category === LabelCategory.UNRESOLVED_COMMENTS) { + const num = change?.unresolved_comment_count ?? 0; + const plural = num > 1 ? 's' : ''; + return `${num} unresolved comment${plural}`; + } const significantLabel = label.rejected || label.approved || label.disliked || label.recommended; if (significantLabel && significantLabel.name) { @@ -143,58 +160,90 @@ class GrChangeListItem extends ChangeTableMixin( } _computeLabelClass(change: ChangeInfo | undefined, labelName: string) { - const label: QuickLabelInfo | undefined = change?.labels?.[labelName]; - // Mimic a Set. - // TODO(TS): replace with `u_green` to remove the quotes and brackets - const classes: { - cell: boolean; - label: boolean; - ['u-green']?: boolean; - ['u-monospace']?: boolean; - ['u-red']?: boolean; - ['u-gray-background']?: boolean; - } = { - cell: true, - label: true, - }; - if (label) { - if (label.approved) { - classes['u-green'] = true; - } - if (label.value === 1) { - classes['u-monospace'] = true; - classes['u-green'] = true; - } else if (label.value === -1) { - classes['u-monospace'] = true; - classes['u-red'] = true; - } - if (label.rejected) { - classes['u-red'] = true; - } - } else { - classes['u-gray-background'] = true; + const category = this._computeLabelCategory(change, labelName); + const classes = ['cell', 'label']; + switch (category) { + case LabelCategory.NOT_APPLICABLE: + classes.push('u-gray-background'); + break; + case LabelCategory.APPROVED: + classes.push('u-green'); + break; + case LabelCategory.POSITIVE: + classes.push('u-monospace'); + classes.push('u-green'); + break; + case LabelCategory.NEGATIVE: + classes.push('u-monospace'); + classes.push('u-red'); + break; + case LabelCategory.REJECTED: + classes.push('u-red'); + break; } - return Object.keys(classes).sort().join(' '); + return classes.sort().join(' '); } - _computeLabelValue(change: ChangeInfo | undefined, labelName: string) { + _computeHasLabelIcon(change: ChangeInfo | undefined, labelName: string) { + return this._computeLabelIcon(change, labelName) !== ''; + } + + _computeLabelIcon(change: ChangeInfo | undefined, labelName: string): string { + const category = this._computeLabelCategory(change, labelName); + switch (category) { + case LabelCategory.APPROVED: + return 'gr-icons:check'; + case LabelCategory.UNRESOLVED_COMMENTS: + return 'gr-icons:comment'; + case LabelCategory.REJECTED: + return 'gr-icons:close'; + default: + return ''; + } + } + + _computeLabelCategory(change: ChangeInfo | undefined, labelName: string) { const label: QuickLabelInfo | undefined = change?.labels?.[labelName]; if (!label) { - return ''; - } - if (label.approved) { - return '✓'; + return LabelCategory.NOT_APPLICABLE; } if (label.rejected) { - return '✕'; + return LabelCategory.REJECTED; + } + if (label.value && label.value < 0) { + return LabelCategory.NEGATIVE; + } + if (change?.unresolved_comment_count && labelName === 'Code-Review') { + return LabelCategory.UNRESOLVED_COMMENTS; + } + if (label.approved) { + return LabelCategory.APPROVED; } if (label.value && label.value > 0) { - return `+${label.value}`; + return LabelCategory.POSITIVE; } - if (label.value && label.value < 0) { - return label.value; + return LabelCategory.NEUTRAL; + } + + _computeLabelValue(change: ChangeInfo | undefined, labelName: string) { + const label: QuickLabelInfo | undefined = change?.labels?.[labelName]; + const category = this._computeLabelCategory(change, labelName); + switch (category) { + case LabelCategory.NOT_APPLICABLE: + return ''; + case LabelCategory.APPROVED: + return '\u2713'; // ✓ + case LabelCategory.POSITIVE: + return `+${label?.value}`; + case LabelCategory.NEUTRAL: + return ''; + case LabelCategory.UNRESOLVED_COMMENTS: + return 'u'; + case LabelCategory.NEGATIVE: + return `${label?.value}`; + case LabelCategory.REJECTED: + return '\u2715'; // ✕ } - return ''; } _computeRepoUrl(change?: ChangeInfo) { @@ -319,13 +368,13 @@ class GrChangeListItem extends ChangeTableMixin( if (isNaN(delta) || delta === 0) { return null; // Unknown } - if (delta < CHANGE_SIZE.XS) { + if (delta < ChangeSize.XS) { return 'XS'; - } else if (delta < CHANGE_SIZE.SMALL) { + } else if (delta < ChangeSize.SMALL) { return 'S'; - } else if (delta < CHANGE_SIZE.MEDIUM) { + } else if (delta < ChangeSize.MEDIUM) { return 'M'; - } else if (delta < CHANGE_SIZE.LARGE) { + } else if (delta < ChangeSize.LARGE) { return 'L'; } else { return 'XL'; diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_html.ts b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_html.ts index e0c9ac3..5316fe5 100644 --- a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_html.ts +++ b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_html.ts @@ -92,10 +92,12 @@ export const htmlTemplate = html` font-size: var(--font-size-mono); line-height: var(--line-height-mono); } - .u-green { + .u-green, + .u-green iron-icon { color: var(--positive-green-text-color); } - .u-red { + .u-red, + .u-red iron-icon { color: var(--negative-red-text-color); } .u-gray-background { @@ -108,6 +110,9 @@ export const htmlTemplate = html` .cell.label { font-weight: var(--font-weight-normal); } + .cell.label iron-icon { + vertical-align: top; + } .lastChildHidden:last-of-type { display: none; } @@ -278,7 +283,12 @@ export const htmlTemplate = html` title$="[[_computeLabelTitle(change, labelName)]]" class$="[[_computeLabelClass(change, labelName)]]" > - [[_computeLabelValue(change, labelName)]] + +