summaryrefslogtreecommitdiffstats
path: root/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js
diff options
context:
space:
mode:
Diffstat (limited to 'polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js')
-rw-r--r--polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js424
1 files changed, 323 insertions, 101 deletions
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js
index e8c2d03815..3e5c4f760c 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js
@@ -1,16 +1,19 @@
-// Copyright (C) 2016 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.
+/**
+ * @license
+ * Copyright (C) 2016 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.
+ */
(function() {
'use strict';
@@ -52,6 +55,8 @@
ABANDON: 'abandon',
DELETE: '/',
DELETE_EDIT: 'deleteEdit',
+ EDIT: 'edit',
+ FOLLOW_UP: 'followup',
IGNORE: 'ignore',
MOVE: 'move',
PRIVATE: 'private',
@@ -61,6 +66,7 @@
RESTORE: 'restore',
REVERT: 'revert',
REVIEWED: 'reviewed',
+ STOP_EDIT: 'stopEdit',
UNIGNORE: 'unignore',
UNREVIEWED: 'unreviewed',
WIP: 'wip',
@@ -76,7 +82,7 @@
const ActionLoadingLabels = {
abandon: 'Abandoning...',
- cherrypick: 'Cherry-Picking...',
+ cherrypick: 'Cherry-picking...',
delete: 'Deleting...',
move: 'Moving..',
rebase: 'Rebasing...',
@@ -97,7 +103,7 @@
__type: 'change',
enabled: true,
key: 'review',
- label: 'Quick Approve',
+ label: 'Quick approve',
method: 'POST',
};
@@ -120,7 +126,7 @@
const REBASE_EDIT = {
enabled: true,
- label: 'Rebase Edit',
+ label: 'Rebase edit',
title: 'Rebase change edit',
__key: 'rebaseEdit',
__primary: false,
@@ -130,7 +136,7 @@
const PUBLISH_EDIT = {
enabled: true,
- label: 'Publish Edit',
+ label: 'Publish edit',
title: 'Publish change edit',
__key: 'publishEdit',
__primary: false,
@@ -140,7 +146,7 @@
const DELETE_EDIT = {
enabled: true,
- label: 'Delete Edit',
+ label: 'Delete edit',
title: 'Delete change edit',
__key: 'deleteEdit',
__primary: false,
@@ -148,6 +154,40 @@
method: 'DELETE',
};
+ const EDIT = {
+ enabled: true,
+ label: 'Edit',
+ title: 'Edit this change',
+ __key: 'edit',
+ __primary: false,
+ __type: 'change',
+ };
+
+ const STOP_EDIT = {
+ enabled: true,
+ label: 'Stop editing',
+ title: 'Stop editing this change',
+ __key: 'stopEdit',
+ __primary: false,
+ __type: 'change',
+ };
+
+ // Set of keys that have icons. As more icons are added to gr-icons.html, this
+ // set should be expanded.
+ const ACTIONS_WITH_ICONS = new Set([
+ ChangeActions.ABANDON,
+ ChangeActions.DELETE_EDIT,
+ ChangeActions.EDIT,
+ ChangeActions.PUBLISH_EDIT,
+ ChangeActions.REBASE_EDIT,
+ ChangeActions.RESTORE,
+ ChangeActions.REVERT,
+ ChangeActions.STOP_EDIT,
+ QUICK_APPROVE_ACTION.key,
+ RevisionActions.REBASE,
+ RevisionActions.SUBMIT,
+ ]);
+
const AWAIT_CHANGE_ATTEMPTS = 5;
const AWAIT_CHANGE_TIMEOUT_MS = 1000;
@@ -172,8 +212,22 @@
* @event show-alert
*/
+ /**
+ * Fires when a change action fails.
+ *
+ * @event show-error
+ */
+
properties: {
- /** @type {{ branch: string, project: string }} */
+ /**
+ * @type {{
+ * _number: number,
+ * branch: string,
+ * id: string,
+ * project: string,
+ * subject: string,
+ * }}
+ */
change: Object,
actions: {
type: Object,
@@ -187,10 +241,18 @@
];
},
},
+ disableEdit: {
+ type: Boolean,
+ value: false,
+ },
_hasKnownChainState: {
type: Boolean,
value: false,
},
+ _hideQuickApproveAction: {
+ type: Boolean,
+ value: false,
+ },
changeNum: String,
changeStatus: String,
commitNum: String,
@@ -198,7 +260,7 @@
type: Boolean,
observer: '_computeChainState',
},
- patchNum: String,
+ latestPatchNum: String,
commitMessage: {
type: String,
value: '',
@@ -208,6 +270,7 @@
type: Object,
value() { return {}; },
},
+ privateByDefault: String,
_loading: {
type: Boolean,
@@ -227,7 +290,10 @@
type: Array,
computed: '_computeTopLevelActions(_allActionValues.*, ' +
'_hiddenActions.*, _overflowActions.*)',
+ observer: '_filterPrimaryActions',
},
+ _topLevelPrimaryActions: Array,
+ _topLevelSecondaryActions: Array,
_menuActions: {
type: Array,
computed: '_computeMenuActions(_allActionValues.*, _hiddenActions.*, ' +
@@ -281,6 +347,10 @@
type: ActionType.CHANGE,
key: ChangeActions.PRIVATE_DELETE,
},
+ {
+ type: ActionType.CHANGE,
+ key: ChangeActions.FOLLOW_UP,
+ },
];
return value;
},
@@ -301,7 +371,14 @@
type: Array,
value() { return []; },
},
- editLoaded: {
+ // editPatchsetLoaded == "does the current selected patch range have
+ // 'edit' as one of either basePatchNum or patchNum".
+ editPatchsetLoaded: {
+ type: Boolean,
+ value: false,
+ },
+ // editMode == "is edit mode enabled in the file list".
+ editMode: {
type: Boolean,
value: false,
},
@@ -321,9 +398,10 @@
],
observers: [
- '_actionsChanged(actions.*, revisionActions.*, _additionalActions.*, ' +
- 'editLoaded, editBasedOnCurrentPatchSet, change)',
+ '_actionsChanged(actions.*, revisionActions.*, _additionalActions.*)',
'_changeChanged(change)',
+ '_editStatusChanged(editMode, editPatchsetLoaded, ' +
+ 'editBasedOnCurrentPatchSet, disableEdit, actions.*, change.*)',
],
listeners: {
@@ -333,11 +411,11 @@
ready() {
this.$.jsAPI.addElement(this.$.jsAPI.Element.CHANGE_ACTIONS, this);
- this._loading = false;
+ this._handleLoadingComplete();
},
reload() {
- if (!this.changeNum || !this.patchNum) {
+ if (!this.changeNum || !this.latestPatchNum) {
return Promise.resolve();
}
@@ -346,7 +424,7 @@
if (!revisionActions) { return; }
this.revisionActions = revisionActions;
- this._loading = false;
+ this._handleLoadingComplete();
}).catch(err => {
this.fire('show-alert', {message: ERR_REVISION_ACTIONS});
this._loading = false;
@@ -354,6 +432,10 @@
});
},
+ _handleLoadingComplete() {
+ Gerrit.awaitPluginsLoaded().then(() => this._loading = false);
+ },
+
_changeChanged() {
this.reload();
},
@@ -457,7 +539,7 @@
_getRevisionActions() {
return this.$.restAPI.getChangeRevisionActions(this.changeNum,
- this.patchNum);
+ this.latestPatchNum);
},
_shouldHideActions(actions, loading) {
@@ -469,8 +551,7 @@
},
_actionsChanged(actionsChangeRecord, revisionActionsChangeRecord,
- additionalActionsChangeRecord, editLoaded, editBasedOnCurrentPatchSet,
- change) {
+ additionalActionsChangeRecord) {
const additionalActions = (additionalActionsChangeRecord &&
additionalActionsChangeRecord.base) || [];
this.hidden = this._keyCount(actionsChangeRecord) === 0 &&
@@ -480,50 +561,78 @@
this._disabledMenuActions = [];
const revisionActions = revisionActionsChangeRecord.base || {};
- if (Object.keys(revisionActions).length !== 0 &&
- !revisionActions.download) {
- this.set('revisionActions.download', DOWNLOAD_ACTION);
+ if (Object.keys(revisionActions).length !== 0) {
+ if (!revisionActions.download) {
+ this.set('revisionActions.download', DOWNLOAD_ACTION);
+ }
}
+ },
- const changeActions = actionsChangeRecord.base || {};
- if (Object.keys(changeActions).length !== 0) {
- if (editLoaded) {
- if (this.changeIsOpen(change.status)) {
- if (editBasedOnCurrentPatchSet) {
- if (!changeActions.publishEdit) {
- this.set('actions.publishEdit', PUBLISH_EDIT);
- }
- if (changeActions.rebaseEdit) {
- delete this.actions.rebaseEdit;
- this.notifyPath('actions.rebaseEdit');
- }
- } else {
- if (!changeActions.rebasEdit) {
- this.set('actions.rebaseEdit', REBASE_EDIT);
- }
- if (changeActions.publishEdit) {
- delete this.actions.publishEdit;
- this.notifyPath('actions.publishEdit');
- }
+ /**
+ * @param {string=} actionName
+ */
+ _deleteAndNotify(actionName) {
+ if (this.actions[actionName]) {
+ delete this.actions[actionName];
+ this.notifyPath('actions.' + actionName);
+ }
+ },
+
+ _editStatusChanged(editMode, editPatchsetLoaded,
+ editBasedOnCurrentPatchSet, disableEdit) {
+ if (disableEdit) {
+ this._deleteAndNotify('publishEdit');
+ this._deleteAndNotify('rebaseEdit');
+ this._deleteAndNotify('deleteEdit');
+ this._deleteAndNotify('stopEdit');
+ this._deleteAndNotify('edit');
+ return;
+ }
+ if (editPatchsetLoaded) {
+ // Only show actions that mutate an edit if an actual edit patch set
+ // is loaded.
+ if (this.changeIsOpen(this.change.status)) {
+ if (editBasedOnCurrentPatchSet) {
+ if (!this.actions.publishEdit) {
+ this.set('actions.publishEdit', PUBLISH_EDIT);
}
+ this._deleteAndNotify('rebaseEdit');
+ } else {
+ if (!this.actions.rebaseEdit) {
+ this.set('actions.rebaseEdit', REBASE_EDIT);
+ }
+ this._deleteAndNotify('publishEdit');
}
- if (!changeActions.deleteEdit) {
- this.set('actions.deleteEdit', DELETE_EDIT);
- }
+ }
+ if (!this.actions.deleteEdit) {
+ this.set('actions.deleteEdit', DELETE_EDIT);
+ }
+ } else {
+ this._deleteAndNotify('publishEdit');
+ this._deleteAndNotify('rebaseEdit');
+ this._deleteAndNotify('deleteEdit');
+ }
+
+ if (this.changeIsOpen(this.change.status)) {
+ // Only show edit button if there is no edit patchset loaded and the
+ // file list is not in edit mode.
+ if (editPatchsetLoaded || editMode) {
+ this._deleteAndNotify('edit');
} else {
- if (changeActions.publishEdit) {
- delete this.actions.publishEdit;
- this.notifyPath('actions.publishEdit');
- }
- if (changeActions.rebaseEdit) {
- delete this.actions.rebaseEdit;
- this.notifyPath('actions.rebaseEdit');
- }
- if (changeActions.deleteEdit) {
- delete this.actions.deleteEdit;
- this.notifyPath('actions.deleteEdit');
+ if (!this.actions.edit) { this.set('actions.edit', EDIT); }
+ }
+ // Only show STOP_EDIT if edit mode is enabled, but no edit patch set
+ // is loaded.
+ if (editMode && !editPatchsetLoaded) {
+ if (!this.actions.stopEdit) {
+ this.set('actions.stopEdit', STOP_EDIT);
}
+ } else {
+ this._deleteAndNotify('stopEdit');
}
+ } else {
+ // Remove edit button.
+ this._deleteAndNotify('edit');
}
},
@@ -593,7 +702,18 @@
return null;
},
+ hideQuickApproveAction() {
+ this._topLevelSecondaryActions =
+ this._topLevelSecondaryActions.filter(sa => {
+ return sa.key !== QUICK_APPROVE_ACTION.key;
+ });
+ this._hideQuickApproveAction = true;
+ },
+
_getQuickApproveAction() {
+ if (this._hideQuickApproveAction) {
+ return null;
+ }
const approval = this._getTopMissingApproval();
if (!approval) {
return null;
@@ -636,13 +756,8 @@
} else if (!values.includes(a)) {
return;
}
- if (actions[a].label === 'Delete') {
- // This label is common within change and revision actions. Make it
- // more explicit to the user.
- if (type === ActionType.CHANGE) {
- actions[a].label += ' Change';
- }
- }
+ actions[a].label = this._getActionLabel(actions[a]);
+
// Triggers a re-render by ensuring object inequality.
result.push(Object.assign({}, actions[a]));
});
@@ -661,19 +776,45 @@
_populateActionUrl(action) {
const patchNum =
- action.__type === ActionType.REVISION ? this.patchNum : null;
+ action.__type === ActionType.REVISION ? this.latestPatchNum : null;
this.$.restAPI.getChangeActionURL(
this.changeNum, patchNum, '/' + action.__key)
.then(url => action.__url = url);
},
+ /**
+ * Given a change action, return a display label that uses the appropriate
+ * casing or includes explanatory details.
+ */
+ _getActionLabel(action) {
+ if (action.label === 'Delete') {
+ // This label is common within change and revision actions. Make it more
+ // explicit to the user.
+ return 'Delete change';
+ } else if (action.label === 'WIP') {
+ return 'Mark as work in progress';
+ }
+ // Otherwise, just map the name to sentence case.
+ return this._toSentenceCase(action.label);
+ },
+
+ /**
+ * Capitalize the first letter and lowecase all others.
+ * @param {string} s
+ * @return {string}
+ */
+ _toSentenceCase(s) {
+ if (!s.length) { return ''; }
+ return s[0].toUpperCase() + s.slice(1).toLowerCase();
+ },
+
_computeLoadingLabel(action) {
return ActionLoadingLabels[action] || 'Working...';
},
_canSubmitChange() {
return this.$.jsAPI.canSubmitChange(this.change,
- this._getRevision(this.change, this.patchNum));
+ this._getRevision(this.change, this.latestPatchNum));
},
_getRevision(change, patchNum) {
@@ -699,7 +840,12 @@
_handleActionTap(e) {
e.preventDefault();
- const el = Polymer.dom(e).localTarget;
+ let el = Polymer.dom(e).localTarget;
+ while (el.is !== 'gr-button') {
+ if (!el.parentElement) { return; }
+ el = el.parentElement;
+ }
+
const key = el.getAttribute('data-action-key');
if (key.startsWith(ADDITIONAL_ACTION_KEY_PREFIX) ||
key.indexOf('~') !== -1) {
@@ -723,6 +869,7 @@
},
_handleAction(type, key) {
+ this.$.reporting.reportInteraction(`${type}-${key}`);
switch (type) {
case ActionType.REVISION:
this._handleRevisionAction(key);
@@ -751,12 +898,21 @@
this._fireAction(
this._prependSlash(key), action, true, action.payload);
break;
+ case ChangeActions.EDIT:
+ this._handleEditTap();
+ break;
+ case ChangeActions.STOP_EDIT:
+ this._handleStopEditTap();
+ break;
case ChangeActions.DELETE:
this._handleDeleteTap();
break;
case ChangeActions.DELETE_EDIT:
this._handleDeleteEditTap();
break;
+ case ChangeActions.FOLLOW_UP:
+ this._handleFollowUpTap();
+ break;
case ChangeActions.WIP:
this._handleWipTap();
break;
@@ -778,6 +934,7 @@
switch (key) {
case RevisionActions.REBASE:
this._showActionDialog(this.$.confirmRebase);
+ this.$.confirmRebase.fetchRecentChanges();
break;
case RevisionActions.CHERRYPICK:
this._handleCherrypickTap();
@@ -786,10 +943,9 @@
this._handleDownloadTap();
break;
case RevisionActions.SUBMIT:
- if (!this._canSubmitChange()) {
- return;
- }
- // eslint-disable-next-line no-fallthrough
+ if (!this._canSubmitChange()) { return; }
+ this._showActionDialog(this.$.confirmSubmitDialog);
+ break;
default:
this._fireAction(this._prependSlash(key),
this.revisionActions[key], true);
@@ -826,15 +982,23 @@
this.$.overlay.close();
},
- _handleRebaseConfirm() {
+ _handleRebaseConfirm(e) {
const el = this.$.confirmRebase;
- const payload = {base: el.base};
+ const payload = {base: e.detail.base};
this.$.overlay.close();
el.hidden = true;
this._fireAction('/rebase', this.revisionActions.rebase, true, payload);
},
_handleCherrypickConfirm() {
+ this._handleCherryPickRestApi(false);
+ },
+
+ _handleCherrypickConflictConfirm() {
+ this._handleCherryPickRestApi(true);
+ },
+
+ _handleCherryPickRestApi(conflicts) {
const el = this.$.confirmCherrypick;
if (!el.branch) {
// TODO(davido): Fix error handling
@@ -853,7 +1017,9 @@
true,
{
destination: el.branch,
+ base: el.baseCommit ? el.baseCommit : null,
message: el.message,
+ allow_conflicts: conflicts,
}
);
},
@@ -893,6 +1059,15 @@
{message: el.message});
},
+ _handleCreateFollowUpChange() {
+ this.$.createFollowUpChange.handleCreateChange();
+ this._handleCloseCreateFollowUpChange();
+ },
+
+ _handleCloseCreateFollowUpChange() {
+ this.$.overlay.close();
+ },
+
_handleDeleteConfirm() {
this._fireAction('/', this.actions[ChangeActions.DELETE], false);
},
@@ -903,6 +1078,12 @@
this._fireAction('/edit', this.actions.deleteEdit, false);
},
+ _handleSubmitConfirm() {
+ if (!this._canSubmitChange()) { return; }
+ this._hideAllDialogs();
+ this._fireAction('/submit', this.revisionActions.submit, true);
+ },
+
_getActionOverflowIndex(type, key) {
return this._overflowActions.findIndex(action => {
return action.type === type && action.key === key;
@@ -941,8 +1122,9 @@
_fireAction(endpoint, action, revAction, opt_payload) {
const cleanupFn =
this._setLoadingOnButtonWithKey(action.__type, action.__key);
- this._send(action.method, opt_payload, endpoint, revAction, cleanupFn)
- .then(this._handleResponse.bind(this, action));
+
+ this._send(action.method, opt_payload, endpoint, revAction, cleanupFn,
+ action).then(this._handleResponse.bind(this, action));
},
_showActionDialog(dialog) {
@@ -961,8 +1143,7 @@
_setLabelValuesOnRevert(newChangeId) {
const labels = this.$.jsAPI.getLabelValuesPostRevert(this.change);
if (!labels) { return Promise.resolve(); }
- return this.$.restAPI.getChangeURLAndSend(newChangeId,
- this.actions.revert.method, 'current', '/review', {labels});
+ return this.$.restAPI.saveChangeReview(newChangeId, 'current', {labels});
},
_handleResponse(action, response) {
@@ -983,14 +1164,14 @@
break;
case ChangeActions.DELETE:
if (action.__type === ActionType.CHANGE) {
- page.show('/');
+ Gerrit.Nav.navigateToRelativeUrl(Gerrit.Nav.getUrlForRoot());
}
break;
case ChangeActions.WIP:
case ChangeActions.DELETE_EDIT:
case ChangeActions.PUBLISH_EDIT:
case ChangeActions.REBASE_EDIT:
- page.show(this.changePath(this.changeNum));
+ Gerrit.Nav.navigateToChange(this.change);
break;
default:
this.dispatchEvent(new CustomEvent('reload-change',
@@ -1000,9 +1181,16 @@
});
},
- _handleResponseError(response) {
+ _handleResponseError(action, response, body) {
+ if (action && action.__key === RevisionActions.CHERRYPICK) {
+ if (response && response.status === 409 &&
+ body && !body.allow_conflicts) {
+ return this._showActionDialog(
+ this.$.confirmCherrypickConflict);
+ }
+ }
return response.text().then(errText => {
- this.fire('show-alert',
+ this.fire('show-error',
{message: `Could not perform action: ${errText}`});
if (!errText.startsWith('Change is already up to date')) {
throw Error(errText);
@@ -1016,18 +1204,17 @@
* @param {string} actionEndpoint
* @param {boolean} revisionAction
* @param {?Function} cleanupFn
- * @param {?Function=} opt_errorFn
+ * @param {!Object|undefined} action
*/
- _send(method, payload, actionEndpoint, revisionAction, cleanupFn,
- opt_errorFn) {
+ _send(method, payload, actionEndpoint, revisionAction, cleanupFn, action) {
const handleError = response => {
cleanupFn.call(this);
- this._handleResponseError(response);
+ this._handleResponseError(action, response, payload);
};
- return this.fetchIsLatestKnown(this.change, this.$.restAPI)
- .then(isLatest => {
- if (!isLatest) {
+ return this.fetchChangeUpdates(this.change, this.$.restAPI)
+ .then(result => {
+ if (!result.isLatest) {
this.fire('show-alert', {
message: 'Cannot set label: a newer patch has been ' +
'uploaded to this change.',
@@ -1044,9 +1231,9 @@
return Promise.resolve();
}
- const patchNum = revisionAction ? this.patchNum : null;
- return this.$.restAPI.getChangeURLAndSend(this.changeNum, method,
- patchNum, actionEndpoint, payload, handleError, this)
+ const patchNum = revisionAction ? this.latestPatchNum : null;
+ return this.$.restAPI.executeChangeAction(this.changeNum, method,
+ actionEndpoint, patchNum, payload, handleError)
.then(response => {
cleanupFn.call(this);
return response;
@@ -1081,6 +1268,10 @@
this._showActionDialog(this.$.confirmDeleteEditDialog);
},
+ _handleFollowUpTap() {
+ this._showActionDialog(this.$.createFollowUpDialog);
+ },
+
_handleWipTap() {
this._fireAction('/wip', this.actions.wip, false);
},
@@ -1121,9 +1312,16 @@
if (quickApprove) {
changeActionValues.unshift(quickApprove);
}
+
return revisionActionValues
.concat(changeActionValues)
- .sort(this._actionComparator.bind(this));
+ .sort(this._actionComparator.bind(this))
+ .map(action => {
+ if (ACTIONS_WITH_ICONS.has(action.__key)) {
+ action.icon = action.__key;
+ }
+ return action;
+ });
},
_getActionPriority(action) {
@@ -1170,6 +1368,13 @@
});
},
+ _filterPrimaryActions(_topLevelActions) {
+ this._topLevelPrimaryActions = _topLevelActions.filter(action =>
+ action.__primary);
+ this._topLevelSecondaryActions = _topLevelActions.filter(action =>
+ !action.__primary);
+ },
+
_computeMenuActions(actionRecord, hiddenActionsRecord) {
const hiddenActions = hiddenActionsRecord.base || [];
return actionRecord.base.filter(a => {
@@ -1182,6 +1387,7 @@
name: action.label,
id: `${key}-${action.__type}`,
action,
+ tooltip: action.title,
};
});
},
@@ -1219,5 +1425,21 @@
check();
});
},
+
+ _handleEditTap() {
+ this.dispatchEvent(new CustomEvent('edit-tap', {bubbles: false}));
+ },
+
+ _handleStopEditTap() {
+ this.dispatchEvent(new CustomEvent('stop-edit-tap', {bubbles: false}));
+ },
+
+ _computeHasTooltip(title) {
+ return !!title;
+ },
+
+ _computeHasIcon(action) {
+ return action.icon ? '' : 'hidden';
+ },
});
})();