blob: 9beb24305b384a59bf64dde7fc80ef82d37857bf [file] [log] [blame]
/**
* @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 '../../../scripts/bundled-polymer.js';
import '@polymer/iron-icon/iron-icon.js';
import '../../../styles/shared-styles.js';
import '../../shared/gr-dialog/gr-dialog.js';
import '../../shared/gr-overlay/gr-overlay.js';
import '../../shared/gr-rest-api-interface/gr-rest-api-interface.js';
import '../gr-diff/gr-diff.js';
import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
import {htmlTemplate} from './gr-apply-fix-dialog_html.js';
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
/**
* @extends Polymer.Element
*/
class GrApplyFixDialog extends GestureEventListeners(
LegacyElementMixin(PolymerElement)) {
static get template() { return htmlTemplate; }
static get is() { return 'gr-apply-fix-dialog'; }
static get properties() {
return {
// Diff rendering preference API response.
prefs: Array,
// ChangeInfo API response object.
change: Object,
changeNum: String,
_patchNum: Number,
// robot ID associated with a robot comment.
_robotId: String,
// Selected FixSuggestionInfo entity from robot comment API response.
_currentFix: Object,
// Flattened /preview API response DiffInfo map object.
_currentPreviews: {type: Array, value: () => []},
// FixSuggestionInfo entities from robot comment API response.
_fixSuggestions: Array,
_isApplyFixLoading: {
type: Boolean,
value: false,
},
// Index of currently showing suggested fix.
_selectedFixIdx: Number,
_disableApplyFixButton: {
type: Boolean,
computed: '_computeDisableApplyFixButton(_isApplyFixLoading, change, '
+ '_patchNum)',
},
};
}
/**
* Given robot comment CustomEvent objevt, fetch diffs associated
* with first robot comment suggested fix and open dialog.
*
* @param {*} e CustomEvent to be passed from gr-comment with
* robot comment detail.
* @return {Promise<undefined>} Promise that resolves either when all
* preview diffs are fetched or no fix suggestions in custom event detail.
*/
open(e) {
this._patchNum = e.detail.patchNum;
this._fixSuggestions = e.detail.comment.fix_suggestions;
this._robotId = e.detail.comment.robot_id;
if (this._fixSuggestions == null || this._fixSuggestions.length == 0) {
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();
this.removeEventListener('diff-context-expanded', this.refitOverlay);
}
_showSelectedFixSuggestion(fixSuggestion) {
this._currentFix = fixSuggestion;
return this._fetchFixPreview(fixSuggestion.fix_id);
}
_fetchFixPreview(fixId) {
return this.$.restAPI
.getRobotCommentFixPreview(this.changeNum, this._patchNum, fixId)
.then(res => {
if (res != null) {
const previews = Object.keys(res).map(key => {
return {filepath: key, preview: res[key]};
});
this._currentPreviews = previews;
}
})
.catch(err => {
this._close();
throw err;
});
}
hasSingleFix(_fixSuggestions) {
return (_fixSuggestions || {}).length === 1;
}
overridePartialPrefs(prefs) {
// generate a smaller gr-diff than fullscreen for dialog
return Object.assign({}, prefs, {line_length: 50});
}
onCancel(e) {
if (e) {
e.stopPropagation();
}
this._close();
}
addOneTo(_selectedFixIdx) {
return _selectedFixIdx + 1;
}
_onPrevFixClick(e) {
if (e) e.stopPropagation();
if (this._selectedFixIdx >= 1 && this._fixSuggestions != null) {
this._selectedFixIdx -= 1;
return this._showSelectedFixSuggestion(
this._fixSuggestions[this._selectedFixIdx]);
}
}
_onNextFixClick(e) {
if (e) e.stopPropagation();
if (this._fixSuggestions &&
this._selectedFixIdx < this._fixSuggestions.length) {
this._selectedFixIdx += 1;
return this._showSelectedFixSuggestion(
this._fixSuggestions[this._selectedFixIdx]);
}
}
_noPrevFix(_selectedFixIdx) {
return _selectedFixIdx === 0;
}
_noNextFix(_selectedFixIdx, fixSuggestions) {
if (fixSuggestions == null) return true;
return _selectedFixIdx === fixSuggestions.length - 1;
}
_close() {
this._currentFix = {};
this._currentPreviews = [];
this._isApplyFixLoading = false;
this.dispatchEvent(new CustomEvent('close-fix-preview', {
bubbles: true,
composed: true,
}));
this.$.applyFixOverlay.close();
}
_getApplyFixButtonLabel(isLoading) {
return isLoading ? 'Saving...' : 'Apply Fix';
}
_computeTooltip(change, patchNum) {
if (!change || patchNum == undefined) return '';
// If change is defined, change.revisions and change.current_revisions
// must be defined
const latestPatchNum = change.revisions[change.current_revision]._number;
return latestPatchNum !== patchNum ?
'Fix can only be applied to the latest patchset' : '';
}
_computeDisableApplyFixButton(isApplyFixLoading, change, patchNum) {
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) {
if (e) {
e.stopPropagation();
}
if (this._currentFix == null || this._currentFix.fix_id == null) {
return;
}
this._isApplyFixLoading = true;
return this.$.restAPI
.applyFixSuggestion(
this.changeNum, this._patchNum, this._currentFix.fix_id
)
.then(res => {
if (res && res.ok) {
GerritNav.navigateToChange(this.change, 'edit', this._patchNum);
this._close();
}
this._isApplyFixLoading = false;
});
}
getFixDescription(currentFix) {
return currentFix != null && currentFix.description ?
currentFix.description : '';
}
}
customElements.define(GrApplyFixDialog.is, GrApplyFixDialog);