Render Code Review votes in patchset picker https://imgur.com/a/U7Mjj4E VoteChip component is already used in the Submit Requirements section. We only limit the values to Code Review vote. Release-Notes: skip Google-bug-id: b/230605262 Change-Id: I0fbc665865fb542d5482d54c1dc9bd067c0751b5
diff --git a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.ts b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.ts index c5a72fc..fb2a2b7 100644 --- a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.ts +++ b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.ts
@@ -22,8 +22,12 @@ } from '../../../utils/patch-set-util'; import {ReportingService} from '../../../services/gr-reporting/gr-reporting'; import { + AccountInfo, + ApprovalInfo, BasePatchSetNum, + ChangeInfo, EDIT, + LabelInfo, NumericChangeId, PARENT, PatchSetNum, @@ -38,7 +42,7 @@ DropdownItem, GrDropdownList, } from '../../shared/gr-dropdown-list/gr-dropdown-list'; -import {EditRevisionInfo} from '../../../types/types'; +import {EditRevisionInfo, ParsedChangeInfo} from '../../../types/types'; import {a11yStyles} from '../../../styles/gr-a11y-styles'; import {sharedStyles} from '../../../styles/shared-styles'; import {css, html, LitElement, nothing} from 'lit'; @@ -55,6 +59,9 @@ import {changeViewModelToken} from '../../../models/views/change'; import {fireNoBubbleNoCompose} from '../../../utils/event-util'; import {FlagsService, KnownExperimentId} from '../../../services/flags/flags'; +import {userModelToken} from '../../../models/user/user-model'; +import {getCodeReviewLabel} from '../../../utils/label-util'; +import {getCodeReviewVotesFromMessage} from '../../../utils/message-util'; // Maximum length for patch set descriptions. const PATCH_DESC_MAX_LENGTH = 500; @@ -102,6 +109,12 @@ @state() changeNum?: NumericChangeId; + @state() + change?: ParsedChangeInfo; + + @state() + selfAccount?: AccountInfo; + @property() path?: string; @@ -131,6 +144,8 @@ private readonly flags: FlagsService = getAppContext().flagsService; + private readonly getUserModel = resolve(this, userModelToken); + private readonly getCommentsModel = resolve(this, commentsModelToken); private readonly getChangeModel = resolve(this, changeModelToken); @@ -147,6 +162,17 @@ subscribe( this, () => this.getChangeModel().change$, + x => (this.change = x) + ); + subscribe( + this, + () => this.getUserModel().account$, + x => (this.selfAccount = x) + ); + + subscribe( + this, + () => this.getChangeModel().change$, x => (this.revisionInfo = x ? new RevisionInfoClass(x) : undefined) ); subscribe( @@ -357,6 +383,8 @@ !!this.path /* ignorePatchsetLevelComments*/ ), deemphasizeReason: this.computeDeemphasizeReason(sha), + vote: this.computeVote(this.selfAccount, this.change, patchNum), + label: this.computeCodeReviewLabel(this.change), }; const date = this.computePatchSetDate(patchNum); if (date) { @@ -376,6 +404,36 @@ : undefined; } + private computeVote( + reviewer?: AccountInfo, + change?: ParsedChangeInfo, + revisionNum?: PatchSetNum + ): ApprovalInfo | undefined { + if (!change || !reviewer || !revisionNum) return undefined; + + const codeReviewVotes = getCodeReviewVotesFromMessage( + change as ChangeInfo, + reviewer + ); + const vote = codeReviewVotes.get(revisionNum); + + if (vote) { + return { + ...reviewer, + value: Number(vote.value), + }; + } + + return undefined; + } + + private computeCodeReviewLabel( + change?: ParsedChangeInfo + ): LabelInfo | undefined { + if (!change?.labels) return; + return getCodeReviewLabel(change.labels); + } + /** * The basePatchNum should always be <= patchNum -- because sortedRevisions * is sorted in reverse order (higher patchset nums first), invalid base
diff --git a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.ts b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.ts index 097da3c..ca93e1a 100644 --- a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.ts +++ b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.ts
@@ -12,7 +12,9 @@ import {ChangeComments} from '../gr-comment-api/gr-comment-api'; import {queryAll, stubReporting} from '../../../test/test-utils'; import { + AccountId, BasePatchSetNum, + ChangeMessageId, CommentInfo, EDIT, PARENT, @@ -26,6 +28,7 @@ import {EditRevisionInfo, ParsedChangeInfo} from '../../../types/types'; import {SpecialFilePath} from '../../../constants/constants'; import { + createAccountDetailWithId, createChangeViewState, createEditRevision, createParsedChange, @@ -46,6 +49,7 @@ changeModelToken, RevisionFileUpdateStatus, } from '../../../models/change/change-model'; +import {userModelToken} from '../../../models/user/user-model'; type RevIdToRevisionInfo = { [revisionId: string]: RevisionInfo | EditRevisionInfo; @@ -149,12 +153,14 @@ date: '2020-02-01 01:02:03.000000000' as Timestamp, commentThreads: [], deemphasizeReason: undefined, + label: undefined, + vote: undefined, } as DropdownItem, { - text: 'Base | ', triggerText: 'Base', value: PARENT, bottomText: undefined, + text: 'Base | ', } as DropdownItem, ]; element.patchNum = 2 as PatchSetNumber; @@ -265,6 +271,8 @@ value: EDIT, commentThreads: [], deemphasizeReason: undefined, + vote: undefined, + label: undefined, }, { triggerText: 'Patchset 3', @@ -275,6 +283,8 @@ date: '2020-02-01 01:02:03.000000000' as Timestamp, commentThreads: [], deemphasizeReason: undefined, + vote: undefined, + label: undefined, } as DropdownItem, { triggerText: 'Patchset 2', @@ -285,6 +295,8 @@ date: '2020-02-01 01:02:03.000000000' as Timestamp, commentThreads: [], deemphasizeReason: undefined, + vote: undefined, + label: undefined, } as DropdownItem, ]; @@ -559,3 +571,84 @@ ); }); }); + +suite('gr-patch-range-select with votes', () => { + let element: GrPatchRangeSelect; + + setup(async () => { + const changeModel = testResolver(changeModelToken); + const userModel = testResolver(userModelToken); + + const viewModel = testResolver(changeViewModelToken); + viewModel.setState({ + ...createChangeViewState(), + patchNum: 2 as RevisionPatchSetNum, + basePatchNum: PARENT, + }); + + const account = createAccountDetailWithId(1); + userModel.setAccount(account); + + const change: ParsedChangeInfo = { + ...createParsedChange(), + messages: [ + { + id: '1' as ChangeMessageId, + author: {_account_id: 1 as AccountId}, + date: '2020-01-01 10:00:00' as Timestamp, + message: 'Patch Set 1: Code-Review+1', + _revision_number: 1 as PatchSetNumber, + }, + { + id: '2' as ChangeMessageId, + author: {_account_id: 1 as AccountId}, + date: '2020-01-01 11:00:00' as Timestamp, + message: 'Patch Set 2: Code-Review-1', + _revision_number: 2 as PatchSetNumber, + }, + ], + revisions: { + sha1: createRevision(1), + sha2: createRevision(2), + }, + labels: { + 'Code-Review': { + values: { + '-1': 'No', + ' 0': 'No score', + '+1': 'Yes', + }, + }, + }, + }; + + changeModel.updateStateChange(change); + + element = await fixture( + html`<gr-patch-range-select></gr-patch-range-select>` + ); + await element.updateComplete; + + // Unclear why but it's required twice + changeModel.updateStateChange(change); + await element.updateComplete; + }); + + test('shows votes in dropdown', async () => { + const dropdown = queryAndAssert<GrDropdownList>( + element, + '#patchNumDropdown' + ); + await dropdown.updateComplete; + + dropdown.open(); + await dropdown.updateComplete; + + const menu = dropdown.shadowRoot?.querySelector('md-menu'); + assert.isDefined(menu); + + const voteChip = menu!.querySelector('gr-vote-chip'); + assert.isDefined(voteChip); + assert.equal(voteChip!.vote?.value, -1); + }); +});
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.ts b/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.ts index 3ace525..389b53c 100644 --- a/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.ts +++ b/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.ts
@@ -7,8 +7,10 @@ import '../gr-button/gr-button'; import '../gr-date-formatter/gr-date-formatter'; import '../gr-file-status/gr-file-status'; +import '../gr-vote-chip/gr-vote-chip'; import {css, html, LitElement, nothing, PropertyValues} from 'lit'; import {customElement, property, query, state} from 'lit/decorators.js'; +import {ApprovalInfo, LabelInfo} from '../../../api/rest-api'; import {CommentThread, Timestamp} from '../../../types/common'; import {NormalizedFileInfo} from '../../change/gr-file-list/gr-file-list'; import {GrButton} from '../gr-button/gr-button'; @@ -47,6 +49,8 @@ file?: NormalizedFileInfo; commentThreads?: CommentThread[]; deemphasizeReason?: string; + vote?: ApprovalInfo; + label?: LabelInfo; } declare global { @@ -180,6 +184,9 @@ font-family: var(--trigger-style-font-family); --gr-button-text-color: var(--trigger-style-text-color); } + gr-vote-chip { + margin-right: var(--spacing-s); + } gr-date-formatter { color: var(--deemphasized-text-color); margin-left: var(--spacing-xxl); @@ -398,6 +405,16 @@ )} </div> ${when( + item.vote, + () => + html` <div> + <gr-vote-chip + .vote=${item.vote} + .label=${item.label} + ></gr-vote-chip> + </div>` + )} + ${when( item.date, () => html` <gr-date-formatter .dateStr=${item.date}></gr-date-formatter>