Enable send button when patchset level comment is in editing mode

Patchset level comment in reply dialog is always kept in editing
mode. This would set "commentEditing" to true and disable the
send button.
Avoid setting commentEditing to true for patchset level comments.

This still has the issue that text typed in GrComment is not
reflected to GrReplyDialog but solves the issue where already
present text correctly calculates the value of hasDrafts.

Release-Notes: skip
Google-bug-id: b/242982372
Change-Id: I877847d1b2a331e297cefb5e42e3ed47a58e4f67
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 603b180..7ac962d 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
@@ -120,7 +120,10 @@
 import {hasHumanReviewer, isOwner} from '../../../utils/change-util';
 import {KnownExperimentId} from '../../../services/flags/flags';
 import {commentsModelToken} from '../../../models/comments/comments-model';
-import {GrComment} from '../../shared/gr-comment/gr-comment';
+import {
+  CommentEditingChangedDetail,
+  GrComment,
+} from '../../shared/gr-comment/gr-comment';
 
 const STORAGE_DEBOUNCE_INTERVAL_MS = 400;
 
@@ -715,9 +718,16 @@
       )
     );
     this.cleanups.push(addShortcut(this, {key: Key.ESC}, _ => this.cancel()));
-    this.addEventListener('comment-editing-changed', e => {
-      this.commentEditing = (e as CustomEvent).detail;
-    });
+    this.addEventListener(
+      'comment-editing-changed',
+      (e: CustomEvent<CommentEditingChangedDetail>) => {
+        // Patchset level comment is always in editing mode which means it would
+        // set commentEditing = true and the send button would be permanently
+        // disabled.
+        if (e.detail.path === SpecialFilePath.PATCHSET_LEVEL_COMMENTS) return;
+        this.commentEditing = e.detail.editing;
+      }
+    );
 
     // Plugins on reply-reviewers endpoint can take advantage of these
     // events to add / remove reviewers
@@ -2178,8 +2188,18 @@
         isDetailedLabelInfo(label) && getApprovalInfo(label, this.account!)
     );
     const revotingOrNewVote = this.labelsChanged || existingVote;
-    const hasDrafts =
-      this.includeComments && this.draftCommentThreads.length > 0;
+    let hasDrafts = this.includeComments && this.draftCommentThreads.length > 0;
+    if (
+      this.flagsService.isEnabled(
+        KnownExperimentId.PATCHSET_LEVEL_COMMENT_USES_GRCOMMENT
+      )
+    ) {
+      const patchsetLevelComment = queryAndAssert<GrComment>(
+        this,
+        '#patchsetLevelComment'
+      );
+      hasDrafts = hasDrafts || patchsetLevelComment.messageText.length > 0;
+    }
     return (
       !hasDrafts &&
       !this.draft.length &&
diff --git a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts
index 32e53a1..11dfab8 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts
+++ b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts
@@ -47,7 +47,7 @@
   RepoName,
   UrlEncodedCommentId,
 } from '../../../types/common';
-import {GrComment} from '../gr-comment/gr-comment';
+import {CommentEditingChangedDetail, GrComment} from '../gr-comment/gr-comment';
 import {FILE} from '../../../embed/diff/gr-diff/gr-diff-line';
 import {GrButton} from '../gr-button/gr-button';
 import {DiffInfo, DiffPreferencesInfo} from '../../../types/diff';
@@ -527,8 +527,10 @@
         }
         @reply-to-comment=${this.handleReplyToComment}
         @copy-comment-link=${this.handleCopyLink}
-        @comment-editing-changed=${(e: CustomEvent) => {
-          if (isDraftOrUnsaved(comment)) this.editing = e.detail;
+        @comment-editing-changed=${(
+          e: CustomEvent<CommentEditingChangedDetail>
+        ) => {
+          if (isDraftOrUnsaved(comment)) this.editing = e.detail.editing;
         }}
         @comment-unresolved-changed=${(e: CustomEvent) => {
           if (isDraftOrUnsaved(comment)) this.unresolved = e.detail;
diff --git a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.ts b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.ts
index 77ff47e..86ba96a 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.ts
+++ b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.ts
@@ -78,7 +78,7 @@
 
 declare global {
   interface HTMLElementEventMap {
-    'comment-editing-changed': CustomEvent<boolean>;
+    'comment-editing-changed': CustomEvent<CommentEditingChangedDetail>;
     'comment-unresolved-changed': CustomEvent<boolean>;
     'comment-anchor-tap': CustomEvent<CommentAnchorTapEventDetail>;
   }
@@ -89,6 +89,11 @@
   side?: CommentSide;
 }
 
+export interface CommentEditingChangedDetail {
+  editing: boolean;
+  path: string;
+}
+
 @customElement('gr-comment')
 export class GrComment extends LitElement {
   /**
@@ -1025,7 +1030,10 @@
 
     // Parent components such as the reply dialog might be interested in whether
     // come of their child components are in editing mode.
-    fire(this, 'comment-editing-changed', this.editing);
+    fire(this, 'comment-editing-changed', {
+      editing: this.editing,
+      path: this.comment?.path ?? '',
+    });
   }
 
   // private, but visible for testing