Merge "Move edit link from metaA/B level up to diff level"
diff --git a/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.ts b/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.ts
index 39a5d54..738abc0 100644
--- a/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.ts
+++ b/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.ts
@@ -30,7 +30,6 @@
   $: {
     name: HTMLInputElement;
     username: HTMLInputElement;
-    email: HTMLSelectElement;
   };
 }
 
@@ -73,11 +72,17 @@
   _serverConfig?: ServerInfo;
 
   @property({
-    computed: '_computeUsernameMutable(_serverConfig,_account.username)',
+    computed: '_computeUsernameMutable(_serverConfig, _account.username)',
     type: Boolean,
   })
   _usernameMutable = false;
 
+  @property({type: Boolean})
+  _hasUsernameChange?: boolean;
+
+  @property({type: String, observer: '_usernameChanged'})
+  _username?: string;
+
   private readonly restApiService = appContext.restApiService;
 
   /** @override */
@@ -86,26 +91,17 @@
     this._ensureAttribute('role', 'dialog');
   }
 
-  _computeUsernameMutable(config?: ServerInfo, username?: string) {
-    // Polymer 2: check for undefined
-    // username is not being checked for undefined as we want to avoid
-    // setting it null explicitly to trigger the computation
-    if (config === undefined) {
-      return false;
-    }
-
-    return (
-      config.auth.editable_account_fields.includes(
-        EditableAccountField.USER_NAME
-      ) && !username
-    );
-  }
-
   loadData() {
     this._loading = true;
 
     const loadAccount = this.restApiService.getAccount().then(account => {
-      this._account = {...this._account, ...account};
+      if (!account) return;
+      this._hasUsernameChange = false;
+      // Provide predefined value for username to trigger computation of
+      // username mutability.
+      account.username = account.username || '';
+      this._account = account;
+      this._username = account.username;
     });
 
     const loadConfig = this.restApiService.getConfig().then(config => {
@@ -117,17 +113,37 @@
     });
   }
 
+  _usernameChanged() {
+    if (this._loading || !this._account) {
+      return;
+    }
+    this._hasUsernameChange =
+      (this._account.username || '') !== (this._username || '');
+  }
+
+  _computeUsernameMutable(config?: ServerInfo, username?: string) {
+    // Polymer 2: check for undefined
+    if (config === undefined) {
+      return false;
+    }
+
+    // Username may not be changed once it is set.
+    return (
+      config.auth.editable_account_fields.includes(
+        EditableAccountField.USER_NAME
+      ) && !username
+    );
+  }
+
   _save() {
     this._saving = true;
-    const promises = [
-      this.restApiService.setAccountName(this.$.name.value),
-      this.restApiService.setPreferredAccountEmail(this.$.email.value || ''),
-    ];
 
-    if (this._usernameMutable) {
-      promises.push(
-        this.restApiService.setAccountUsername(this.$.username.value)
-      );
+    const promises = [this.restApiService.setAccountName(this.$.name.value)];
+
+    // Note that we are intentionally not acting on this._username being the
+    // empty string (which is falsy).
+    if (this._hasUsernameChange && this._usernameMutable && this._username) {
+      promises.push(this.restApiService.setAccountUsername(this._username));
     }
 
     return Promise.all(promises).then(() => {
@@ -151,12 +167,8 @@
     fireEvent(this, 'close');
   }
 
-  _computeSaveDisabled(name?: string, email?: string, saving?: boolean) {
-    return !name || !email || saving;
-  }
-
-  _computeUsernameClass(usernameMutable: boolean) {
-    return usernameMutable ? '' : 'hide';
+  _computeSaveDisabled(name?: string, username?: string, saving?: boolean) {
+    return saving || (!name && !username);
   }
 
   @observe('_loading')
diff --git a/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog_html.ts b/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog_html.ts
index a1d6a5c..0e31bc9 100644
--- a/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog_html.ts
+++ b/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog_html.ts
@@ -59,9 +59,6 @@
     input {
       width: 20em;
     }
-    section.hide {
-      display: none;
-    }
   </style>
   <div class="container gr-form-styles">
     <header>Please confirm your contact information</header>
@@ -75,35 +72,31 @@
       </p>
       <hr />
       <section>
-        <div class="title">Full Name</div>
-        <iron-input bind-value="{{_account.name}}">
-          <input
-            is="iron-input"
-            id="name"
-            bind-value="{{_account.name}}"
-            disabled="[[_saving]]"
-          />
-        </iron-input>
-      </section>
-      <section class$="[[_computeUsernameClass(_usernameMutable)]]">
-        <div class="title">Username</div>
-        <iron-input bind-value="{{_account.username}}">
-          <input
-            is="iron-input"
-            id="username"
-            bind-value="{{_account.username}}"
-            disabled="[[_saving]]"
-          />
-        </iron-input>
+        <span class="title">Full Name</span>
+        <span class="value">
+          <iron-input bind-value="{{_account.name}}">
+            <input
+              is="iron-input"
+              id="name"
+              bind-value="{{_account.name}}"
+              disabled="[[_saving]]"
+            />
+          </iron-input>
+        </span>
       </section>
       <section>
-        <div class="title">Preferred Email</div>
-        <select id="email" disabled="[[_saving]]">
-          <option value="[[_account.email]]">[[_account.email]]</option>
-          <template is="dom-repeat" items="[[_account.secondary_emails]]">
-            <option value="[[item]]">[[item]]</option>
-          </template>
-        </select>
+        <span class="title">Username</span>
+        <span hidden$="[[_usernameMutable]]" class="value">[[_username]]</span>
+        <span hidden$="[[!_usernameMutable]]" class="value">
+          <iron-input bind-value="{{_username}}">
+            <input
+              is="iron-input"
+              id="username"
+              bind-value="{{_username}}"
+              disabled="[[_saving]]"
+            />
+          </iron-input>
+        </span>
       </section>
       <hr />
       <p>
@@ -123,7 +116,7 @@
         id="saveButton"
         primary=""
         link=""
-        disabled="[[_computeSaveDisabled(_account.name, _account.email, _saving)]]"
+        disabled="[[_computeSaveDisabled(_account.name, _username, _saving)]]"
         on-click="_handleSave"
         >Save</gr-button
       >
diff --git a/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog_test.ts b/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog_test.ts
index ccb7404..22f21e1 100644
--- a/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog_test.ts
+++ b/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog_test.ts
@@ -17,11 +17,7 @@
 import '../../../test/common-test-setup-karma';
 import {GrRegistrationDialog} from './gr-registration-dialog';
 import {queryAndAssert, stubRestApi} from '../../../test/test-utils';
-import {
-  AccountDetailInfo,
-  EmailAddress,
-  Timestamp,
-} from '../../../types/common';
+import {AccountDetailInfo, Timestamp} from '../../../types/common';
 import * as MockInteractions from '@polymer/iron-test-helpers/mock-interactions';
 import {AuthType, EditableAccountField} from '../../../constants/constants';
 import {createServerInfo} from '../../../test/test-data-generators';
@@ -39,8 +35,6 @@
 
     account = {
       name: 'name',
-      email: 'email' as EmailAddress,
-      secondary_emails: ['email2', 'email3'],
       registered_on: '2018-02-08 18:49:18.000000000' as Timestamp,
     };
 
@@ -53,10 +47,6 @@
       account.username = username;
       return Promise.resolve();
     });
-    stubRestApi('setPreferredAccountEmail').callsFake(email => {
-      account.email = email as EmailAddress;
-      return Promise.resolve();
-    });
     stubRestApi('getConfig').returns(
       Promise.resolve({
         ...createServerInfo(),
@@ -116,41 +106,32 @@
   test('saves account details', done => {
     flush(() => {
       element.$.name.value = 'new name';
-      element.$.username.value = 'new username';
-      element.$.email.value = 'email3';
+
+      element.set('_account.username', '');
+      element._hasUsernameChange = false;
+      assert.isTrue(element._usernameMutable);
+
+      element.set('_username', 'new username');
 
       // Nothing should be committed yet.
       assert.equal(account.name, 'name');
       assert.isNotOk(account.username);
-      assert.equal(account.email, 'email' as EmailAddress);
 
       // Save and verify new values are committed.
       save()
         .then(() => {
           assert.equal(account.name, 'new name');
           assert.equal(account.username, 'new username');
-          assert.equal(account.email, 'email3' as EmailAddress);
         })
         .then(done);
     });
   });
 
-  test('email select properly populated', done => {
-    element._account = {
-      email: 'foo' as EmailAddress,
-      secondary_emails: ['bar', 'baz'],
-    };
-    flush(() => {
-      assert.equal(element.$.email.value, 'foo');
-      done();
-    });
-  });
-
   test('save btn disabled', () => {
     const compute = element._computeSaveDisabled;
     assert.isTrue(compute('', '', false));
-    assert.isTrue(compute('', 'test', false));
-    assert.isTrue(compute('test', '', false));
+    assert.isFalse(compute('', 'test', false));
+    assert.isFalse(compute('test', '', false));
     assert.isTrue(compute('test', 'test', true));
     assert.isFalse(compute('test', 'test', false));
   });