Enable "Show Edit" and "Apply Edit" for fix_suggestions within comments
We use newly introduced gr-fix-suggestions as wrapper for
gr-suggestion-diff-preview with buttons to preview and apply fix,
with link to documentation and title.
This is intended for comment.fix_suggestions if comment has them
attached. UI is not final, this is still part of experiment for
ml suggestions v2.
We have gr-user-suggestion-fix for user suggestions inside comment
message (as code blocks). They are similar but UI will be different
in future, that's why we don't reuse gr-user-suggestions-fix for
comment.fix_suggestions
Release-Notes: skip
Google-Bug-Id: b/325954020
Change-Id: Ic4c2469702b265a964961cf4c85d608b161c05c2
diff --git a/polygerrit-ui/app/elements/shared/gr-fix-suggestions/gr-fix-suggestions.ts b/polygerrit-ui/app/elements/shared/gr-fix-suggestions/gr-fix-suggestions.ts
new file mode 100644
index 0000000..02d64ff
--- /dev/null
+++ b/polygerrit-ui/app/elements/shared/gr-fix-suggestions/gr-fix-suggestions.ts
@@ -0,0 +1,162 @@
+/**
+ * @license
+ * Copyright 2023 Google LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+import '../../shared/gr-button/gr-button';
+import '../../shared/gr-icon/gr-icon';
+import '../../shared/gr-copy-clipboard/gr-copy-clipboard';
+import '../gr-suggestion-diff-preview/gr-suggestion-diff-preview';
+import {css, html, LitElement} from 'lit';
+import {customElement, state, query, property} from 'lit/decorators.js';
+import {fire} from '../../../utils/event-util';
+import {getDocUrl} from '../../../utils/url-util';
+import {subscribe} from '../../lit/subscription-controller';
+import {resolve} from '../../../models/dependency';
+import {configModelToken} from '../../../models/config/config-model';
+import {GrSuggestionDiffPreview} from '../gr-suggestion-diff-preview/gr-suggestion-diff-preview';
+import {changeModelToken} from '../../../models/change/change-model';
+import {Comment, isDraft, PatchSetNumber} from '../../../types/common';
+import {OpenFixPreviewEventDetail} from '../../../types/events';
+
+/**
+ * gr-fix-suggestions is UI for comment.fix_suggestions.
+ * gr-fix-suggestions is wrapper for gr-suggestion-diff-preview with buttons
+ * to preview and apply fix and for giving a context about suggestion.
+ */
+@customElement('gr-fix-suggestions')
+export class GrFixSuggestions extends LitElement {
+ @query('gr-suggestion-diff-preview')
+ suggestionDiffPreview?: GrSuggestionDiffPreview;
+
+ @property({type: Object})
+ comment?: Comment;
+
+ @state() private docsBaseUrl = '';
+
+ @state() private applyingFix = false;
+
+ @state() latestPatchNum?: PatchSetNumber;
+
+ private readonly getConfigModel = resolve(this, configModelToken);
+
+ private readonly getChangeModel = resolve(this, changeModelToken);
+
+ constructor() {
+ super();
+ subscribe(
+ this,
+ () => this.getConfigModel().docsBaseUrl$,
+ docsBaseUrl => (this.docsBaseUrl = docsBaseUrl)
+ );
+ subscribe(
+ this,
+ () => this.getChangeModel().latestPatchNum$,
+ x => (this.latestPatchNum = x)
+ );
+ }
+
+ static override get styles() {
+ return [
+ css`
+ .header {
+ background-color: var(--background-color-primary);
+ border: 1px solid var(--border-color);
+ padding: var(--spacing-xs) var(--spacing-xl);
+ display: flex;
+ align-items: center;
+ border-top-left-radius: var(--border-radius);
+ border-top-right-radius: var(--border-radius);
+ }
+ .header .title {
+ flex: 1;
+ }
+ .copyButton {
+ margin-right: var(--spacing-l);
+ }
+ `,
+ ];
+ }
+
+ override render() {
+ return html`<div class="header">
+ <div class="title">
+ <span>Suggested edit</span>
+ <a
+ href=${getDocUrl(this.docsBaseUrl, 'user-suggest-edits.html')}
+ target="_blank"
+ rel="noopener noreferrer"
+ ><gr-icon icon="help" title="read documentation"></gr-icon
+ ></a>
+ </div>
+ <div>
+ <gr-button
+ secondary
+ flatten
+ class="action show-fix"
+ @click=${this.handleShowFix}
+ >
+ Show edit
+ </gr-button>
+ <gr-button
+ secondary
+ flatten
+ .loading=${this.applyingFix}
+ .disabled=${this.isApplyEditDisabled()}
+ class="action show-fix"
+ @click=${this.handleApplyFix}
+ .title=${this.computeApplyEditTooltip()}
+ >
+ Apply edit
+ </gr-button>
+ </div>
+ </div>
+ <gr-suggestion-diff-preview
+ .fixSuggestionInfo=${this.comment?.fix_suggestions?.[0]}
+ ></gr-suggestion-diff-preview>`;
+ }
+
+ handleShowFix() {
+ if (!this.comment?.fix_suggestions || !this.comment?.patch_set) return;
+ const eventDetail: OpenFixPreviewEventDetail = {
+ fixSuggestions: this.comment.fix_suggestions.map(s => {
+ return {
+ ...s,
+ description: 'Suggested Edit from comment',
+ };
+ }),
+ patchNum: this.comment.patch_set,
+ onCloseFixPreviewCallbacks: [],
+ };
+ fire(this, 'open-fix-preview', eventDetail);
+ }
+
+ async handleApplyFix() {
+ if (!this.comment?.fix_suggestions) return;
+ this.applyingFix = true;
+ try {
+ await this.suggestionDiffPreview?.applyFixSuggestion();
+ } finally {
+ this.applyingFix = false;
+ }
+ }
+
+ private isApplyEditDisabled() {
+ if (this.comment?.patch_set === undefined) return true;
+ if (isDraft(this.comment)) return true;
+ return this.comment.patch_set !== this.latestPatchNum;
+ }
+
+ private computeApplyEditTooltip() {
+ if (this.comment?.patch_set === undefined) return '';
+ return this.comment.patch_set !== this.latestPatchNum
+ ? 'You cannot apply this fix because it is from a previous patchset'
+ : '';
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'gr-fix-suggestions': GrFixSuggestions;
+ }
+}