Merge "Add filter for mentioned threads in Comments Tab"
diff --git a/polygerrit-ui/app/elements/change/gr-change-summary/gr-change-summary.ts b/polygerrit-ui/app/elements/change/gr-change-summary/gr-change-summary.ts
index 2b35d6b..f4375a6 100644
--- a/polygerrit-ui/app/elements/change/gr-change-summary/gr-change-summary.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-summary/gr-change-summary.ts
@@ -582,7 +582,7 @@
return html` <gr-summary-chip
class="mentionSummary"
styleType=${SummaryChipStyles.WARNING}
- category=${CommentTabState.UNRESOLVED}
+ category=${CommentTabState.MENTIONS}
icon="alternate_email"
>
${pluralize(this.mentionCount, 'mention')}</gr-summary-chip
diff --git a/polygerrit-ui/app/elements/change/gr-change-summary/gr-change-summary_test.ts b/polygerrit-ui/app/elements/change/gr-change-summary/gr-change-summary_test.ts
index 9aa2117..dc8135e 100644
--- a/polygerrit-ui/app/elements/change/gr-change-summary/gr-change-summary_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-summary/gr-change-summary_test.ts
@@ -134,7 +134,7 @@
// Resolved threads are ignored hence mention chip count is 2
expect(mentionSummary).dom.to.equal(/* HTML */ `
<gr-summary-chip
- category="unresolved"
+ category="mentions"
class="mentionSummary"
icon="alternate_email"
styletype="warning"
diff --git a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.ts b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.ts
index a56d87d..fec995c 100644
--- a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.ts
+++ b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list.ts
@@ -17,9 +17,11 @@
import {
CommentThread,
getCommentAuthors,
+ getMentionedThreads,
hasHumanReply,
isDraft,
isDraftThread,
+ isMentionedThread,
isRobotThread,
isUnresolved,
lastUpdated,
@@ -40,6 +42,7 @@
import {resolve} from '../../../models/dependency';
import {changeModelToken} from '../../../models/change/change-model';
import {Interaction} from '../../../constants/reporting';
+import {KnownExperimentId} from '../../../services/flags/flags';
enum SortDropdownState {
TIMESTAMP = 'Latest timestamp',
@@ -192,10 +195,15 @@
@state()
draftsOnly = false;
+ @state()
+ mentionsOnly = false;
+
private readonly getChangeModel = resolve(this, changeModelToken);
private readonly reporting = getAppContext().reportingService;
+ private readonly flagsService = getAppContext().flagsService;
+
private readonly userModel = getAppContext().userModel;
constructor() {
@@ -228,6 +236,9 @@
private onCommentTabStateUpdate() {
switch (this.commentTabState?.commentTab) {
+ case CommentTabState.MENTIONS:
+ this.handleOnlyMentions();
+ break;
case CommentTabState.UNRESOLVED:
this.handleOnlyUnresolved();
break;
@@ -452,6 +463,7 @@
}
private getCommentsDropdownValue() {
+ if (this.mentionsOnly) return CommentTabState.MENTIONS;
if (this.draftsOnly) return CommentTabState.DRAFTS;
if (this.unresolvedOnly) return CommentTabState.UNRESOLVED;
return CommentTabState.SHOW_ALL;
@@ -473,6 +485,14 @@
value: CommentTabState.UNRESOLVED,
});
if (this.account) {
+ if (this.flagsService.isEnabled(KnownExperimentId.MENTION_USERS)) {
+ items.push({
+ text: `Mentions (${
+ getMentionedThreads(threads, this.account).length
+ })`,
+ value: CommentTabState.MENTIONS,
+ });
+ }
items.push({
text: `Drafts (${threads.filter(isDraftThread).length})`,
value: CommentTabState.DRAFTS,
@@ -504,6 +524,9 @@
case CommentTabState.UNRESOLVED:
this.handleOnlyUnresolved();
break;
+ case CommentTabState.MENTIONS:
+ this.handleOnlyMentions();
+ break;
case CommentTabState.DRAFTS:
this.handleOnlyDrafts();
break;
@@ -566,6 +589,9 @@
if (isRobotThread(thread) && !hasHumanReply(thread)) return false;
}
+ if (this.mentionsOnly && !isMentionedThread(thread, this.account))
+ return false;
+
if (this.draftsOnly && !isDraftThread(thread)) return false;
if (this.unresolvedOnly && !isUnresolved(thread)) return false;
@@ -575,16 +601,25 @@
private handleOnlyUnresolved() {
this.unresolvedOnly = true;
this.draftsOnly = false;
+ this.mentionsOnly = false;
+ }
+
+ private handleOnlyMentions() {
+ this.mentionsOnly = true;
+ this.unresolvedOnly = true;
+ this.draftsOnly = false;
}
private handleOnlyDrafts() {
this.draftsOnly = true;
this.unresolvedOnly = false;
+ this.mentionsOnly = false;
}
private handleAllComments() {
this.draftsOnly = false;
this.unresolvedOnly = false;
+ this.mentionsOnly = false;
}
private queryThreadElement(rootId: string): GrCommentThread | undefined {
diff --git a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_test.ts b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_test.ts
index ed06325..f6de258 100644
--- a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_test.ts
@@ -12,16 +12,23 @@
GrThreadList,
__testOnly_SortDropdownState,
} from './gr-thread-list';
-import {queryAll} from '../../../test/test-utils';
+import {queryAll, stubFlags} from '../../../test/test-utils';
import {accountOrGroupKey} from '../../../utils/account-util';
import {tap} from '@polymer/iron-test-helpers/mock-interactions';
import {
createAccountDetailWithId,
+ createComment,
+ createCommentThread,
createDraft,
createParsedChange,
createThread,
} from '../../../test/test-data-generators';
-import {AccountId, NumericChangeId, Timestamp} from '../../../api/rest-api';
+import {
+ AccountId,
+ EmailAddress,
+ NumericChangeId,
+ Timestamp,
+} from '../../../api/rest-api';
import {
RobotId,
UrlEncodedCommentId,
@@ -498,6 +505,54 @@
assert.equal(element.getDisplayedThreads().length, 2);
});
+ suite('mention threads', () => {
+ let mentionedThreads: CommentThread[];
+ setup(async () => {
+ stubFlags('isEnabled').returns(true);
+ mentionedThreads = [
+ createCommentThread([
+ {
+ ...createComment(),
+ message: 'random text with no emails',
+ },
+ ]),
+ // Resolved thread does not contribute to the count
+ createCommentThread([
+ {
+ ...createComment(),
+ message: '@abcd@def.com please take a look',
+ },
+ {
+ ...createComment(),
+ message: '@abcd@def.com please take a look again at this',
+ },
+ ]),
+ createCommentThread([
+ {
+ ...createComment(),
+ message: '@abcd@def.com this is important',
+ unresolved: true,
+ },
+ ]),
+ ];
+ element.account!.email = 'abcd@def.com' as EmailAddress;
+ element.threads.push(...mentionedThreads);
+ element.requestUpdate();
+ await element.updateComplete;
+ });
+
+ test('mentions filter', async () => {
+ const filterDropdown = queryAndAssert<GrDropdownList>(
+ element,
+ '#filterDropdown'
+ );
+ filterDropdown.value = CommentTabState.MENTIONS;
+ await filterDropdown.updateComplete;
+ await element.updateComplete;
+ assert.deepEqual(element.getDisplayedThreads(), [mentionedThreads[2]]);
+ });
+ });
+
suite('hideDropdown', () => {
test('header hidden for hideDropdown=true', async () => {
element.hideDropdown = true;
diff --git a/polygerrit-ui/app/types/events.ts b/polygerrit-ui/app/types/events.ts
index b732295..2a568dc 100644
--- a/polygerrit-ui/app/types/events.ts
+++ b/polygerrit-ui/app/types/events.ts
@@ -225,6 +225,7 @@
UNRESOLVED = 'unresolved',
DRAFTS = 'drafts',
SHOW_ALL = 'show all',
+ MENTIONS = 'mentions',
}
export interface ChecksTabState {
statusOrCategory?: RunStatus | Category;
diff --git a/polygerrit-ui/app/utils/comment-util.ts b/polygerrit-ui/app/utils/comment-util.ts
index 911c821..f531698 100644
--- a/polygerrit-ui/app/utils/comment-util.ts
+++ b/polygerrit-ui/app/utils/comment-util.ts
@@ -289,6 +289,16 @@
return isDraft(getLastComment(thread));
}
+export function isMentionedThread(
+ thread: CommentThread,
+ account?: AccountInfo
+) {
+ if (!account?.email) return false;
+ return getMentionedUsers(thread)
+ .map(v => v.email)
+ .includes(account.email);
+}
+
export function isRobotThread(thread: CommentThread): boolean {
return isRobot(getFirstComment(thread));
}