Fix Delete vote button not checking removable_labels.

Whether or not a vote can be removed by a current user is controlled by
removable_labels field of ChangeInfo. Frontend code however was
erroneously checking removable_reviewers instead.

Bug: Google b/447150520
Release-Notes: skip
Change-Id: Ib9b46c533ca27c2edea8fc3dc99602ffb4a6ee6b
diff --git a/polygerrit-ui/app/api/rest-api.ts b/polygerrit-ui/app/api/rest-api.ts
index cb09c45..ec117f8 100644
--- a/polygerrit-ui/app/api/rest-api.ts
+++ b/polygerrit-ui/app/api/rest-api.ts
@@ -402,6 +402,9 @@
   labels?: LabelNameToInfoMap;
   permitted_labels?: LabelNameToValuesMap;
   removable_reviewers?: AccountInfo[];
+  removable_labels?: {
+    [labelName: string]: {[labelValue: string]: AccountInfo[]};
+  };
   // This is documented as optional, but actually always set.
   reviewers: Reviewers;
   pending_reviewers?: AccountInfo[];
diff --git a/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info.ts b/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info.ts
index 44eda05..28f6d6e 100644
--- a/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info.ts
+++ b/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info.ts
@@ -170,7 +170,7 @@
       ></gr-account-chip>
       ${noVoteYet
         ? this.renderVoteAbility(reviewer)
-        : html`${this.renderRemoveVote(reviewer)}`}
+        : html`${this.renderRemoveVote(reviewer, approvalInfo)}`}
     </div>`;
   }
 
@@ -187,12 +187,16 @@
     return html`<span class="no-votes">No votes</span>`;
   }
 
-  private renderRemoveVote(reviewer: AccountInfo) {
+  private renderRemoveVote(
+    reviewer: AccountInfo,
+    approvalInfo: ApprovalInfo | undefined
+  ) {
     const accountId = reviewer._account_id;
     const canDeleteVote = this.canDeleteVote(
       reviewer,
       this.mutable,
-      this.change
+      this.change,
+      approvalInfo
     );
     if (!accountId || !canDeleteVote) return;
 
@@ -253,22 +257,30 @@
 
   /**
    * A user is able to delete a vote iff the mutable property is true and the
-   * reviewer that left the vote exists in the list of removable_reviewers
+   * reviewer that left the vote exists in the list of removable_labels
    * received from the backend.
    */
   private canDeleteVote(
-    reviewer: ApprovalInfo,
+    reviewer: AccountInfo,
     mutable: boolean,
-    change?: ParsedChangeInfo
+    change?: ParsedChangeInfo,
+    approvalInfo?: ApprovalInfo
   ) {
-    if (!mutable || !change || !change.removable_reviewers) {
+    if (
+      !mutable ||
+      !change ||
+      !approvalInfo ||
+      !approvalInfo.value ||
+      !change.removable_labels
+    ) {
       return false;
     }
-    const removable = change.removable_reviewers;
-    if (removable.find(r => r._account_id === reviewer?._account_id)) {
-      return true;
+    const removableAccounts =
+      change.removable_labels[this.label]?.[valueString(approvalInfo.value)];
+    if (!removableAccounts) {
+      return false;
     }
-    return false;
+    return removableAccounts.find(r => r._account_id === reviewer?._account_id);
   }
 
   private async onDeleteVote(accountId: AccountId) {
diff --git a/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_test.ts b/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_test.ts
index 0514b68..14561ea 100644
--- a/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_test.ts
@@ -90,7 +90,7 @@
       await element.updateComplete;
       assert.isUndefined(query<GrButton>(element, 'gr-button'));
 
-      element.change!.removable_reviewers = [account];
+      element.change!.removable_labels = {'Code-Review': {'+1': [account]}};
       element.mutable = true;
       await element.updateComplete;
       assert.isDefined(query<GrButton>(element, 'gr-button'));
@@ -100,7 +100,7 @@
       const mock = mockPromise();
       const deleteResponse = mock.then(() => new Response(null, {status: 200}));
       const deleteStub = stubRestApi('deleteVote').returns(deleteResponse);
-      element.change!.removable_reviewers = [account];
+      element.change!.removable_labels = {'Code-Review': {'+1': [account]}};
       element.change!.labels!['Code-Review'] = {
         ...label,
         recommended: account,