blob: 42a24341453f5f4ba7692a58352ccb69ad4dcfd8 [file] [log] [blame]
/**
* @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, nothing, PropertyValues} from 'lit';
import {customElement, state, query} 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, PatchSetNumber} from '../../../types/common';
import {commentModelToken} from '../gr-comment-model/gr-comment-model';
import {createUserFixSuggestion} from '../../../utils/comment-util';
declare global {
interface HTMLElementEventMap {
'open-user-suggest-preview': OpenUserSuggestionPreviewEvent;
}
}
export type OpenUserSuggestionPreviewEvent =
CustomEvent<OpenUserSuggestionPreviewEventDetail>;
export interface OpenUserSuggestionPreviewEventDetail {
code: string;
}
@customElement('gr-user-suggestion-fix')
export class GrUserSuggestionsFix extends LitElement {
@query('gr-suggestion-diff-preview')
suggestionDiffPreview?: GrSuggestionDiffPreview;
@state() private docsBaseUrl = '';
@state() private applyingFix = false;
@state() latestPatchNum?: PatchSetNumber;
@state() comment?: Comment;
@state() private previewLoaded = false;
@state() commentedText?: string;
private readonly getConfigModel = resolve(this, configModelToken);
private readonly getChangeModel = resolve(this, changeModelToken);
private readonly getCommentModel = resolve(this, commentModelToken);
constructor() {
super();
subscribe(
this,
() => this.getConfigModel().docsBaseUrl$,
docsBaseUrl => (this.docsBaseUrl = docsBaseUrl)
);
subscribe(
this,
() => this.getChangeModel().latestPatchNum$,
x => (this.latestPatchNum = x)
);
subscribe(
this,
() => this.getCommentModel().comment$,
comment => (this.comment = comment)
);
subscribe(
this,
() => this.getCommentModel().commentedText$,
commentedText => (this.commentedText = commentedText)
);
}
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() {
if (!this.textContent || !this.comment || !this.commentedText)
return nothing;
const code = this.textContent;
const fixSuggestions = createUserFixSuggestion(
this.comment,
this.commentedText,
code
);
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 class="copyButton">
<gr-copy-clipboard
hideInput=""
text=${code}
multiline
copyTargetName="Suggested edit"
buttonTitle="Copy Suggested edit to clipboard"
></gr-copy-clipboard>
</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
.patchSet=${this.comment?.patch_set}
.commentId=${this.comment?.id}
.fixSuggestionInfo=${fixSuggestions[0]}
.codeText=${code}
@preview-loaded=${() => (this.previewLoaded = true)}
></gr-suggestion-diff-preview>`;
}
override updated(changedProperties: PropertyValues) {
super.updated(changedProperties);
if (changedProperties.has('commentedText') && this.commentedText) {
this.previewLoaded = false;
}
}
handleShowFix() {
if (!this.textContent) return;
fire(this, 'open-user-suggest-preview', {code: this.textContent});
}
async handleApplyFix() {
if (!this.textContent) return;
this.applyingFix = true;
await this.suggestionDiffPreview?.applyFix();
this.applyingFix = false;
}
private isApplyEditDisabled() {
if (this.comment?.patch_set === undefined) return true;
return !this.previewLoaded;
}
private computeApplyEditTooltip() {
if (this.comment?.patch_set === undefined) return '';
if (!this.previewLoaded) return 'Fix is still loading ...';
return '';
}
}
declare global {
interface HTMLElementTagNameMap {
'gr-user-suggestion-fix': GrUserSuggestionsFix;
}
}