PolyGerrit: Add support for moving changes from one branch to another
Bug: Issue 6844 Change-Id: Id9479af9ef81146bdfa9e90671b657d5677dc160
This commit is contained in:
		@@ -29,6 +29,7 @@ limitations under the License.
 | 
			
		||||
 | 
			
		||||
<link rel="import" href="../gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.html">
 | 
			
		||||
<link rel="import" href="../gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.html">
 | 
			
		||||
<link rel="import" href="../gr-confirm-move-dialog/gr-confirm-move-dialog.html">
 | 
			
		||||
<link rel="import" href="../gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.html">
 | 
			
		||||
<link rel="import" href="../gr-confirm-revert-dialog/gr-confirm-revert-dialog.html">
 | 
			
		||||
<link rel="import" href="../../../styles/shared-styles.html">
 | 
			
		||||
@@ -124,6 +125,12 @@ limitations under the License.
 | 
			
		||||
          on-cancel="_handleConfirmDialogCancel"
 | 
			
		||||
          project="[[change.project]]"
 | 
			
		||||
          hidden></gr-confirm-cherrypick-dialog>
 | 
			
		||||
      <gr-confirm-move-dialog id="confirmMove"
 | 
			
		||||
          class="confirmDialog"
 | 
			
		||||
          on-confirm="_handleMoveConfirm"
 | 
			
		||||
          on-cancel="_handleConfirmDialogCancel"
 | 
			
		||||
          project="[[change.project]]"
 | 
			
		||||
          hidden></gr-confirm-move-dialog>
 | 
			
		||||
      <gr-confirm-revert-dialog id="confirmRevertDialog"
 | 
			
		||||
          class="confirmDialog"
 | 
			
		||||
          on-confirm="_handleRevertDialogConfirm"
 | 
			
		||||
 
 | 
			
		||||
@@ -51,6 +51,7 @@
 | 
			
		||||
    ABANDON: 'abandon',
 | 
			
		||||
    DELETE: '/',
 | 
			
		||||
    IGNORE: 'ignore',
 | 
			
		||||
    MOVE: 'move',
 | 
			
		||||
    MUTE: 'mute',
 | 
			
		||||
    PRIVATE: 'private',
 | 
			
		||||
    PRIVATE_DELETE: 'private.delete',
 | 
			
		||||
@@ -75,6 +76,7 @@
 | 
			
		||||
    abandon: 'Abandoning...',
 | 
			
		||||
    cherrypick: 'Cherry-Picking...',
 | 
			
		||||
    delete: 'Deleting...',
 | 
			
		||||
    move: 'Moving..',
 | 
			
		||||
    publish: 'Publishing...',
 | 
			
		||||
    rebase: 'Rebasing...',
 | 
			
		||||
    restore: 'Restoring...',
 | 
			
		||||
@@ -216,6 +218,10 @@
 | 
			
		||||
              type: ActionType.REVISION,
 | 
			
		||||
              key: RevisionActions.CHERRYPICK,
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              type: ActionType.CHANGE,
 | 
			
		||||
              key: ChangeActions.MOVE,
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              type: ActionType.REVISION,
 | 
			
		||||
              key: RevisionActions.DOWNLOAD,
 | 
			
		||||
@@ -624,6 +630,9 @@
 | 
			
		||||
        case ChangeActions.WIP:
 | 
			
		||||
          this._handleWipTap();
 | 
			
		||||
          break;
 | 
			
		||||
        case ChangeActions.MOVE:
 | 
			
		||||
          this._handleMoveTap();
 | 
			
		||||
          break;
 | 
			
		||||
        default:
 | 
			
		||||
          this._fireAction(this._prependSlash(key), this.actions[key], false);
 | 
			
		||||
      }
 | 
			
		||||
@@ -717,6 +726,25 @@
 | 
			
		||||
      );
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _handleMoveConfirm() {
 | 
			
		||||
      const el = this.$.confirmMove;
 | 
			
		||||
      if (!el.branch) {
 | 
			
		||||
        this.fire('show-alert', {message: ERR_BRANCH_EMPTY});
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      this.$.overlay.close();
 | 
			
		||||
      el.hidden = true;
 | 
			
		||||
      this._fireAction(
 | 
			
		||||
          '/move',
 | 
			
		||||
          this.actions.move,
 | 
			
		||||
          false,
 | 
			
		||||
          {
 | 
			
		||||
            destination_branch: el.branch,
 | 
			
		||||
            message: el.message,
 | 
			
		||||
          }
 | 
			
		||||
      );
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _handleRevertDialogConfirm() {
 | 
			
		||||
      const el = this.$.confirmRevertDialog;
 | 
			
		||||
      this.$.overlay.close();
 | 
			
		||||
@@ -870,6 +898,12 @@
 | 
			
		||||
      this._showActionDialog(this.$.confirmCherrypick);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _handleMoveTap() {
 | 
			
		||||
      this.$.confirmMove.branch = '';
 | 
			
		||||
      this.$.confirmMove.message = '';
 | 
			
		||||
      this._showActionDialog(this.$.confirmMove);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _handleDownloadTap() {
 | 
			
		||||
      this.fire('download-tap', null, {bubbles: false});
 | 
			
		||||
    },
 | 
			
		||||
 
 | 
			
		||||
@@ -398,6 +398,34 @@ limitations under the License.
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    suite('move change', () => {
 | 
			
		||||
      let fireActionStub;
 | 
			
		||||
 | 
			
		||||
      setup(() => {
 | 
			
		||||
        fireActionStub = sandbox.stub(element, '_fireAction');
 | 
			
		||||
        sandbox.stub(window, 'alert');
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      test('works', () => {
 | 
			
		||||
        element._handleMoveTap();
 | 
			
		||||
 | 
			
		||||
        element._handleMoveConfirm();
 | 
			
		||||
        assert.equal(fireActionStub.callCount, 0);
 | 
			
		||||
 | 
			
		||||
        element.$.confirmMove.branch = 'master';
 | 
			
		||||
        element._handleMoveConfirm();
 | 
			
		||||
        assert.equal(fireActionStub.callCount, 1);
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      test('branch name cleared when re-open move', () => {
 | 
			
		||||
        const emptyBranchName = '';
 | 
			
		||||
        element.$.confirmMove.branch = 'master';
 | 
			
		||||
 | 
			
		||||
        element._handleMoveTap();
 | 
			
		||||
        assert.equal(element.$.confirmMove.branch, emptyBranchName);
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    test('custom actions', done => {
 | 
			
		||||
      // Add a button with the same key as a server-based one to ensure
 | 
			
		||||
      // collisions are taken care of.
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,87 @@
 | 
			
		||||
<!--
 | 
			
		||||
Copyright (C) 2017 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.
 | 
			
		||||
-->
 | 
			
		||||
 | 
			
		||||
<link rel="import" href="../../../bower_components/iron-autogrow-textarea/iron-autogrow-textarea.html">
 | 
			
		||||
<link rel="import" href="../../../bower_components/polymer/polymer.html">
 | 
			
		||||
<link rel="import" href="../../../styles/shared-styles.html">
 | 
			
		||||
<link rel="import" href="../../shared/gr-autocomplete/gr-autocomplete.html">
 | 
			
		||||
<link rel="import" href="../../shared/gr-confirm-dialog/gr-confirm-dialog.html">
 | 
			
		||||
<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
 | 
			
		||||
 | 
			
		||||
<dom-module id="gr-confirm-move-dialog">
 | 
			
		||||
  <template>
 | 
			
		||||
    <style include="shared-styles">
 | 
			
		||||
      :host {
 | 
			
		||||
        display: block;
 | 
			
		||||
        width: 30em;
 | 
			
		||||
      }
 | 
			
		||||
      :host([disabled]) {
 | 
			
		||||
        opacity: .5;
 | 
			
		||||
        pointer-events: none;
 | 
			
		||||
      }
 | 
			
		||||
      label {
 | 
			
		||||
        cursor: pointer;
 | 
			
		||||
      }
 | 
			
		||||
      iron-autogrow-textarea {
 | 
			
		||||
        padding: 0;
 | 
			
		||||
      }
 | 
			
		||||
      .main {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        flex-direction: column;
 | 
			
		||||
        width: 100%;
 | 
			
		||||
      }
 | 
			
		||||
      .main label,
 | 
			
		||||
      .main input[type="text"] {
 | 
			
		||||
        display: block;
 | 
			
		||||
        font: inherit;
 | 
			
		||||
        width: 100%;
 | 
			
		||||
      }
 | 
			
		||||
      .main .message {
 | 
			
		||||
        border: groove;
 | 
			
		||||
        width: 100%;
 | 
			
		||||
      }
 | 
			
		||||
    </style>
 | 
			
		||||
    <gr-confirm-dialog
 | 
			
		||||
        confirm-label="Move Change"
 | 
			
		||||
        on-confirm="_handleConfirmTap"
 | 
			
		||||
        on-cancel="_handleCancelTap">
 | 
			
		||||
      <div class="header">Move Change to Another Branch</div>
 | 
			
		||||
      <div class="main">
 | 
			
		||||
        <label for="branchInput">
 | 
			
		||||
          Move change to branch
 | 
			
		||||
        </label>
 | 
			
		||||
        <gr-autocomplete
 | 
			
		||||
            id="branchInput"
 | 
			
		||||
            text="{{branch}}"
 | 
			
		||||
            query="[[_query]]"
 | 
			
		||||
            placeholder="Destination branch">
 | 
			
		||||
        </gr-autocomplete>
 | 
			
		||||
        <label for="messageInput">
 | 
			
		||||
          Move Change Commit Message
 | 
			
		||||
        </label>
 | 
			
		||||
        <iron-autogrow-textarea
 | 
			
		||||
            id="messageInput"
 | 
			
		||||
            class="message"
 | 
			
		||||
            autocomplete="on"
 | 
			
		||||
            rows="4"
 | 
			
		||||
            max-rows="15"
 | 
			
		||||
            bind-value="{{message}}"></iron-autogrow-textarea>
 | 
			
		||||
      </div>
 | 
			
		||||
    </gr-confirm-dialog>
 | 
			
		||||
    <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 | 
			
		||||
  </template>
 | 
			
		||||
  <script src="gr-confirm-move-dialog.js"></script>
 | 
			
		||||
</dom-module>
 | 
			
		||||
@@ -0,0 +1,79 @@
 | 
			
		||||
// Copyright (C) 2017 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';
 | 
			
		||||
 | 
			
		||||
  const SUGGESTIONS_LIMIT = 15;
 | 
			
		||||
 | 
			
		||||
  Polymer({
 | 
			
		||||
    is: 'gr-confirm-move-dialog',
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Fired when the confirm button is pressed.
 | 
			
		||||
     *
 | 
			
		||||
     * @event confirm
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Fired when the cancel button is pressed.
 | 
			
		||||
     *
 | 
			
		||||
     * @event cancel
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    properties: {
 | 
			
		||||
      branch: String,
 | 
			
		||||
      message: String,
 | 
			
		||||
      project: String,
 | 
			
		||||
      _query: {
 | 
			
		||||
        type: Function,
 | 
			
		||||
        value() {
 | 
			
		||||
          return this._getProjectBranchesSuggestions.bind(this);
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _handleConfirmTap(e) {
 | 
			
		||||
      e.preventDefault();
 | 
			
		||||
      this.fire('confirm', null, {bubbles: false});
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _handleCancelTap(e) {
 | 
			
		||||
      e.preventDefault();
 | 
			
		||||
      this.fire('cancel', null, {bubbles: false});
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _getProjectBranchesSuggestions(input) {
 | 
			
		||||
      if (input.startsWith('refs/heads/')) {
 | 
			
		||||
        input = input.substring('refs/heads/'.length);
 | 
			
		||||
      }
 | 
			
		||||
      return this.$.restAPI.getProjectBranches(
 | 
			
		||||
          input, this.project, SUGGESTIONS_LIMIT).then(response => {
 | 
			
		||||
            const branches = [];
 | 
			
		||||
            let branch;
 | 
			
		||||
            for (const key in response) {
 | 
			
		||||
              if (!response.hasOwnProperty(key)) { continue; }
 | 
			
		||||
              if (response[key].ref.startsWith('refs/heads/')) {
 | 
			
		||||
                branch = response[key].ref.substring('refs/heads/'.length);
 | 
			
		||||
              } else {
 | 
			
		||||
                branch = response[key].ref;
 | 
			
		||||
              }
 | 
			
		||||
              branches.push({
 | 
			
		||||
                name: branch,
 | 
			
		||||
              });
 | 
			
		||||
            }
 | 
			
		||||
            return branches;
 | 
			
		||||
          });
 | 
			
		||||
    },
 | 
			
		||||
  });
 | 
			
		||||
})();
 | 
			
		||||
@@ -0,0 +1,81 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<!--
 | 
			
		||||
Copyright (C) 2017 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.
 | 
			
		||||
-->
 | 
			
		||||
 | 
			
		||||
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
 | 
			
		||||
<title>gr-confirm-move-dialog</title>
 | 
			
		||||
 | 
			
		||||
<script src="../../../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
 | 
			
		||||
<script src="../../../bower_components/web-component-tester/browser.js"></script>
 | 
			
		||||
<link rel="import" href="../../../test/common-test-setup.html"/>
 | 
			
		||||
<link rel="import" href="gr-confirm-move-dialog.html">
 | 
			
		||||
 | 
			
		||||
<script>void(0);</script>
 | 
			
		||||
 | 
			
		||||
<test-fixture id="basic">
 | 
			
		||||
  <template>
 | 
			
		||||
    <gr-confirm-move-dialog></gr-confirm-move-dialog>
 | 
			
		||||
  </template>
 | 
			
		||||
</test-fixture>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
  suite('gr-confirm-move-dialog tests', () => {
 | 
			
		||||
    let element;
 | 
			
		||||
 | 
			
		||||
    setup(() => {
 | 
			
		||||
      stub('gr-rest-api-interface', {
 | 
			
		||||
        getProjectBranches(input) {
 | 
			
		||||
          if (input.startsWith('test')) {
 | 
			
		||||
            return Promise.resolve([
 | 
			
		||||
              {
 | 
			
		||||
                ref: 'refs/heads/test-branch',
 | 
			
		||||
                revision: '67ebf73496383c6777035e374d2d664009e2aa5c',
 | 
			
		||||
                can_delete: true,
 | 
			
		||||
              },
 | 
			
		||||
            ]);
 | 
			
		||||
          } else {
 | 
			
		||||
            return Promise.resolve({});
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
      element = fixture('basic');
 | 
			
		||||
      element.project = 'test-project';
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    test('with updated commit message', () => {
 | 
			
		||||
      element.branch = 'master';
 | 
			
		||||
      const myNewMessage = 'updated commit message';
 | 
			
		||||
      element.message = myNewMessage;
 | 
			
		||||
      flushAsynchronousOperations();
 | 
			
		||||
      assert.equal(element.message, myNewMessage);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    test('_getProjectBranchesSuggestions empty', done => {
 | 
			
		||||
      element._getProjectBranchesSuggestions('nonexistent').then(branches => {
 | 
			
		||||
        assert.equal(branches.length, 0);
 | 
			
		||||
        done();
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    test('_getProjectBranchesSuggestions non-empty', done => {
 | 
			
		||||
      element._getProjectBranchesSuggestions('test-branch').then(branches => {
 | 
			
		||||
        assert.equal(branches.length, 1);
 | 
			
		||||
        assert.equal(branches[0].name, 'test-branch');
 | 
			
		||||
        done();
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
</script>
 | 
			
		||||
@@ -51,6 +51,7 @@ limitations under the License.
 | 
			
		||||
    'change/gr-comment-list/gr-comment-list_test.html',
 | 
			
		||||
    'change/gr-commit-info/gr-commit-info_test.html',
 | 
			
		||||
    'change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_test.html',
 | 
			
		||||
    'change/gr-confirm-move-dialog/gr-confirm-move-dialog_test.html',
 | 
			
		||||
    'change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_test.html',
 | 
			
		||||
    'change/gr-confirm-revert-dialog/gr-confirm-revert-dialog_test.html',
 | 
			
		||||
    'change/gr-download-dialog/gr-download-dialog_test.html',
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user