Make action order configurable from plugin
``` js
Gerrit.install(function(plugin) {
// Make cherry-pick appear first.
plugin.changeActions().setActionPriority(
'revision', 'cherrypick', -5);
// Make cherry-pick appear last
plugin.changeActions().setActionPriority(
'revision', 'cherrypick', 5);
});
```
Default priority list is:
- Reply is always first, aligned to the left
- More actions if always after it
- Quick approve (CodeReview+2) after them, with priority at -3
- Primary actions come last, with priority of 3
- Change actions before primary, with priority of 2
- Revision actions before change actions, with priority of 1
- In case of a tie, actions are sorted alphabetically
Feature: Issue 5360
Change-Id: I7f36954608f764bff4e36a4a2f916bf0dda3859d
This commit is contained in:
@@ -87,6 +87,14 @@
|
||||
method: 'POST',
|
||||
};
|
||||
|
||||
var ActionPriority = {
|
||||
CHANGE: 2,
|
||||
DEFAULT: 0,
|
||||
PRIMARY: 3,
|
||||
REVIEW: -3,
|
||||
REVISION: 1,
|
||||
};
|
||||
|
||||
Polymer({
|
||||
is: 'gr-change-actions',
|
||||
|
||||
@@ -149,7 +157,8 @@
|
||||
_allActionValues: {
|
||||
type: Array,
|
||||
computed: '_computeAllActions(actions.*, revisionActions.*,' +
|
||||
'primaryActionKeys.*, _additionalActions.*, change)',
|
||||
'primaryActionKeys.*, _additionalActions.*, change, ' +
|
||||
'_actionPriorityOverrides.*)',
|
||||
},
|
||||
_topLevelActions: {
|
||||
type: Array,
|
||||
@@ -181,6 +190,10 @@
|
||||
return value;
|
||||
},
|
||||
},
|
||||
_actionPriorityOverrides: {
|
||||
type: Array,
|
||||
value: function() { return []; },
|
||||
},
|
||||
_additionalActions: {
|
||||
type: Array,
|
||||
value: function() { return []; },
|
||||
@@ -279,6 +292,25 @@
|
||||
}
|
||||
},
|
||||
|
||||
setActionPriority: function(type, key, priority) {
|
||||
if (type !== ActionType.CHANGE && type !== ActionType.REVISION) {
|
||||
throw Error('Invalid action type given: ' + type);
|
||||
}
|
||||
var index = this._actionPriorityOverrides.findIndex(function(action) {
|
||||
return action.type === type && action.key === key;
|
||||
});
|
||||
var action = {
|
||||
type: type,
|
||||
key: key,
|
||||
priority: priority,
|
||||
};
|
||||
if (index !== -1) {
|
||||
this.set('_actionPriorityOverrides', index, action);
|
||||
} else {
|
||||
this.push('_actionPriorityOverrides', action);
|
||||
}
|
||||
},
|
||||
|
||||
setActionHidden: function(type, key, hidden) {
|
||||
if (type !== ActionType.CHANGE && type !== ActionType.REVISION) {
|
||||
throw Error('Invalid action type given: ' + type);
|
||||
@@ -764,10 +796,12 @@
|
||||
* @param {splices} primariesRecord
|
||||
* @param {splices} additionalActionsRecord
|
||||
* @param {Object} change The change object.
|
||||
* @param {Object} priorityOverridesRecord
|
||||
* @return {Array}
|
||||
*/
|
||||
_computeAllActions: function(changeActionsRecord, revisionActionsRecord,
|
||||
primariesRecord, additionalActionsRecord, change) {
|
||||
primariesRecord, additionalActionsRecord, change,
|
||||
priorityOverridesRecord) {
|
||||
var revisionActionValues = this._getActionValues(revisionActionsRecord,
|
||||
primariesRecord, additionalActionsRecord, ActionType.REVISION);
|
||||
var changeActionValues = this._getActionValues(changeActionsRecord,
|
||||
@@ -778,36 +812,43 @@
|
||||
}
|
||||
return revisionActionValues
|
||||
.concat(changeActionValues)
|
||||
.sort(this._actionComparator);
|
||||
.sort(this._actionComparator.bind(this));
|
||||
},
|
||||
|
||||
_getActionPriority: function(action) {
|
||||
if (action.__type && action.__key) {
|
||||
var overrideAction = this._actionPriorityOverrides.find(function(i) {
|
||||
return i.type === action.__type && i.key === action.__key;
|
||||
});
|
||||
|
||||
if (overrideAction !== undefined) {
|
||||
return overrideAction.priority;
|
||||
}
|
||||
}
|
||||
if (action.__key === 'review') {
|
||||
return ActionPriority.REVIEW;
|
||||
} else if (action.__primary) {
|
||||
return ActionPriority.PRIMARY;
|
||||
} else if (action.__type === ActionType.CHANGE) {
|
||||
return ActionPriority.CHANGE;
|
||||
} else if (action.__type === ActionType.REVISION) {
|
||||
return ActionPriority.REVISION;
|
||||
}
|
||||
return ActionPriority.DEFAULT;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sort comparator to define the order of change actions.
|
||||
*/
|
||||
_actionComparator: function(actionA, actionB) {
|
||||
// The code review action always appears first.
|
||||
if (actionA.__key === 'review') {
|
||||
return -1;
|
||||
} else if (actionB.__key === 'review') {
|
||||
return 1;
|
||||
var priorityDelta = this._getActionPriority(actionA) -
|
||||
this._getActionPriority(actionB);
|
||||
// Sort by the button label if same priority.
|
||||
if (priorityDelta === 0) {
|
||||
return actionA.label > actionB.label ? 1 : -1;
|
||||
} else {
|
||||
return priorityDelta;
|
||||
}
|
||||
|
||||
// Primary actions always appear last.
|
||||
if (actionA.__primary) {
|
||||
return 1;
|
||||
} else if (actionB.__primary) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Change actions appear before revision actions.
|
||||
if (actionA.__type === 'change' && actionB.__type === 'revision') {
|
||||
return 1;
|
||||
} else if (actionA.__type === 'revision' && actionB.__type === 'change') {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Otherwise, sort by the button label.
|
||||
return actionA.label > actionB.label ? 1 : -1;
|
||||
},
|
||||
|
||||
_computeTopLevelActions: function(actionRecord, hiddenActionsRecord,
|
||||
|
||||
@@ -207,16 +207,15 @@ limitations under the License.
|
||||
test('_actionComparator sort order', function() {
|
||||
var actions = [
|
||||
{label: '123', __type: 'change', __key: 'review'},
|
||||
{label: 'abc', __type: 'revision'},
|
||||
{label: 'abc-ro', __type: 'revision'},
|
||||
{label: 'abc', __type: 'change'},
|
||||
{label: 'def', __type: 'change'},
|
||||
{label: 'def', __type: 'change', __primary: true},
|
||||
{label: 'def-p', __type: 'change', __primary: true},
|
||||
];
|
||||
|
||||
var result = actions.slice();
|
||||
result.reverse();
|
||||
result.sort(element._actionComparator);
|
||||
|
||||
result.sort(element._actionComparator.bind(element));
|
||||
assert.deepEqual(result, actions);
|
||||
});
|
||||
|
||||
|
||||
@@ -38,6 +38,11 @@
|
||||
return this._el.setActionOverflow(type, key, overflow);
|
||||
};
|
||||
|
||||
GrChangeActionsInterface.prototype.setActionPriority = function(type, key,
|
||||
priority) {
|
||||
return this._el.setActionPriority(type, key, priority);
|
||||
};
|
||||
|
||||
GrChangeActionsInterface.prototype.setActionHidden = function(type, key,
|
||||
hidden) {
|
||||
return this._el.setActionHidden(type, key, hidden);
|
||||
|
||||
@@ -155,5 +155,25 @@ breaking changes to gr-change-actions won’t be noticed.
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('change actions priority', function(done) {
|
||||
var key1 = changeActions.add(changeActions.ActionType.REVISION, 'Bork!');
|
||||
var key2 = changeActions.add(changeActions.ActionType.CHANGE, 'Squanch?');
|
||||
flush(function() {
|
||||
var buttons =
|
||||
Polymer.dom(element.root).querySelectorAll('[data-action-key]');
|
||||
assert.equal(buttons[0].getAttribute('data-action-key'), key1);
|
||||
assert.equal(buttons[1].getAttribute('data-action-key'), key2);
|
||||
changeActions.setActionPriority(
|
||||
changeActions.ActionType.REVISION, key1, 10);
|
||||
flush(function() {
|
||||
buttons =
|
||||
Polymer.dom(element.root).querySelectorAll('[data-action-key]');
|
||||
assert.equal(buttons[0].getAttribute('data-action-key'), key2);
|
||||
assert.equal(buttons[1].getAttribute('data-action-key'), key1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user