Add a flag and a button for triggering AI Chat

Screenshot https://imgur.com/a/7NrRGKC

Also fix the self referencing css vars that break the side panel layout.

Release-Notes: skip
Google-Bug-Id: b/437944720
Change-Id: If66c73508630a599806bf87e49adfd327de99a28
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
index 12e2715..54c1469 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
@@ -121,6 +121,7 @@
 import {commentsModelToken} from '../../../models/comments/comments-model';
 import {when} from 'lit/directives/when.js';
 import {ValidationOptionInfo} from '../../../api/rest-api';
+import {KnownExperimentId} from '../../../services/flags/flags';
 
 const ERR_BRANCH_EMPTY = 'The destination branch can’t be empty.';
 const ERR_COMMIT_EMPTY = 'The commit message can’t be empty.';
@@ -180,6 +181,13 @@
   method: HttpMethod.POST,
 };
 
+const AI_CHAT_ACTION: UIActionInfo = {
+  __key: 'chat',
+  __type: ActionType.CHANGE,
+  enabled: true,
+  label: 'AI Chat',
+};
+
 function isQuickApproveAction(
   action: UIActionInfo
 ): action is QuickApproveUIActionInfo {
@@ -268,6 +276,7 @@
   [ChangeActions.REVERT, {icon: 'undo'}],
   [ChangeActions.STOP_EDIT, {icon: 'stop', filled: true}],
   [QUICK_APPROVE_ACTION.key, {icon: 'check'}],
+  [AI_CHAT_ACTION.__key, {icon: 'stars'}],
   [RevisionActions.SUBMIT, {icon: 'done_all'}],
 ]);
 
@@ -487,12 +496,16 @@
 
   @state() pluginsLoaded = false;
 
+  @state() aiPluginsRegistered = false;
+
   @state() threadsWithUnappliedSuggestions?: CommentThread[];
 
   private readonly restApiService = getAppContext().restApiService;
 
   private readonly reporting = getAppContext().reportingService;
 
+  private readonly flagService = getAppContext().flagsService;
+
   private readonly getPluginLoader = resolve(this, pluginLoaderToken);
 
   private readonly getUserModel = resolve(this, userModelToken);
@@ -576,6 +589,11 @@
     );
     subscribe(
       this,
+      () => this.getPluginLoader().pluginsModel.aiCodeReviewPlugins$,
+      plugins => (this.aiPluginsRegistered = (plugins.length ?? 0) > 0)
+    );
+    subscribe(
+      this,
       () => this.getConfigModel().repoConfig$,
       config => (this.privateByDefault = config?.private_by_default)
     );
@@ -1219,6 +1237,16 @@
     this._hideQuickApproveAction = true;
   }
 
+  private getAiChatAction(): UIActionInfo | null {
+    if (!this.flagService.isEnabled(KnownExperimentId.ENABLE_AI_CHAT)) {
+      return null;
+    }
+    if (!this.aiPluginsRegistered) {
+      return null;
+    }
+    return AI_CHAT_ACTION;
+  }
+
   private getQuickApproveAction(): QuickApproveUIActionInfo | null {
     if (this._hideQuickApproveAction) {
       return null;
@@ -1488,6 +1516,10 @@
         this.fireAction(this.prependSlash(key), action, true, action.payload);
         break;
       }
+      case AI_CHAT_ACTION.__key: {
+        fire(this, 'ai-chat', {});
+        break;
+      }
       case ChangeActions.EDIT:
         this.handleEditTap();
         break;
@@ -2200,6 +2232,10 @@
     if (quickApprove) {
       changeActionValues.unshift(quickApprove);
     }
+    const aiChat = this.getAiChatAction();
+    if (aiChat) {
+      changeActionValues.unshift(aiChat);
+    }
 
     return revisionActionValues
       .concat(changeActionValues)
@@ -2327,6 +2363,7 @@
 
 declare global {
   interface HTMLElementEventMap {
+    'ai-chat': CustomEvent<{}>;
     'download-tap': CustomEvent<{}>;
     'edit-tap': CustomEvent<{}>;
     'included-tap': CustomEvent<{}>;
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
index 37e7ccf..d0e84ac 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
@@ -1185,6 +1185,10 @@
     `;
   }
 
+  private toggleChat() {
+    this.showSidebarChat = !this.showSidebarChat;
+  }
+
   private renderSidebar() {
     if (!this.showSidebarChat) return;
     return html` <div>Hello, I am a fancy sidebar for AI Chat.</div> `;
@@ -1310,6 +1314,7 @@
       <div class="commitActions">
         <gr-change-actions
           id="actions"
+          @ai-chat=${() => this.toggleChat()}
           @edit-tap=${() => this.handleEditTap()}
           @stop-edit-tap=${() => this.handleStopEditTap()}
           @download-tap=${() => this.handleOpenDownloadDialog()}
diff --git a/polygerrit-ui/app/elements/shared/gr-content-with-sidebar/gr-content-with-sidebar.ts b/polygerrit-ui/app/elements/shared/gr-content-with-sidebar/gr-content-with-sidebar.ts
index b61a10a..f87914f 100644
--- a/polygerrit-ui/app/elements/shared/gr-content-with-sidebar/gr-content-with-sidebar.ts
+++ b/polygerrit-ui/app/elements/shared/gr-content-with-sidebar/gr-content-with-sidebar.ts
@@ -43,8 +43,6 @@
         :host {
           display: block;
           --sidebar-height: calc(100vh - var(--sidebar-top));
-          --sidebar-top: var(--sidebar-top, 0px);
-          --sidebar-bottom-overflow: var(--sidebar-bottom-overflow, 0px);
         }
         .sidebar-wrapper {
           z-index: 50;
diff --git a/polygerrit-ui/app/services/flags/flags.ts b/polygerrit-ui/app/services/flags/flags.ts
index 2c7993c..70d24aa 100644
--- a/polygerrit-ui/app/services/flags/flags.ts
+++ b/polygerrit-ui/app/services/flags/flags.ts
@@ -25,4 +25,5 @@
   ML_SUGGESTED_EDIT_EDITABLE_SUGGESTION = 'UiFeature__ml_suggested_edit_editable_suggestion',
   SHOW_FLOWS_TAB = 'UiFeature__show_flows_tab',
   ASYNC_SUBMIT_REQUIREMENTS = 'UiFeature__async_submit_requirements',
+  ENABLE_AI_CHAT = 'UiFeature__enable_ai_chat',
 }