Add ability to hide actions via the experimental plugin API

The use case for this is that some projects may not want to have
the submit or cherry-pick buttons visible since they cause confusion
with users.

Change-Id: Id823cd2711ace9a4e7473a791521132b56d8f034
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.html b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.html
index 09d5b84..96c6193 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.html
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.html
@@ -66,6 +66,7 @@
       <section hidden$="[[!_actionCount(actions.*, _additionalActions.*)]]">
         <template is="dom-repeat" items="[[_changeActionValues]]" as="action">
           <gr-button title$="[[action.title]]"
+              hidden$="[[_computeActionHidden(action.__key, _hiddenChangeActions.*)]]"
               primary$="[[action.__primary]]"
               hidden$="[[!action.enabled]]"
               data-action-key$="[[action.__key]]"
@@ -78,6 +79,7 @@
       <section hidden$="[[!_actionCount(_revisionActions.*, _additionalActions.*)]]">
         <template is="dom-repeat" items="[[_revisionActionValues]]" as="action">
           <gr-button title$="[[action.title]]"
+              hidden$="[[_computeActionHidden(action.__key, _hiddenRevisionActions.*)]]"
               primary$="[[action.__primary]]"
               disabled$="[[!action.enabled]]"
               data-action-key$="[[action.__key]]"
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 89c06c4..7a1f7d4 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
@@ -102,6 +102,14 @@
         type: Array,
         value: function() { return []; },
       },
+      _hiddenChangeActions: {
+        type: Array,
+        value: function() { return []; },
+      },
+      _hiddenRevisionActions: {
+        type: Array,
+        value: function() { return []; },
+      },
     },
 
     ActionType: ActionType,
@@ -169,6 +177,24 @@
       ], value);
     },
 
+    setActionHidden: function(type, key, hidden) {
+      var path;
+      if (type === ActionType.CHANGE) {
+        path = '_hiddenChangeActions';
+      } else if (type === ActionType.REVISION) {
+        path = '_hiddenRevisionActions';
+      } else {
+        throw Error('Invalid action type given: ' + type);
+      }
+
+      var idx = this.get(path).indexOf(key);
+      if (hidden && idx === -1) {
+        this.push(path, key);
+      } else if (!hidden && idx !== -1) {
+        this.splice(path, idx, 1);
+      }
+    },
+
     _indexOfActionButtonWithKey: function(key) {
       for (var i = 0; i < this._additionalActions.length; i++) {
         if (this._additionalActions[i].__key === key) {
@@ -270,6 +296,12 @@
           this._getRevision(this.change, this.patchNum));
     },
 
+    _computeActionHidden: function(key, hiddenActionsChangeRecord) {
+      var hiddenActions =
+          (hiddenActionsChangeRecord && hiddenActionsChangeRecord.base) || [];
+      return hiddenActions.indexOf(key) !== -1;
+    },
+
     _getRevision: function(change, patchNum) {
       var num = window.parseInt(patchNum, 10);
       for (var hash in change.revisions) {
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html
index bbd51e2..e091651 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html
@@ -97,6 +97,64 @@
       return element.reload();
     });
 
+    test('hide revision action', function(done) {
+      flush(function() {
+        var buttonEl = element.$$('[data-action-key="submit"]');
+        assert.isOk(buttonEl);
+        assert.isFalse(buttonEl.hasAttribute('hidden'));
+        assert.throws(element.setActionHidden.bind(element, 'invalid type'));
+        element.setActionHidden(element.ActionType.REVISION,
+            element.RevisionActions.SUBMIT, true);
+        assert.lengthOf(element._hiddenRevisionActions, 1);
+        element.setActionHidden(element.ActionType.REVISION,
+            element.RevisionActions.SUBMIT, true);
+        assert.lengthOf(element._hiddenRevisionActions, 1);
+        flush(function() {
+          var buttonEl = element.$$('[data-action-key="submit"]');
+          assert.isOk(buttonEl);
+          assert.isTrue(buttonEl.hasAttribute('hidden'));
+
+          element.setActionHidden(element.ActionType.REVISION,
+            element.RevisionActions.SUBMIT, false);
+          flush(function() {
+            var buttonEl = element.$$('[data-action-key="submit"]');
+            assert.isOk(buttonEl);
+            assert.isFalse(buttonEl.hasAttribute('hidden'));
+            done();
+          });
+        });
+      });
+    });
+
+    test('hide change action', function(done) {
+      flush(function() {
+        var buttonEl = element.$$('[data-action-key="/"]');
+        assert.isOk(buttonEl);
+        assert.isFalse(buttonEl.hasAttribute('hidden'));
+        assert.throws(element.setActionHidden.bind(element, 'invalid type'));
+        element.setActionHidden(element.ActionType.CHANGE,
+            element.ChangeActions.DELETE, true);
+        assert.lengthOf(element._hiddenChangeActions, 1);
+        element.setActionHidden(element.ActionType.CHANGE,
+            element.ChangeActions.DELETE, true);
+        assert.lengthOf(element._hiddenChangeActions, 1);
+        flush(function() {
+          var buttonEl = element.$$('[data-action-key="/"]');
+          assert.isOk(buttonEl);
+          assert.isTrue(buttonEl.hasAttribute('hidden'));
+
+          element.setActionHidden(element.ActionType.CHANGE,
+            element.RevisionActions.DELETE, false);
+          flush(function() {
+            var buttonEl = element.$$('[data-action-key="/"]');
+            assert.isOk(buttonEl);
+            assert.isFalse(buttonEl.hasAttribute('hidden'));
+            done();
+          });
+        });
+      });
+    });
+
     test('buttons show', function(done) {
       flush(function() {
         var buttonEls = Polymer.dom(element.root).querySelectorAll('gr-button');
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api.js
index f7c337b..72c7f6e 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api.js
@@ -33,6 +33,11 @@
     });
   };
 
+  GrChangeActionsInterface.prototype.setActionHidden = function(type, key,
+      hidden) {
+    return this._el.setActionHidden(type, key, hidden);
+  };
+
   GrChangeActionsInterface.prototype.add = function(type, label) {
     return this._el.addActionButton(type, label);
   };
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api_test.html
index 4919a5a..93e676c 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api_test.html
@@ -119,5 +119,22 @@
         });
       });
     });
+
+    test('hide action buttons', function(done) {
+      var key = changeActions.add(changeActions.ActionType.REVISION, 'Bork!');
+      flush(function() {
+        var button = element.$$('[data-action-key="' + key + '"]');
+        assert.isOk(button);
+        assert.isFalse(button.hasAttribute('hidden'));
+        changeActions.setActionHidden(changeActions.ActionType.REVISION, key,
+            true);
+        flush(function() {
+          var button = element.$$('[data-action-key="' + key + '"]');
+          assert.isOk(button);
+          assert.isTrue(button.hasAttribute('hidden'));
+          done();
+        });
+      });
+    });
   });
 </script>