The change converts the following files to typescript: * elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.ts Change-Id: I274ba656285897c89c42f299724e402758b8cfe3
317 lines
8.6 KiB
TypeScript
317 lines
8.6 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright (C) 2019 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
import '@polymer/iron-icon/iron-icon';
|
|
import '../../../styles/shared-styles';
|
|
import '../../shared/gr-dialog/gr-dialog';
|
|
import '../../shared/gr-overlay/gr-overlay';
|
|
import '../../shared/gr-rest-api-interface/gr-rest-api-interface';
|
|
import '../gr-diff/gr-diff';
|
|
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
|
|
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
|
|
import {PolymerElement} from '@polymer/polymer/polymer-element';
|
|
import {htmlTemplate} from './gr-apply-fix-dialog_html';
|
|
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
|
|
import {customElement, property} from '@polymer/decorators';
|
|
import {ParsedChangeInfo} from '../../shared/gr-rest-api-interface/gr-reviewer-updates-parser';
|
|
import {
|
|
ChangeNum,
|
|
DiffInfo,
|
|
DiffPreferencesInfo,
|
|
EditPatchSetNum,
|
|
FixId,
|
|
FixSuggestionInfo,
|
|
PatchSetNum,
|
|
RobotId,
|
|
} from '../../../types/common';
|
|
import {GrOverlay} from '../../shared/gr-overlay/gr-overlay';
|
|
import {
|
|
CommentEventDetail,
|
|
isRobotComment,
|
|
} from '../../shared/gr-comment/gr-comment';
|
|
import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
|
|
|
|
export interface GrApplyFixDialog {
|
|
$: {
|
|
restAPI: RestApiService & Element;
|
|
applyFixOverlay: GrOverlay;
|
|
};
|
|
}
|
|
|
|
interface FilePreview {
|
|
filepath: string;
|
|
preview: DiffInfo;
|
|
}
|
|
|
|
@customElement('gr-apply-fix-dialog')
|
|
export class GrApplyFixDialog extends GestureEventListeners(
|
|
LegacyElementMixin(PolymerElement)
|
|
) {
|
|
static get template() {
|
|
return htmlTemplate;
|
|
}
|
|
|
|
@property({type: Object})
|
|
prefs?: DiffPreferencesInfo;
|
|
|
|
@property({type: Object})
|
|
change?: ParsedChangeInfo;
|
|
|
|
@property({type: String})
|
|
changeNum?: ChangeNum;
|
|
|
|
@property({type: Number})
|
|
_patchNum?: PatchSetNum;
|
|
|
|
@property({type: String})
|
|
_robotId?: RobotId;
|
|
|
|
@property({type: Object})
|
|
_currentFix?: FixSuggestionInfo;
|
|
|
|
@property({type: Array})
|
|
_currentPreviews: FilePreview[] = [];
|
|
|
|
@property({type: Array})
|
|
_fixSuggestions?: FixSuggestionInfo[];
|
|
|
|
@property({type: Boolean})
|
|
_isApplyFixLoading = false;
|
|
|
|
@property({type: Number})
|
|
_selectedFixIdx = 0;
|
|
|
|
@property({
|
|
type: Boolean,
|
|
computed:
|
|
'_computeDisableApplyFixButton(_isApplyFixLoading, change, ' +
|
|
'_patchNum)',
|
|
})
|
|
_disableApplyFixButton?: boolean;
|
|
|
|
private refitOverlay?: () => void;
|
|
|
|
/**
|
|
* Given robot comment CustomEvent object, fetch diffs associated
|
|
* with first robot comment suggested fix and open dialog.
|
|
*
|
|
* @param e to be passed from gr-comment with robot comment detail.
|
|
* @return Promise that resolves either when all
|
|
* preview diffs are fetched or no fix suggestions in custom event detail.
|
|
*/
|
|
open(e: CustomEvent<CommentEventDetail>) {
|
|
const detail = e.detail;
|
|
const comment = detail.comment;
|
|
if (!detail.patchNum || !comment || !isRobotComment(comment)) {
|
|
return Promise.resolve();
|
|
}
|
|
this._patchNum = detail.patchNum;
|
|
this._fixSuggestions = comment.fix_suggestions;
|
|
this._robotId = comment.robot_id;
|
|
if (!this._fixSuggestions || !this._fixSuggestions.length) {
|
|
return Promise.resolve();
|
|
}
|
|
this._selectedFixIdx = 0;
|
|
const promises = [];
|
|
promises.push(
|
|
this._showSelectedFixSuggestion(this._fixSuggestions[0]),
|
|
this.$.applyFixOverlay.open()
|
|
);
|
|
return Promise.all(promises).then(() => {
|
|
// ensures gr-overlay repositions overlay in center
|
|
this.$.applyFixOverlay.dispatchEvent(
|
|
new CustomEvent('iron-resize', {
|
|
composed: true,
|
|
bubbles: true,
|
|
})
|
|
);
|
|
});
|
|
}
|
|
|
|
attached() {
|
|
super.attached();
|
|
this.refitOverlay = () => {
|
|
// re-center the dialog as content changed
|
|
this.$.applyFixOverlay.dispatchEvent(
|
|
new CustomEvent('iron-resize', {
|
|
composed: true,
|
|
bubbles: true,
|
|
})
|
|
);
|
|
};
|
|
this.addEventListener('diff-context-expanded', this.refitOverlay);
|
|
}
|
|
|
|
detached() {
|
|
super.detached();
|
|
if (this.refitOverlay) {
|
|
this.removeEventListener('diff-context-expanded', this.refitOverlay);
|
|
}
|
|
}
|
|
|
|
_showSelectedFixSuggestion(fixSuggestion: FixSuggestionInfo) {
|
|
this._currentFix = fixSuggestion;
|
|
return this._fetchFixPreview(fixSuggestion.fix_id);
|
|
}
|
|
|
|
_fetchFixPreview(fixId: FixId) {
|
|
if (!this.changeNum || !this._patchNum) {
|
|
return Promise.reject(
|
|
new Error('Both _patchNum and changeNum must be set')
|
|
);
|
|
}
|
|
return this.$.restAPI
|
|
.getRobotCommentFixPreview(this.changeNum, this._patchNum, fixId)
|
|
.then(res => {
|
|
if (res) {
|
|
this._currentPreviews = Object.keys(res).map(key => {
|
|
return {filepath: key, preview: res[key]};
|
|
});
|
|
}
|
|
})
|
|
.catch(err => {
|
|
this._close();
|
|
throw err;
|
|
});
|
|
}
|
|
|
|
hasSingleFix(_fixSuggestions?: FixSuggestionInfo[]) {
|
|
return (_fixSuggestions || []).length === 1;
|
|
}
|
|
|
|
overridePartialPrefs(prefs: DiffPreferencesInfo): DiffPreferencesInfo {
|
|
// generate a smaller gr-diff than fullscreen for dialog
|
|
return {...prefs, line_length: 50};
|
|
}
|
|
|
|
onCancel(e: CustomEvent) {
|
|
if (e) {
|
|
e.stopPropagation();
|
|
}
|
|
this._close();
|
|
}
|
|
|
|
addOneTo(_selectedFixIdx: number) {
|
|
return _selectedFixIdx + 1;
|
|
}
|
|
|
|
_onPrevFixClick(e: CustomEvent) {
|
|
if (e) e.stopPropagation();
|
|
if (this._selectedFixIdx >= 1 && this._fixSuggestions) {
|
|
this._selectedFixIdx -= 1;
|
|
this._showSelectedFixSuggestion(
|
|
this._fixSuggestions[this._selectedFixIdx]
|
|
);
|
|
}
|
|
}
|
|
|
|
_onNextFixClick(e: CustomEvent) {
|
|
if (e) e.stopPropagation();
|
|
if (
|
|
this._fixSuggestions &&
|
|
this._selectedFixIdx < this._fixSuggestions.length
|
|
) {
|
|
this._selectedFixIdx += 1;
|
|
this._showSelectedFixSuggestion(
|
|
this._fixSuggestions[this._selectedFixIdx]
|
|
);
|
|
}
|
|
}
|
|
|
|
_noPrevFix(_selectedFixIdx: number) {
|
|
return _selectedFixIdx === 0;
|
|
}
|
|
|
|
_noNextFix(_selectedFixIdx: number, fixSuggestions?: FixSuggestionInfo[]) {
|
|
if (!fixSuggestions) return true;
|
|
return _selectedFixIdx === fixSuggestions.length - 1;
|
|
}
|
|
|
|
_close() {
|
|
this._currentFix = undefined;
|
|
this._currentPreviews = [];
|
|
this._isApplyFixLoading = false;
|
|
|
|
this.dispatchEvent(
|
|
new CustomEvent('close-fix-preview', {
|
|
bubbles: true,
|
|
composed: true,
|
|
})
|
|
);
|
|
this.$.applyFixOverlay.close();
|
|
}
|
|
|
|
_getApplyFixButtonLabel(isLoading: boolean) {
|
|
return isLoading ? 'Saving...' : 'Apply Fix';
|
|
}
|
|
|
|
_computeTooltip(change?: ParsedChangeInfo, patchNum?: PatchSetNum) {
|
|
if (!change || !patchNum) return '';
|
|
const latestPatchNum = change.revisions[change.current_revision]._number;
|
|
return latestPatchNum !== patchNum
|
|
? 'Fix can only be applied to the latest patchset'
|
|
: '';
|
|
}
|
|
|
|
_computeDisableApplyFixButton(
|
|
isApplyFixLoading?: boolean,
|
|
change?: ParsedChangeInfo,
|
|
patchNum?: PatchSetNum
|
|
) {
|
|
if (!change || isApplyFixLoading === undefined || patchNum === undefined) {
|
|
return true;
|
|
}
|
|
const currentPatchNum = change.revisions[change.current_revision]._number;
|
|
if (patchNum !== currentPatchNum) {
|
|
return true;
|
|
}
|
|
return isApplyFixLoading;
|
|
}
|
|
|
|
_handleApplyFix(e: CustomEvent) {
|
|
if (e) {
|
|
e.stopPropagation();
|
|
}
|
|
|
|
const changeNum = this.changeNum;
|
|
const patchNum = this._patchNum;
|
|
const change = this.change;
|
|
if (!changeNum || !patchNum || !change || !this._currentFix) {
|
|
return Promise.reject(new Error('Not all required properties are set.'));
|
|
}
|
|
this._isApplyFixLoading = true;
|
|
return this.$.restAPI
|
|
.applyFixSuggestion(changeNum, patchNum, this._currentFix.fix_id)
|
|
.then(res => {
|
|
if (res && res.ok) {
|
|
GerritNav.navigateToChange(change, EditPatchSetNum, patchNum);
|
|
this._close();
|
|
}
|
|
this._isApplyFixLoading = false;
|
|
});
|
|
}
|
|
|
|
getFixDescription(currentFix?: FixSuggestionInfo) {
|
|
return currentFix && currentFix.description ? currentFix.description : '';
|
|
}
|
|
}
|
|
|
|
declare global {
|
|
interface HTMLElementTagNameMap {
|
|
'gr-apply-fix-dialog': GrApplyFixDialog;
|
|
}
|
|
}
|