Merge "PG: autocomplete reviewers" into stable-2.16
diff --git a/rv-reviewers/rv-filter-section.html b/rv-reviewers/rv-filter-section.html
index d4784cc..104ecbd 100644
--- a/rv-reviewers/rv-filter-section.html
+++ b/rv-reviewers/rv-filter-section.html
@@ -77,6 +77,7 @@
             <rv-reviewer
                 reviewer="{{item}}"
                 can-modify-config="[[canModifyConfig]]"
+                plugin-rest-api="[[pluginRestApi]]"
                 on-reviewer-deleted="_handleReviewerDeleted"
                 on-reviewer-added="_handleReviewerAdded">
             </rv-reviewer>
diff --git a/rv-reviewers/rv-reviewer.html b/rv-reviewers/rv-reviewer.html
index 3609612..339eff7 100644
--- a/rv-reviewers/rv-reviewer.html
+++ b/rv-reviewers/rv-reviewer.html
@@ -19,24 +19,52 @@
     <style include="shared-styles">
       #editReviewerInput {
         display: block;
+        width: 250px;
       }
       .reviewerRow {
         align-items: center;
         display: flex;
       }
-      #reviewerHeader, #editReviewerInput, #deleteCancelBtn, #addBtn {
+      #reviewerHeader,
+      #editReviewerInput,
+      #deleteCancelBtn,
+      #addBtn,
+      #reviewerField {
           margin-left: 3px;
       }
+      #reviewerField {
+        width: 250px;
+        text-indent: 1px;
+        border: 1px solid var(--border-color);
+      }
     </style>
     <style include="gr-form-styles"></style>
     <div class="reviewerRow">
       <h4 id="reviewerHeader">Reviewer:</h4>
-      <input
-          id="editReviewerInput"
-          bind-value="{{reviewer}}"
-          is="iron-input"
-          type="text"
-          disabled="[[_computeReviewerDisabled(reviewer, _originalReviewer)]]">
+      <template is="dom-if" if="[[_computeEditing(reviewer, _originalReviewer)]]">
+        <span class="value">
+            <!--
+              TODO:
+              Investigate wether we could reuse gr-account-list.
+              If the REST API returns AccountInfo instead of an account
+              identifier String we should be able to use gr-account-list(size=1)
+              for all reviewers, including those who are non-editable
+              (#reviewerField below) and allign the plugin with how accounts
+              are displayed in core Gerrit's UI.
+            -->
+            <gr-autocomplete
+                id="editReviewerInput"
+                text="{{reviewer}}"
+                value="{{_reviewerSearchId}}"
+                query="[[_queryReviewers]]"
+                placeholder="Name Or Email"
+                disabled="[[_computeReviewerDisabled(reviewer, _originalReviewer)]]">
+            </gr-autocomplete>
+        </span>
+      </template>
+      <template is="dom-if" if="[[!_computeEditing(reviewer, _originalReviewer)]]">
+        <td id="reviewerField">[[reviewer]]</td>
+      </template>
       <gr-button
           id="deleteCancelBtn"
           on-tap="_handleDeleteCancel"
diff --git a/rv-reviewers/rv-reviewer.js b/rv-reviewers/rv-reviewer.js
index 9698a22..a8da113 100644
--- a/rv-reviewers/rv-reviewer.js
+++ b/rv-reviewers/rv-reviewer.js
@@ -16,8 +16,16 @@
     is: 'rv-reviewer',
 
     properties: {
-      reviewer: String,
       canModifyConfig: Boolean,
+      pluginRestAPi: Object,
+      reviewer: String,
+      _reviewerSearchId: String,
+      _queryReviewers: {
+        type: Function,
+        value() {
+          return this._getAccountSuggestions.bind(this);
+        },
+      },
       _originalReviewer: String,
       _deleted: Boolean,
       _editing: {
@@ -48,13 +56,50 @@
 
     _computeHideAddButton(reviewer, _originalReviewer) {
       return !(this._computeEditing(reviewer, _originalReviewer)
-      && this.$.editReviewerInput.value);
+      && this._reviewerSearchId);
     },
 
     _computeHideDeleteButton(canModifyConfig) {
       return !canModifyConfig;
     },
 
+    _getAccountSuggestions(input) {
+      if (input.length === 0) { return Promise.resolve([]); }
+      return this._getSuggestedAccounts(
+          input).then(accounts => {
+            const accountSuggestions = [];
+            let nameAndEmail;
+            let value;
+            if (!accounts) { return []; }
+            for (const key in accounts) {
+              if (!accounts.hasOwnProperty(key)) { continue; }
+              if (accounts[key].email) {
+                nameAndEmail = accounts[key].name +
+                  ' <' + accounts[key].email + '>';
+              } else {
+                nameAndEmail = accounts[key].name;
+              }
+              if (accounts[key].username) {
+                value = accounts[key].username;
+              } else if (accounts[key].email) {
+                value = accounts[key].email;
+              } else {
+                value = accounts[key]._account_id;
+              }
+              accountSuggestions.push({
+                name: nameAndEmail,
+                value,
+              });
+            }
+            return accountSuggestions;
+          });
+    },
+
+    _getSuggestedAccounts(input) {
+      const suggestUrl = `/accounts/?suggest&q=${input}`;
+      return this.pluginRestApi.get(suggestUrl);
+    },
+
     _handleDeleteCancel() {
       const detail = {editing: this._editing};
       if (this._editing) {
@@ -65,7 +110,7 @@
     },
 
     _handleAddReviewer() {
-      const detail = {reviewer: this.reviewer};
+      const detail = {reviewer: this._reviewerSearchId};
       this._originalReviewer = this.reviewer;
       this.dispatchEvent(
           new CustomEvent('reviewer-added', {detail, bubbles: true}));