blob: 0cfbaa4f280002e2d09be721b03f945fd65602ee [file] [log] [blame]
/**
* @license
* Copyright 2022 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import {navigationToken} from '../../core/gr-navigation/gr-navigation';
import {
RepoName,
BranchName,
ChangeInfo,
PatchSetNumber,
} from '../../../types/common';
import {getAppContext} from '../../../services/app-context';
import {LitElement, html, nothing} from 'lit';
import {customElement, property, query, state} from 'lit/decorators.js';
import {resolve} from '../../../models/dependency';
import {createEditUrl} from '../../../models/views/change';
import {modalStyles} from '../../../styles/gr-modal-styles';
import {assertIsDefined} from '../../../utils/common-util';
import {when} from 'lit/directives/when.js';
import {GrDialog} from '../../shared/gr-dialog/gr-dialog';
declare global {
interface HTMLElementTagNameMap {
'gr-create-file-edit-dialog': GrCreateFileEditDialog;
}
}
@customElement('gr-create-file-edit-dialog')
export class GrCreateFileEditDialog extends LitElement {
@query('dialog')
modal?: HTMLDialogElement;
@query('gr-dialog')
grDialog?: GrDialog;
@property({type: String})
repo?: RepoName;
@property({type: String})
branch?: BranchName;
@property({type: String})
path?: string;
/**
* If this is set, then we show this message replacing all other content.
*/
@state()
errorMessage?: string;
/**
* Triggers showing the dialog and kicks off creating a change.
*/
@state()
active = false;
/**
* Indicates whether the REST API call for creating a change is in progress.
*/
@state()
loading = false;
private readonly restApiService = getAppContext().restApiService;
private readonly getNavigation = resolve(this, navigationToken);
static override get styles() {
return [modalStyles];
}
override render() {
if (!this.active) return nothing;
return html`
<dialog tabindex="-1">
<gr-dialog
disabled
?loading=${this.loading}
.loadingLabel=${'Creating change ...'}
@cancel=${() => this.deactivate()}
.confirmLabel=${this.loading ? 'Please wait ...' : 'Failed'}
.cancelLabel=${'Cancel'}
>
<div slot="header">
<span class="main-heading">Create Change from URL</span>
</div>
<div slot="main">
${when(
this.errorMessage,
() => this.renderError(),
() => this.renderCreating()
)}
</div>
</gr-dialog>
</dialog>
`;
}
async activate() {
this.active = true;
this.createChange();
await this.updateComplete;
if (this.active && this.modal?.open === false) this.modal.showModal();
}
deactivate() {
this.active = false;
this.modal?.close();
}
private renderCreating() {
return html`
<div>
<span>
Creating a change in repository <b>${this.repo}</b> on branch
<b>${this.branch}</b>.
</span>
</div>
<div>
<span>
The page will then redirect to the file editor for
<b>${this.path}</b>
in the newly created change.
</span>
</div>
`;
}
private renderError() {
return html`<div>Error: ${this.errorMessage}</div>`;
}
private createChange() {
if (!this.repo || !this.branch || !this.path) {
this.errorMessage = 'repo, branch and path must be set';
return;
}
if (this.loading || this.errorMessage) return;
this.loading = true;
this.restApiService
.createChange(this.repo, this.branch, `Edit ${this.path}`)
.then(change => {
if (!this.active) return;
if (change) {
this.loading = false;
this.redirectToFileEdit(change);
this.deactivate();
} else {
this.errorMessage = 'Creating the change failed.';
}
})
.catch(() => {
this.errorMessage = 'Creating the change failed.';
})
.finally(() => {
this.loading = false;
});
}
private redirectToFileEdit(change: ChangeInfo) {
assertIsDefined(this.path, 'path');
const url = createEditUrl({
changeNum: change._number,
repo: change.project,
patchNum: 1 as PatchSetNumber,
editView: {path: this.path},
});
this.getNavigation().setUrl(url);
}
}