Upload help dialog

Provide a dialog with explanation and copyable commands for how to
update an existing change from local modifications. The button to show
the dialog only appears when a user views their own unmerged change.

Feature: Issue 9532
Change-Id: I841197468f9663d75db9b0e5d20b11943959f5d7
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html
index b73fe02..76d7f1e 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html
@@ -51,6 +51,7 @@
 <link rel="import" href="../gr-related-changes-list/gr-related-changes-list.html">
 <link rel="import" href="../gr-reply-dialog/gr-reply-dialog.html">
 <link rel="import" href="../gr-thread-list/gr-thread-list.html">
+<link rel="import" href="../gr-upload-help-dialog/gr-upload-help-dialog.html">
 
 <dom-module id="gr-change-view">
   <template>
@@ -243,6 +244,9 @@
       #includedInOverlay {
         width: 65em;
       }
+      #uploadHelpOverlay {
+        width: 50em;
+      }
       @media screen and (min-width: 80em) {
         .commitMessage {
           max-width: var(--commit-message-max-width, 100ch);
@@ -527,6 +531,7 @@
             files-expanded="[[_filesExpanded]]"
             on-open-diff-prefs="_handleOpenDiffPrefs"
             on-open-download-dialog="_handleOpenDownloadDialog"
+            on-open-upload-help-dialog="_handleOpenUploadHelpDialog"
             on-open-included-in-dialog="_handleOpenIncludedInDialog"
             on-expand-diffs="_expandAllDiffs"
             on-collapse-diffs="_collapseAllDiffs">
@@ -599,6 +604,10 @@
           config="[[_serverConfig.download]]"
           on-close="_handleDownloadDialogClose"></gr-download-dialog>
     </gr-overlay>
+    <gr-overlay id="uploadHelpOverlay" with-backdrop>
+      <gr-upload-help-dialog
+          on-close="_handleCloseUploadHelpDialog"></gr-upload-help-dialog>
+    </gr-overlay>
     <gr-overlay id="includedInOverlay" with-backdrop>
       <gr-included-in-dialog
           id="includedInDialog"
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
index c47e12e..243ebf1 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
@@ -536,6 +536,14 @@
       this.$.downloadOverlay.close();
     },
 
+    _handleOpenUploadHelpDialog(e) {
+      this.$.uploadHelpOverlay.open();
+    },
+
+    _handleCloseUploadHelpDialog(e) {
+      this.$.uploadHelpOverlay.close();
+    },
+
     _handleMessageReply(e) {
       const msg = e.detail.message.message;
       const quoteStr = msg.split('\n').map(
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.html b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.html
index 3dc556d..5520ac9 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.html
+++ b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.html
@@ -78,13 +78,13 @@
         align-items: center;
         display: flex;
       }
-      .downloadContainer {
-        margin-right: 16px;
-      }
+      .downloadContainer,
+      .uploadContainer,
       .includedInContainer {
         margin-right: 16px;
       }
-      .includedInContainer.hide {
+      .includedInContainer.hide,
+      .uploadContainer.hide {
         display: none;
       }
       .rightControls {
@@ -211,6 +211,11 @@
               change="[[change]]"></gr-edit-controls>
           <span class="separator"></span>
         </span>
+        <span class$="[[_computeUploadHelpContainerClass(change, account)]]">
+          <gr-button link
+              class="upload"
+              on-tap="_handleUploadTap">Update Change</gr-button>
+        </span>
         <span class="downloadContainer desktop">
           <gr-button link
               class="download"
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.js b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.js
index 7c5cbc9..665472b 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.js
+++ b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.js
@@ -19,10 +19,35 @@
 
   // Maximum length for patch set descriptions.
   const PATCH_DESC_MAX_LENGTH = 500;
+  const MERGED_STATUS = 'MERGED';
 
   Polymer({
     is: 'gr-file-list-header',
 
+    /**
+     * @event expand-diffs
+     */
+
+    /**
+     * @event collapse-diffs
+     */
+
+    /**
+     * @event open-diff-prefs
+     */
+
+    /**
+     * @event open-included-in-dialog
+     */
+
+    /**
+     * @event open-download-dialog
+     */
+
+    /**
+     * @event open-upload-help-dialog
+     */
+
     properties: {
       account: Object,
       allPatchSets: Array,
@@ -189,7 +214,8 @@
 
     _handleDownloadTap(e) {
       e.preventDefault();
-      this.fire('open-download-dialog');
+      this.dispatchEvent(
+          new CustomEvent('open-download-dialog', {bubbles: false}));
     },
 
     _computeEditModeClass(editMode) {
@@ -209,7 +235,23 @@
     },
 
     _hideIncludedIn(change) {
-      return change && change.status === 'MERGED' ? '' : 'hide';
+      return change && change.status === MERGED_STATUS ? '' : 'hide';
+    },
+
+    _handleUploadTap(e) {
+      e.preventDefault();
+      this.dispatchEvent(
+          new CustomEvent('open-upload-help-dialog', {bubbles: false}));
+    },
+
+    _computeUploadHelpContainerClass(change, account) {
+      const changeIsMerged = change && change.status === MERGED_STATUS;
+      const ownerId = change && change.owner && change.owner._account_id ?
+          change.owner._account_id : null;
+      const userId = account && account._account_id;
+      const userIsOwner = ownerId && userId && ownerId === userId;
+      const hideContainer = !userIsOwner || changeIsMerged;
+      return 'uploadContainer desktop' + (hideContainer ? ' hide' : '');
     },
   });
 })();
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.html b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.html
index ba186b2..e2685e1 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.html
+++ b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.html
@@ -298,6 +298,17 @@
         flushAsynchronousOperations();
         assert.isFalse(isVisible(element.$.editControls.parentElement));
       });
+
+      test('_computeUploadHelpContainerClass', () => {
+        // Only show the upload helper button when an unmerged change is viewed
+        // by its owner.
+        const accountA = {_account_id: 1};
+        const accountB = {_account_id: 2};
+        assert.notInclude(element._computeUploadHelpContainerClass(
+            {owner: accountA}, accountA), 'hide');
+        assert.include(element._computeUploadHelpContainerClass(
+            {owner: accountA}, accountB), 'hide');
+      });
     });
   });
 </script>
diff --git a/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog.html b/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog.html
new file mode 100644
index 0000000..072e7113
--- /dev/null
+++ b/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog.html
@@ -0,0 +1,102 @@
+<!--
+@license
+Copyright (C) 2018 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/polymer/polymer.html">
+<link rel="import" href="../../shared/gr-dialog/gr-dialog.html">
+<link rel="import" href="../../../styles/shared-styles.html">
+
+<dom-module id="gr-upload-help-dialog">
+  <template>
+    <style include="shared-styles">
+      :host {
+        background-color: var(--dialog-background-color);
+        display: block;
+      }
+      .main {
+        width: 100%;
+      }
+      ol {
+        margin-left: 1em;
+        list-style: decimal;
+      }
+      p,
+      .commandContainer {
+        margin-bottom: .75em;
+      }
+      .commandContainer {
+        background: #f5f5f5;
+        padding: .5em .5em .5em 2.5em;
+        position: relative;
+        width: 100%;
+      }
+      .commandContainer:before {
+        background: #ebebeb;
+        bottom: 0;
+        content: '$';
+        display: block;
+        left: 0;
+        padding: .8em;
+        position: absolute;
+        top: 0;
+        width: 2em;
+      }
+      .commandContainer gr-copy-clipboard {
+        --text-container-style: {
+          border: none;
+        }
+      }
+    </style>
+    <gr-dialog
+        confirm-label="Done"
+        cancel-label=""
+        on-confirm="_handleCloseTap">
+      <div class="header" slot="header">How to update this change:</div>
+      <div class="main" slot="main">
+        <ol>
+          <li>
+            <p>
+              Checkout this change locally and make your desired modifications to
+              the files.
+            </p>
+          </li>
+          <li>
+            <p>
+              Update the local commit with your modifications using the following
+              command.
+            </p>
+            <div class="commandContainer">
+              <gr-copy-clipboard text="[[_commitCommand]]"></gr-copy-clipboard>
+            </div>
+            <p>
+              Leave the "Change-Id:" line of the commit message as is.
+            </p>
+          </li>
+          <li>
+            <p>Push the updated commit to Gerrit.</p>
+            <div class="commandContainer">
+              <gr-copy-clipboard text="[[_pushCommand]]"></gr-copy-clipboard>
+            </div>
+          </li>
+          <li>
+            <p>Refresh this page to view the the update.</p>
+          </li>
+        </ol>
+      </div>
+    </gr-dialog>
+  </template>
+  <script src="gr-upload-help-dialog.js"></script>
+</dom-module>
diff --git a/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog.js b/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog.js
new file mode 100644
index 0000000..d796999
--- /dev/null
+++ b/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog.js
@@ -0,0 +1,50 @@
+/**
+ * @license
+ * Copyright (C) 2018 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 COMMIT_COMMAND = 'git add . && git commit --amend --no-edit';
+  const PUSH_COMMAND = 'git push origin HEAD:refs/for/master';
+
+  Polymer({
+    is: 'gr-upload-help-dialog',
+
+    /**
+     * Fired when the user presses the close button.
+     *
+     * @event close
+     */
+
+    properties: {
+      _commitCommand: {
+        type: String,
+        value: COMMIT_COMMAND,
+        readOnly: true,
+      },
+      _pushCommand: {
+        type: String,
+        value: PUSH_COMMAND,
+        readOnly: true,
+      },
+    },
+
+    _handleCloseTap(e) {
+      e.preventDefault();
+      this.fire('close', null, {bubbles: false});
+    },
+  });
+})();
diff --git a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.html b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.html
index d1d9b33..52785ff 100644
--- a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.html
+++ b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.html
@@ -44,6 +44,7 @@
       input {
         font-family: var(--monospace-font-family);
         font-size: inherit;
+        @apply --text-container-style;
       }
       #icon {
         height: 1.2em;