Merge "Fix addition of groups as reviewer."
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-reviewer-flow/gr-change-list-reviewer-flow.ts b/polygerrit-ui/app/elements/change-list/gr-change-list-reviewer-flow/gr-change-list-reviewer-flow.ts
index ab116f1..f72d1ef 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-reviewer-flow/gr-change-list-reviewer-flow.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-reviewer-flow/gr-change-list-reviewer-flow.ts
@@ -31,13 +31,10 @@
 import {allSettled} from '../../../utils/async-util';
 import {listForSentence, pluralize} from '../../../utils/string-util';
 import {getDisplayName} from '../../../utils/display-name-util';
-import {
-  AccountInput,
-  GrAccountList,
-} from '../../shared/gr-account-list/gr-account-list';
+import {GrAccountList} from '../../shared/gr-account-list/gr-account-list';
 import {getReplyByReason} from '../../../utils/attention-set-util';
 import {intersection} from '../../../utils/common-util';
-import {accountKey, getUserId} from '../../../utils/account-util';
+import {AccountInput, accountKey, getUserId} from '../../../utils/account-util';
 import {ValueChangedEvent} from '../../../types/events';
 import {fireAlert, fireReload} from '../../../utils/event-util';
 import {GrDialog} from '../../shared/gr-dialog/gr-dialog';
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts
index a9c472f..b88e893 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts
@@ -22,22 +22,21 @@
   ReviewerState,
   SpecialFilePath,
 } from '../../../constants/constants';
+
 import {
+  AccountInfoInput,
+  AccountInput,
+  AccountInputDetail,
   getUserId,
+  GroupInfoInput,
   isAccountNewlyAdded,
+  RawAccountInput,
   removeServiceUsers,
   toReviewInput,
 } from '../../../utils/account-util';
 import {TargetElement} from '../../../api/plugin';
 import {isDefined, ParsedChangeInfo} from '../../../types/types';
-import {
-  AccountInfoInput,
-  AccountInput,
-  AccountInputDetail,
-  GrAccountList,
-  GroupInfoInput,
-  RawAccountInput,
-} from '../../shared/gr-account-list/gr-account-list';
+import {GrAccountList} from '../../shared/gr-account-list/gr-account-list';
 import {
   AccountId,
   AccountInfo,
diff --git a/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list.ts b/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list.ts
index 9045dd6..e4490a2 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list.ts
+++ b/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list.ts
@@ -13,7 +13,6 @@
   GroupInfo,
   EmailAddress,
   SuggestedReviewerGroupInfo,
-  SuggestedReviewerAccountInfo,
   SuggestedReviewerInfo,
   isGroup,
 } from '../../../types/common';
@@ -21,7 +20,14 @@
 import {GrAccountEntry} from '../gr-account-entry/gr-account-entry';
 import {GrAccountChip} from '../gr-account-chip/gr-account-chip';
 import {fire, fireAlert} from '../../../utils/event-util';
-import {getUserId, isAccountNewlyAdded} from '../../../utils/account-util';
+import {
+  AccountInput,
+  getUserId,
+  isAccountNewlyAdded,
+  isAccountObject,
+  isSuggestedReviewerGroupInfo,
+  RawAccountInput,
+} from '../../../utils/account-util';
 import {LitElement, css, html, PropertyValues} from 'lit';
 import {customElement, property, query, state} from 'lit/decorators.js';
 import {sharedStyles} from '../../../styles/shared-styles';
@@ -51,42 +57,6 @@
     'gr-account-list': GrAccountList;
   }
 }
-export interface AccountInputDetail {
-  account: AccountInput;
-}
-
-/** Supported input to be added */
-export type RawAccountInput =
-  | string
-  | SuggestedReviewerAccountInfo
-  | SuggestedReviewerGroupInfo;
-
-// type guards for SuggestedReviewerAccountInfo and SuggestedReviewerGroupInfo
-function isAccountObject(
-  x: RawAccountInput
-): x is SuggestedReviewerAccountInfo {
-  return !!(x as SuggestedReviewerAccountInfo).account;
-}
-
-function isSuggestedReviewerGroupInfo(
-  x: RawAccountInput
-): x is SuggestedReviewerGroupInfo {
-  return !!(x as SuggestedReviewerGroupInfo).group;
-}
-
-// Internal input type with account info
-export interface AccountInfoInput extends AccountInfo {
-  _account?: boolean;
-  confirmed?: boolean;
-}
-
-// Internal input type with group info
-export interface GroupInfoInput extends GroupInfo {
-  _account?: boolean;
-  confirmed?: boolean;
-}
-
-export type AccountInput = AccountInfoInput | GroupInfoInput;
 
 @customElement('gr-account-list')
 export class GrAccountList extends LitElement {
@@ -450,7 +420,7 @@
     return wasSubmitted;
   }
 
-  additions(): (AccountInfoInput | GroupInfoInput)[] {
+  additions(): AccountInput[] {
     if (!this.change) return [];
     return this.accounts.filter(account =>
       isAccountNewlyAdded(account, this.reviewerState, this.change)
diff --git a/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list_test.ts b/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list_test.ts
index e7112df..eaf8974 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list_test.ts
@@ -5,11 +5,7 @@
  */
 import '../../../test/common-test-setup';
 import './gr-account-list';
-import {
-  AccountInfoInput,
-  GrAccountList,
-  RawAccountInput,
-} from './gr-account-list';
+import {GrAccountList} from './gr-account-list';
 import {
   AccountId,
   AccountInfo,
@@ -35,6 +31,7 @@
 import {createChange} from '../../../test/test-data-generators';
 import {ReviewerState} from '../../../api/rest-api';
 import {fixture, html, assert} from '@open-wc/testing';
+import {AccountInfoInput, RawAccountInput} from '../../../utils/account-util';
 
 class MockSuggestionsProvider implements ReviewerSuggestionsProvider {
   init() {}
diff --git a/polygerrit-ui/app/utils/account-util.ts b/polygerrit-ui/app/utils/account-util.ts
index b21ceee..0853941 100644
--- a/polygerrit-ui/app/utils/account-util.ts
+++ b/polygerrit-ui/app/utils/account-util.ts
@@ -19,6 +19,8 @@
   Suggestion,
   isReviewerAccountSuggestion,
   isReviewerGroupSuggestion,
+  SuggestedReviewerAccountInfo,
+  SuggestedReviewerGroupInfo,
 } from '../types/common';
 import {AccountTag, ReviewerState} from '../constants/constants';
 import {assertNever, hasOwnProperty} from './common-util';
@@ -35,6 +37,43 @@
 export const MENTIONS_REGEX =
   /(?:^|\s)@([a-zA-Z0-9.!#$%&'*+=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)(?=\s+|$)/g;
 
+export interface AccountInputDetail {
+  account: AccountInput;
+}
+
+/** Supported input to be added */
+export type RawAccountInput =
+  | string
+  | SuggestedReviewerAccountInfo
+  | SuggestedReviewerGroupInfo;
+
+// type guards for SuggestedReviewerAccountInfo and SuggestedReviewerGroupInfo
+export function isAccountObject(
+  x: RawAccountInput
+): x is SuggestedReviewerAccountInfo {
+  return !!(x as SuggestedReviewerAccountInfo).account;
+}
+
+export function isSuggestedReviewerGroupInfo(
+  x: RawAccountInput
+): x is SuggestedReviewerGroupInfo {
+  return !!(x as SuggestedReviewerGroupInfo).group;
+}
+
+// AccountInfo with confirmation to be added as reviewer/cc.
+export interface AccountInfoInput extends AccountInfo {
+  _account?: boolean;
+  confirmed?: boolean;
+}
+
+// GroupInfo with confirmation to be added as reviewer/cc.
+export interface GroupInfoInput extends GroupInfo {
+  _account?: boolean;
+  confirmed?: boolean;
+}
+
+export type AccountInput = AccountInfoInput | GroupInfoInput;
+
 export function accountKey(account: AccountInfo): AccountId | EmailAddress {
   if (account._account_id !== undefined) return account._account_id;
   if (account.email) return account.email;
@@ -213,17 +252,22 @@
 }
 
 export function toReviewInput(
-  account: AccountInfo | GroupInfo,
+  account: AccountInput,
   state: ReviewerState
 ): ReviewerInput {
   if (isAccount(account)) {
     return {
       reviewer: accountKey(account),
       state,
+      ...(account.confirmed && {confirmed: account.confirmed}),
     };
   } else if (isGroup(account)) {
     const reviewer = decodeURIComponent(account.id) as GroupId;
-    return {reviewer, state};
+    return {
+      reviewer,
+      state,
+      ...(account.confirmed && {confirmed: account.confirmed}),
+    };
   }
   throw new Error('Must be either an account or a group.');
 }
diff --git a/polygerrit-ui/app/utils/account-util_test.ts b/polygerrit-ui/app/utils/account-util_test.ts
index 3e61255..72fa791 100644
--- a/polygerrit-ui/app/utils/account-util_test.ts
+++ b/polygerrit-ui/app/utils/account-util_test.ts
@@ -5,6 +5,7 @@
  */
 import '../test/common-test-setup';
 import {
+  AccountInput,
   computeVoteableText,
   extractMentionedUsers,
   getAccountTemplate,
@@ -13,6 +14,7 @@
   isServiceUser,
   removeServiceUsers,
   replaceTemplates,
+  toReviewInput,
 } from './account-util';
 import {
   AccountsVisibility,
@@ -23,6 +25,8 @@
   AccountId,
   AccountInfo,
   EmailAddress,
+  GroupId,
+  ReviewerState,
   ServerInfo,
 } from '../api/rest-api';
 import {
@@ -281,4 +285,60 @@
       ''
     );
   });
+
+  test('toReviewInput account no confirm', () => {
+    const account: AccountInput = {
+      ...createAccountWithId(5),
+      _account: true,
+    };
+
+    const reviewInput = toReviewInput(account, ReviewerState.REVIEWER);
+    assert.deepEqual(reviewInput, {
+      reviewer: 5 as AccountId,
+      state: ReviewerState.REVIEWER,
+    });
+  });
+
+  test('toReviewInput account confirm', () => {
+    const account: AccountInput = {
+      ...createAccountWithId(5),
+      _account: true,
+      confirmed: true,
+    };
+
+    const reviewInput = toReviewInput(account, ReviewerState.REVIEWER);
+    assert.deepEqual(reviewInput, {
+      reviewer: 5 as AccountId,
+      state: ReviewerState.REVIEWER,
+      confirmed: true,
+    });
+  });
+
+  test('toReviewInput group no confirm', () => {
+    const account: AccountInput = {
+      ...createGroupInfo('group_id'),
+      _account: false,
+    };
+
+    const reviewInput = toReviewInput(account, ReviewerState.REVIEWER);
+    assert.deepEqual(reviewInput, {
+      reviewer: 'group_id' as GroupId,
+      state: ReviewerState.REVIEWER,
+    });
+  });
+
+  test('toReviewInput group confirm', () => {
+    const account: AccountInput = {
+      ...createGroupInfo('group_id'),
+      _account: false,
+      confirmed: true,
+    };
+
+    const reviewInput = toReviewInput(account, ReviewerState.REVIEWER);
+    assert.deepEqual(reviewInput, {
+      reviewer: 'group_id' as GroupId,
+      state: ReviewerState.REVIEWER,
+      confirmed: true,
+    });
+  });
 });