Add settings section for display name

Change-Id: Ic81bfa53f712cc52680fbd311842c688a18b6bb4
diff --git a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.js b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.js
index c425318..0c4b706 100644
--- a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.js
+++ b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.js
@@ -63,11 +63,12 @@
         type: Boolean,
         notify: true,
         computed: '_computeHasUnsavedChanges(_hasNameChange, ' +
-          '_hasUsernameChange, _hasStatusChange)',
+          '_hasUsernameChange, _hasStatusChange, _hasDisplayNameChange)',
       },
 
       _hasNameChange: Boolean,
       _hasUsernameChange: Boolean,
+      _hasDisplayNameChange: Boolean,
       _hasStatusChange: Boolean,
       _loading: {
         type: Boolean,
@@ -95,6 +96,7 @@
     return [
       '_nameChanged(_account.name)',
       '_statusChanged(_account.status)',
+      '_displayNameChanged(_account.display_name)',
     ];
   }
 
@@ -110,6 +112,7 @@
     promises.push(this.$.restAPI.getAccount().then(account => {
       this._hasNameChange = false;
       this._hasUsernameChange = false;
+      this._hasDisplayNameChange = false;
       this._hasStatusChange = false;
       // Provide predefined value for username to trigger computation of
       // username mutability.
@@ -136,10 +139,12 @@
     // Set only the fields that have changed.
     // Must be done in sequence to avoid race conditions (@see Issue 5721)
     return this._maybeSetName()
-        .then(this._maybeSetUsername.bind(this))
-        .then(this._maybeSetStatus.bind(this))
+        .then(() => this._maybeSetUsername())
+        .then(() => this._maybeSetDisplayName())
+        .then(() => this._maybeSetStatus())
         .then(() => {
           this._hasNameChange = false;
+          this._hasDisplayNameChange = false;
           this._hasStatusChange = false;
           this._saving = false;
           this.fire('account-detail-update');
@@ -158,14 +163,22 @@
       Promise.resolve();
   }
 
+  _maybeSetDisplayName() {
+    return this._hasDisplayNameChange ?
+      this.$.restAPI.setAccountDisplayName(this._account.display_name) :
+      Promise.resolve();
+  }
+
   _maybeSetStatus() {
     return this._hasStatusChange ?
       this.$.restAPI.setAccountStatus(this._account.status) :
       Promise.resolve();
   }
 
-  _computeHasUnsavedChanges(nameChanged, usernameChanged, statusChanged) {
-    return nameChanged || usernameChanged || statusChanged;
+  _computeHasUnsavedChanges(nameChanged, usernameChanged, statusChanged,
+      displayNameChanged) {
+    return nameChanged || usernameChanged || statusChanged
+        || displayNameChanged;
   }
 
   _computeUsernameMutable(config, username) {
@@ -191,6 +204,11 @@
     this._hasStatusChange = true;
   }
 
+  _displayNameChanged() {
+    if (this._loading) { return; }
+    this._hasDisplayNameChange = true;
+  }
+
   _usernameChanged() {
     if (this._loading || !this._account) { return; }
     this._hasUsernameChange =
diff --git a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_html.js b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_html.js
index 6e37c25..0f5ddc8 100644
--- a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_html.js
+++ b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_html.js
@@ -79,6 +79,14 @@
         </span>
       </section>
       <section>
+        <span class="title">Display name (defaults to "Full name")</span>
+        <span class="value">
+          <iron-input on-keydown="_handleKeydown" bind-value="{{_account.display_name}}">
+            <input is="iron-input" id="displayNameInput" disabled="[[_saving]]" on-keydown="_handleKeydown" bind-value="{{_account.display_name}}">
+          </iron-input>
+        </span>
+      </section>
+      <section>
         <span class="title">Status (e.g. "Vacation")</span>
         <span class="value">
           <iron-input on-keydown="_handleKeydown" bind-value="{{_account.status}}">
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
index 3e78bd3..fea44b4 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
@@ -772,6 +772,23 @@
   }
 
   /**
+   * @param {string} displayName
+   * @param {function(?Response, string=)=} opt_errFn
+   */
+  setAccountDisplayName(displayName, opt_errFn) {
+    const req = {
+      method: 'PUT',
+      url: '/accounts/self/displayname',
+      body: {display_name: displayName},
+      errFn: opt_errFn,
+      parseResponse: true,
+      reportUrlAsIs: true,
+    };
+    return this._restApiHelper.send(req)
+        .then(newName => this._updateCachedAccount({displayName: newName}));
+  }
+
+  /**
    * @param {string} status
    * @param {function(?Response, string=)=} opt_errFn
    */