Merge changes I325d2062,I6efb64c4,Ic911d307

* changes:
  Don't display user header above project dashboards
  Support any dashboard ref, not just "custom"
  Link to project dashboards instead of custom
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.html b/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.html
index 36a7d76..1d49db9 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.html
+++ b/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.html
@@ -53,7 +53,7 @@
           </tr>
           <template is="dom-repeat" items="[[item.dashboards]]">
             <tr class="table">
-              <td class="name"><a href$="[[_getUrl(item.project, item.sections)]]">[[item.path]]</a></td>
+              <td class="name"><a href$="[[_getUrl(item.project, item.id)]]">[[item.path]]</a></td>
               <td class="title">[[item.title]]</td>
               <td class="desc">[[item.description]]</td>
               <td class="inherited">[[_computeInheritedFrom(item.project, item.defining_project)]]</td>
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.js b/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.js
index c0fc0cb..7dea7f4 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.js
+++ b/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.js
@@ -43,24 +43,24 @@
       this.$.restAPI.getRepoDashboards(this.repo, errFn).then(res => {
         if (!res) { return Promise.resolve(); }
 
-        // Flatten 2 dimenional array, and sort by id.
+        // Group by ref and sort by id.
         const dashboards = res.concat.apply([], res).sort((a, b) =>
-            a.id > b.id);
-        const customList = dashboards.filter(a => a.ref === 'custom');
-        const defaultList = dashboards.filter(a => a.ref === 'default');
+            a.id < b.id ? -1 : 1);
+        const dashboardsByRef = {};
+        dashboards.forEach(d => {
+          if (!dashboardsByRef[d.ref]) {
+            dashboardsByRef[d.ref] = [];
+          }
+          dashboardsByRef[d.ref].push(d);
+        });
+
         const dashboardBuilder = [];
-        if (customList.length) {
+        Object.keys(dashboardsByRef).sort().forEach(ref => {
           dashboardBuilder.push({
-            section: 'Custom',
-            dashboards: customList,
+            section: ref,
+            dashboards: dashboardsByRef[ref],
           });
-        }
-        if (defaultList.length) {
-          dashboardBuilder.push({
-            section: 'Default',
-            dashboards: defaultList,
-          });
-        }
+        });
 
         this._dashboards = dashboardBuilder;
         this._loading = false;
@@ -68,10 +68,10 @@
       });
     },
 
-    _getUrl(project, sections) {
-      if (!project || !sections) { return ''; }
+    _getUrl(project, id) {
+      if (!project || !id) { return ''; }
 
-      return Gerrit.Nav.getUrlForCustomDashboard(project, sections);
+      return Gerrit.Nav.getUrlForRepoDashboard(project, id);
     },
 
     _computeLoadingClass(loading) {
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards_test.html b/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards_test.html
index 4d86a0c..94bf5e0 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards_test.html
@@ -46,54 +46,61 @@
       sandbox.restore();
     });
 
-    suite('with default only', () => {
+    suite('dashboard table', () => {
       setup(() => {
         sandbox.stub(element.$.restAPI, 'getRepoDashboards').returns(
             Promise.resolve([
-              [
-                {
-                  id: 'default:contributor',
-                  project: 'gerrit',
-                  defining_project: 'gerrit',
-                  ref: 'default',
-                  path: 'contributor',
-                  description: 'Own contributions.',
-                  foreach: 'owner:self',
-                  url: '/dashboard/?params',
-                  title: 'Contributor Dashboard',
-                  sections: [
-                    {
-                      name: 'Mine To Rebase',
-                      query: 'is:open -is:mergeable',
-                    },
-                    {
-                      name: 'My Recently Merged',
-                      query: 'is:merged limit:10',
-                    },
-                  ],
-                },
-              ],
-              [
-                {
-                  id: 'default:open',
-                  project: 'gerrit',
-                  defining_project: 'Public-Projects',
-                  ref: 'default',
-                  path: 'open',
-                  description: 'Recent open changes.',
-                  url: '/dashboard/?params',
-                  title: 'Open Changes',
-                  sections: [
-                    {
-                      name: 'Open Changes',
-                      query: 'status:open project:${project} -age:7w',
-                    },
-                  ],
-                },
-              ],
+              {
+                id: 'default:contributor',
+                project: 'gerrit',
+                defining_project: 'gerrit',
+                ref: 'default',
+                path: 'contributor',
+                description: 'Own contributions.',
+                foreach: 'owner:self',
+                url: '/dashboard/?params',
+                title: 'Contributor Dashboard',
+                sections: [
+                  {
+                    name: 'Mine To Rebase',
+                    query: 'is:open -is:mergeable',
+                  },
+                  {
+                    name: 'My Recently Merged',
+                    query: 'is:merged limit:10',
+                  },
+                ],
+              },
+              {
+                id: 'custom:custom2',
+                project: 'gerrit',
+                defining_project: 'Public-Projects',
+                ref: 'custom',
+                path: 'open',
+                description: 'Recent open changes.',
+                url: '/dashboard/?params',
+                title: 'Open Changes',
+                sections: [
+                  {
+                    name: 'Open Changes',
+                    query: 'status:open project:${project} -age:7w',
+                  },
+                ],
+              },
+              {
+                id: 'default:abc',
+                project: 'gerrit',
+                ref: 'default',
+              },
+              {
+                id: 'custom:custom1',
+                project: 'gerrit',
+                ref: 'custom',
+              },
             ]));
       });
-      test('loading', done => {
+
+      test('loading, sections, and ordering', done => {
         assert.isTrue(element._loading);
         assert.notEqual(getComputedStyle(element.$.loadingContainer).display,
             'none');
@@ -101,143 +108,20 @@
             'none');
         element.repo = 'test';
         flush(() => {
-          assert.equal(element._dashboards.length, 1);
-          assert.equal(element._dashboards[0].section, 'Default');
-          assert.equal(element._dashboards[0].dashboards.length, 2);
           assert.equal(getComputedStyle(element.$.loadingContainer).display,
               'none');
           assert.notEqual(getComputedStyle(element.$.dashboards).display,
               'none');
-          done();
-        });
-      });
 
-      test('dispatched command-tap on button tap', done => {
-        element.repo = 'test';
-        flush(() => {
-          assert.equal(element._dashboards.length, 1);
-          assert.equal(element._dashboards[0].section, 'Default');
-          assert.equal(element._dashboards[0].dashboards.length, 2);
-          done();
-        });
-      });
-    });
-
-    suite('with custom only', () => {
-      setup(() => {
-        sandbox.stub(element.$.restAPI, 'getRepoDashboards').returns(
-            Promise.resolve([
-              [
-                {
-                  id: 'custom:custom1',
-                  project: 'gerrit',
-                  defining_project: 'gerrit',
-                  ref: 'custom',
-                  path: 'contributor',
-                  description: 'Own contributions.',
-                  foreach: 'owner:self',
-                  url: '/dashboard/?params',
-                  title: 'Contributor Dashboard',
-                  sections: [
-                    {
-                      name: 'Mine To Rebase',
-                      query: 'is:open -is:mergeable',
-                    },
-                    {
-                      name: 'My Recently Merged',
-                      query: 'is:merged limit:10',
-                    },
-                  ],
-                },
-              ],
-              [
-                {
-                  id: 'custom:custom2',
-                  project: 'gerrit',
-                  defining_project: 'Public-Projects',
-                  ref: 'custom',
-                  path: 'open',
-                  description: 'Recent open changes.',
-                  url: '/dashboard/?params',
-                  title: 'Open Changes',
-                  sections: [
-                    {
-                      name: 'Open Changes',
-                      query: 'status:open project:${project} -age:7w',
-                    },
-                  ],
-                },
-              ],
-            ]));
-      });
-
-      test('dispatched command-tap on button tap', done => {
-        element.repo = 'test';
-        flush(() => {
-          assert.equal(element._dashboards.length, 1);
-          assert.equal(element._dashboards[0].section, 'Custom');
-          assert.equal(element._dashboards[0].dashboards.length, 2);
-          done();
-        });
-      });
-    });
-
-    suite('with custom and default', () => {
-      setup(() => {
-        sandbox.stub(element.$.restAPI, 'getRepoDashboards').returns(
-            Promise.resolve([
-              [
-                {
-                  id: 'default:contributor',
-                  project: 'gerrit',
-                  defining_project: 'gerrit',
-                  ref: 'default',
-                  path: 'contributor',
-                  description: 'Own contributions.',
-                  foreach: 'owner:self',
-                  url: '/dashboard/?params',
-                  title: 'Contributor Dashboard',
-                  sections: [
-                    {
-                      name: 'Mine To Rebase',
-                      query: 'is:open -is:mergeable',
-                    },
-                    {
-                      name: 'My Recently Merged',
-                      query: 'is:merged limit:10',
-                    },
-                  ],
-                },
-              ],
-              [
-                {
-                  id: 'custom:custom2',
-                  project: 'gerrit',
-                  defining_project: 'Public-Projects',
-                  ref: 'custom',
-                  path: 'open',
-                  description: 'Recent open changes.',
-                  url: '/dashboard/?params',
-                  title: 'Open Changes',
-                  sections: [
-                    {
-                      name: 'Open Changes',
-                      query: 'status:open project:${project} -age:7w',
-                    },
-                  ],
-                },
-              ],
-            ]));
-      });
-
-      test('dispatched command-tap on button tap', done => {
-        element.repo = 'test';
-        flush(() => {
           assert.equal(element._dashboards.length, 2);
-          assert.equal(element._dashboards[0].section, 'Custom');
-          assert.equal(element._dashboards[1].section, 'Default');
-          assert.equal(element._dashboards[0].dashboards.length, 1);
-          assert.equal(element._dashboards[1].dashboards.length, 1);
+          assert.equal(element._dashboards[0].section, 'custom');
+          assert.equal(element._dashboards[1].section, 'default');
+
+          const dashboards = element._dashboards[0].dashboards;
+          assert.equal(dashboards.length, 2);
+          assert.equal(dashboards[0].id, 'custom:custom1');
+          assert.equal(dashboards[1].id, 'custom:custom2');
+
           done();
         });
       });
@@ -245,7 +129,7 @@
 
     suite('test url', () => {
       test('_getUrl', () => {
-        sandbox.stub(Gerrit.Nav, 'getUrlForCustomDashboard',
+        sandbox.stub(Gerrit.Nav, 'getUrlForRepoDashboard',
             () => '/r/dashboard/test');
 
         assert.equal(element._getUrl('/dashboard/test', {}), '/r/dashboard/test');
diff --git a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.html b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.html
index 99aa265..b0ba8a2b 100644
--- a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.html
+++ b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.html
@@ -87,7 +87,7 @@
     <div hidden$="[[_loading]]" hidden>
       <gr-user-header
           user-id="[[params.user]]"
-          class$="[[_computeUserHeaderClass(params.user)]]"></gr-user-header>
+          class$="[[_computeUserHeaderClass(params)]]"></gr-user-header>
       <gr-change-list
           show-star
           show-reviewed-state
diff --git a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.js b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.js
index 3fc4089..0625bbe 100644
--- a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.js
+++ b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.js
@@ -37,7 +37,7 @@
       /** @type {{ selectedChangeIndex: number }} */
       viewState: Object,
 
-      /** @type {{ user: string }} */
+      /** @type {{ project: string, user: string }} */
       params: {
         type: Object,
       },
@@ -217,8 +217,12 @@
           });
     },
 
-    _computeUserHeaderClass(userParam) {
-      return userParam === 'self' ? 'hide' : '';
+    _computeUserHeaderClass(params) {
+      if (!params || !!params.project || !params.user
+          || params.user === 'self') {
+        return 'hide';
+      }
+      return '';
     },
 
     _handleToggleStar(e) {
diff --git a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.html b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.html
index 78fdee6..618ec65 100644
--- a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.html
+++ b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.html
@@ -314,10 +314,13 @@
     });
 
     test('_computeUserHeaderClass', () => {
-      assert.equal(element._computeUserHeaderClass(undefined), '');
-      assert.equal(element._computeUserHeaderClass(''), '');
-      assert.equal(element._computeUserHeaderClass('self'), 'hide');
-      assert.equal(element._computeUserHeaderClass('user'), '');
+      assert.equal(element._computeUserHeaderClass(undefined), 'hide');
+      assert.equal(element._computeUserHeaderClass({}), 'hide');
+      assert.equal(element._computeUserHeaderClass({user: 'self'}), 'hide');
+      assert.equal(element._computeUserHeaderClass({user: 'user'}), '');
+      assert.equal(
+          element._computeUserHeaderClass({project: 'p', user: 'user'}),
+          'hide');
     });
 
     test('404 page', done => {
diff --git a/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html b/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html
index 7278c5a..b1433a3 100644
--- a/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html
+++ b/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html
@@ -522,14 +522,15 @@
 
       /**
        * @param {string} repo The name of the repo.
-       * @param {!Array} sections The sections to display in the dashboard
+       * @param {string} dashboard The ID of the dashboard, in the form of
+       *     '<ref>:<path>'.
        * @return {string}
        */
-      getUrlForCustomDashboard(repo, sections) {
+      getUrlForRepoDashboard(repo, dashboard) {
         return this._getUrlFor({
-          repo,
           view: Gerrit.Nav.View.DASHBOARD,
-          sections,
+          repo,
+          dashboard,
         });
       },
 
diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router.js b/polygerrit-ui/app/elements/core/gr-router/gr-router.js
index 0f2bbff..f4f36b3 100644
--- a/polygerrit-ui/app/elements/core/gr-router/gr-router.js
+++ b/polygerrit-ui/app/elements/core/gr-router/gr-router.js
@@ -427,7 +427,8 @@
         return `/dashboard/${user}?${queryParams.join('&')}`;
       } else if (repoName) {
         // Project dashboard.
-        return `/p/${repoName}/+/dashboard/${params.dashboard}`;
+        const encodedRepo = this.encodeURL(repoName, true);
+        return `/p/${encodedRepo}/+/dashboard/${params.dashboard}`;
       } else {
         // User dashboard.
         return `/dashboard/${params.user || 'self'}`;