Merge "Fix javascript errors in gr-admin-view components"
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.js b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.js
index fd3e491..50f4091 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.js
+++ b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.js
@@ -286,17 +286,23 @@
 
     _computeGroupName(groupId) {
       if (!groupId) { return ''; }
+
       const promises = [];
       this.$.restAPI.getGroupConfig(groupId).then(group => {
+        if (!group || !group.name) { return; }
+
         this._groupName = group.name;
         this.reload();
+
         promises.push(this.$.restAPI.getIsAdmin().then(isAdmin => {
           this._isAdmin = isAdmin;
         }));
+
         promises.push(this.$.restAPI.getIsGroupOwner(group.name).then(
             isOwner => {
               this._groupOwner = isOwner;
             }));
+
         return Promise.all(promises).then(() => {
           this.reload();
         });
diff --git a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.js b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.js
index 0bc9a99..6ab0561 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.js
+++ b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.js
@@ -39,17 +39,21 @@
     },
 
     _getAuditLogs() {
-      if (!this.groupId) {
-        return '';
-      }
-      return this.$.restAPI.getGroupAuditLog(this.groupId).then(auditLog => {
-        if (!auditLog) {
-          this._auditLog = [];
-          return;
-        }
-        this._auditLog = auditLog;
-        this._loading = false;
-      });
+      if (!this.groupId) { return ''; }
+
+      const errFn = response => {
+        this.fire('page-error', {response});
+      };
+
+      return this.$.restAPI.getGroupAuditLog(this.groupId, errFn)
+          .then(auditLog => {
+            if (!auditLog) {
+              this._auditLog = [];
+              return;
+            }
+            this._auditLog = auditLog;
+            this._loading = false;
+          });
     },
 
     _status(item) {
@@ -57,9 +61,8 @@
     },
 
     _computeGroupUrl(id) {
-      if (!id) {
-        return '';
-      }
+      if (!id) { return ''; }
+
       return this.getBaseUrl() + '/admin/groups/' + id;
     },
 
diff --git a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log_test.html b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log_test.html
index b179718..883ca29 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log_test.html
@@ -34,11 +34,17 @@
 <script>
   suite('gr-group-audit-log tests', () => {
     let element;
+    let sandbox;
 
     setup(() => {
+      sandbox = sinon.sandbox.create();
       element = fixture('basic');
     });
 
+    teardown(() => {
+      sandbox.restore();
+    });
+
     suite('members', () => {
       test('test getNameForMember', () => {
         let account = {
@@ -117,5 +123,24 @@
         assert.equal(element._getNameForUser(account.user), 'test-email');
       });
     });
+
+    suite('404', () => {
+      test('fires page-error', done => {
+        element.groupId = 1;
+
+        const response = {status: 404};
+        sandbox.stub(
+            element.$.restAPI, 'getGroupAuditLog', (group, errFn) => {
+              errFn(response);
+            });
+
+        element.addEventListener('page-error', e => {
+          assert.deepEqual(e.detail.response, response);
+          done();
+        });
+
+        element._getAuditLogs();
+      });
+    });
   });
 </script>
diff --git a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.js b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.js
index 5257e69..440a997 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.js
+++ b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.js
@@ -75,9 +75,13 @@
 
       const promises = [];
 
-      return this.$.restAPI.getGroupConfig(this.groupId).then(
-          config => {
-            if (!config.name) { return; }
+      const errFn = response => {
+        this.fire('page-error', {response});
+      };
+
+      return this.$.restAPI.getGroupConfig(this.groupId, errFn)
+          .then(config => {
+            if (!config || !config.name) { return Promise.resolve(); }
 
             this._groupName = config.name;
 
diff --git a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_test.html b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_test.html
index d670d4d..031d4be 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_test.html
@@ -38,9 +38,11 @@
     let groups;
     let groupMembers;
     let includedGroups;
+    let groupStub;
 
     setup(() => {
       sandbox = sinon.sandbox.create();
+
       groups = {
         name: 'Administrators',
         owner: 'Administrators',
@@ -118,9 +120,6 @@
         getConfig() {
           return Promise.resolve();
         },
-        getGroupConfig() {
-          return Promise.resolve(groups);
-        },
         getGroupMembers() {
           return Promise.resolve(groupMembers);
         },
@@ -137,6 +136,9 @@
       element = fixture('basic');
       sandbox.stub(element, 'getBaseUrl').returns('https://test/site');
       element.groupId = 1;
+      groupStub = sandbox.stub(element.$.restAPI, 'getGroupConfig', () => {
+        return Promise.resolve(groups);
+      });
       return element._loadGroupDetails();
     });
 
@@ -251,5 +253,29 @@
       assert.equal(element._itemId, '1000098');
       assert.equal(element._itemName, '1000098');
     });
+
+    test('_computeLoadingClass', () => {
+      assert.equal(element._computeLoadingClass(true), 'loading');
+
+      assert.equal(element._computeLoadingClass(false), '');
+    });
+
+    test('fires page-error', done => {
+      groupStub.restore();
+
+      element.groupId = 1;
+
+      const response = {status: 404};
+      sandbox.stub(
+          element.$.restAPI, 'getGroupConfig', (group, errFn) => {
+            errFn(response);
+          });
+      element.addEventListener('page-error', e => {
+        assert.deepEqual(e.detail.response, response);
+        done();
+      });
+
+      element._loadGroupDetails();
+    });
   });
 </script>
diff --git a/polygerrit-ui/app/elements/admin/gr-group/gr-group.js b/polygerrit-ui/app/elements/admin/gr-group/gr-group.js
index d975675..e6626f5 100644
--- a/polygerrit-ui/app/elements/admin/gr-group/gr-group.js
+++ b/polygerrit-ui/app/elements/admin/gr-group/gr-group.js
@@ -95,18 +95,26 @@
     _loadGroup() {
       if (!this.groupId) { return; }
 
-      return this.$.restAPI.getGroupConfig(this.groupId).then(
-          config => {
+      const promises = [];
+
+      const errFn = response => {
+        this.fire('page-error', {response});
+      };
+
+      return this.$.restAPI.getGroupConfig(this.groupId, errFn)
+          .then(config => {
+            if (!config || !config.name) { return Promise.resolve(); }
+
             this._groupName = config.name;
 
-            this.$.restAPI.getIsAdmin().then(isAdmin => {
+            promises.push(this.$.restAPI.getIsAdmin().then(isAdmin => {
               this._isAdmin = isAdmin ? true : false;
-            });
+            }));
 
-            this.$.restAPI.getIsGroupOwner(config.name)
+            promises.push(this.$.restAPI.getIsGroupOwner(config.name)
                 .then(isOwner => {
                   this._groupOwner = isOwner ? true : false;
-                });
+                }));
 
             // If visible to all is undefined, set to false. If it is defined
             // as false, setting to false is fine. If any optional values
@@ -119,7 +127,9 @@
 
             this.fire('title-change', {title: config.name});
 
-            this._loading = false;
+            return Promise.all(promises).then(() => {
+              this._loading = false;
+            });
           });
     },
 
diff --git a/polygerrit-ui/app/elements/admin/gr-group/gr-group_test.html b/polygerrit-ui/app/elements/admin/gr-group/gr-group_test.html
index 16a6261..fb3f37e 100644
--- a/polygerrit-ui/app/elements/admin/gr-group/gr-group_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-group/gr-group_test.html
@@ -35,25 +35,28 @@
   suite('gr-group tests', () => {
     let element;
     let sandbox;
+    let groupStub;
+    const group = {
+      id: '6a1e70e1a88782771a91808c8af9bbb7a9871389',
+      url: '#/admin/groups/uuid-6a1e70e1a88782771a91808c8af9bbb7a9871389',
+      options: {
+      },
+      description: 'Gerrit Site Administrators',
+      group_id: 1,
+      owner: 'Administrators',
+      owner_id: '6a1e70e1a88782771a91808c8af9bbb7a9871389',
+      name: 'Administrators',
+    };
 
     setup(() => {
       sandbox = sinon.sandbox.create();
       stub('gr-rest-api-interface', {
         getLoggedIn() { return Promise.resolve(true); },
-        getGroupConfig() {
-          return Promise.resolve({
-            id: '6a1e70e1a88782771a91808c8af9bbb7a9871389',
-            url: '#/admin/groups/uuid-6a1e70e1a88782771a91808c8af9bbb7a9871389',
-            options: {
-            },
-            description: 'Gerrit Site Administrators',
-            group_id: 1,
-            owner: 'Administrators',
-            owner_id: '6a1e70e1a88782771a91808c8af9bbb7a9871389',
-          });
-        },
       });
       element = fixture('basic');
+      groupStub = sandbox.stub(element.$.restAPI, 'getGroupConfig', () => {
+        return Promise.resolve(group);
+      });
     });
 
     teardown(() => {
@@ -117,6 +120,30 @@
       });
     });
 
+    test('test for undefined group name', done => {
+      groupStub.restore();
+
+      sandbox.stub(element.$.restAPI, 'getGroupConfig', () => {
+        return Promise.resolve({});
+      });
+
+      assert.isUndefined(element.groupId);
+
+      element.groupId = 1;
+
+      assert.isDefined(element.groupId);
+
+      // Test that loading shows instead of filling
+      // in group details
+      element._loadGroup().then(() => {
+        assert.isTrue(element.$.loading.classList.contains('loading'));
+
+        assert.isTrue(element._loading);
+
+        done();
+      });
+    });
+
     test('test fire event', done => {
       element._groupConfig = {
         name: 'test-group',
@@ -156,5 +183,29 @@
       const owner = false;
       assert.equal(element._computeGroupDisabled(owner, admin), true);
     });
+
+    test('_computeLoadingClass', () => {
+      assert.equal(element._computeLoadingClass(true), 'loading');
+      assert.equal(element._computeLoadingClass(false), '');
+    });
+
+    test('fires page-error', done => {
+      groupStub.restore();
+
+      element.groupId = 1;
+
+      const response = {status: 404};
+      sandbox.stub(
+          element.$.restAPI, 'getGroupConfig', (group, errFn) => {
+            errFn(response);
+          });
+
+      element.addEventListener('page-error', e => {
+        assert.deepEqual(e.detail.response, response);
+        done();
+      });
+
+      element._loadGroup();
+    });
   });
 </script>
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.js b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.js
index d0af0f1..59a94c8 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.js
+++ b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.js
@@ -126,25 +126,40 @@
      */
     _repoChanged(repo) {
       if (!repo) { return Promise.resolve(); }
+
       const promises = [];
+
+      const errFn = response => {
+        this.fire('page-error', {response});
+      };
+
       // Always reset sections when a project changes.
       this._sections = [];
-      promises.push(this.$.restAPI.getRepoAccessRights(repo).then(res => {
-        this._inheritsFrom = res.inherits_from;
-        this._local = res.local;
-        this._groups = res.groups;
-        this._weblinks = res.config_web_links || [];
-        this._canUpload = res.can_upload;
-        return this.toSortedArray(this._local);
-      }));
+      promises.push(this.$.restAPI.getRepoAccessRights(repo, errFn)
+          .then(res => {
+            if (!res) { return Promise.resolve(); }
 
-      promises.push(this.$.restAPI.getCapabilities().then(res => {
-        return res;
-      }));
+            this._inheritsFrom = res.inherits_from;
+            this._local = res.local;
+            this._groups = res.groups;
+            this._weblinks = res.config_web_links || [];
+            this._canUpload = res.can_upload;
+            return this.toSortedArray(this._local);
+          }));
 
-      promises.push(this.$.restAPI.getRepo(repo).then(res => {
-        return res.labels;
-      }));
+      promises.push(this.$.restAPI.getCapabilities(errFn)
+          .then(res => {
+            if (!res) { return Promise.resolve(); }
+
+            return res;
+          }));
+
+      promises.push(this.$.restAPI.getRepo(repo, errFn)
+          .then(res => {
+            if (!res) { return Promise.resolve(); }
+
+            return res.labels;
+          }));
 
       promises.push(this.$.restAPI.getIsAdmin().then(isAdmin => {
         this._isAdmin = isAdmin;
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_test.html b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_test.html
index 242662c..c53f216 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_test.html
@@ -217,6 +217,22 @@
       assert.equal(element._computeLoadingClass(false), '');
     });
 
+    test('fires page-error', done => {
+      const response = {status: 404};
+
+      sandbox.stub(
+          element.$.restAPI, 'getRepoAccessRights', (repoName, errFn) => {
+            errFn(response);
+          });
+
+      element.addEventListener('page-error', e => {
+        assert.deepEqual(e.detail.response, response);
+        done();
+      });
+
+      element.repo = 'test';
+    });
+
     suite('with defined sections', () => {
       const testEditSaveCancelBtns = () => {
         // Edit button is visible and Save button is hidden.
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.js b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.js
index d554f4d..ca92ad4 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.js
+++ b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.js
@@ -47,10 +47,17 @@
     _loadRepo() {
       if (!this.repo) { return Promise.resolve(); }
 
-      return this.$.restAPI.getProjectConfig(this.repo).then(config => {
-        this._repoConfig = config;
-        this._loading = false;
-      });
+      const errFn = response => {
+        this.fire('page-error', {response});
+      };
+
+      return this.$.restAPI.getProjectConfig(this.repo, errFn)
+          .then(config => {
+            if (!config) { return Promise.resolve(); }
+
+            this._repoConfig = config;
+            this._loading = false;
+          });
     },
 
     _computeLoadingClass(loading) {
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_test.html b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_test.html
index 762089f..9e25a63 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_test.html
@@ -36,13 +36,14 @@
   suite('gr-repo-commands tests', () => {
     let element;
     let sandbox;
+    let repoStub;
 
     setup(() => {
       sandbox = sinon.sandbox.create();
-      stub('gr-rest-api-interface', {
-        getProjectConfig() { return Promise.resolve({}); },
-      });
       element = fixture('basic');
+      repoStub = sandbox.stub(element.$.restAPI, 'getProjectConfig', () => {
+        return Promise.resolve({});
+      });
     });
 
     teardown(() => {
@@ -113,5 +114,25 @@
         });
       });
     });
+
+    suite('404', () => {
+      test('fires page-error', done => {
+        repoStub.restore();
+
+        element.repo = 'test';
+
+        const response = {status: 404};
+        sandbox.stub(
+            element.$.restAPI, 'getProjectConfig', (repo, errFn) => {
+              errFn(response);
+            });
+        element.addEventListener('page-error', e => {
+          assert.deepEqual(e.detail.response, response);
+          done();
+        });
+
+        element._loadRepo();
+      });
+    });
   });
 </script>
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 bbdf92f..1a92f25 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
@@ -32,7 +32,14 @@
     _repoChanged(repo) {
       this._loading = true;
       if (!repo) { return Promise.resolve(); }
-      this.$.restAPI.getRepoDashboards(this.repo).then(res => {
+
+      const errFn = response => {
+        this.fire('page-error', {response});
+      };
+
+      this.$.restAPI.getRepoDashboards(this.repo, errFn).then(res => {
+        if (!res) { return Promise.resolve(); }
+
         // Flatten 2 dimenional array, and sort by id.
         const dashboards = res.concat.apply([], res).sort((a, b) =>
             a.id > b.id);
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 bb886c7..91c5b06 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
@@ -241,5 +241,22 @@
         });
       });
     });
+
+    suite('404', () => {
+      test('fires page-error', done => {
+        const response = {status: 404};
+        sandbox.stub(
+            element.$.restAPI, 'getRepoDashboards', (repo, errFn) => {
+              errFn(response);
+            });
+
+        element.addEventListener('page-error', e => {
+          assert.deepEqual(e.detail.response, response);
+          done();
+        });
+
+        element.repo = 'test';
+      });
+    });
   });
 </script>
diff --git a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.js b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.js
index 2febb25..0d70e5d 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.js
+++ b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.js
@@ -118,18 +118,27 @@
       if (!this.repo) { return Promise.resolve(); }
 
       const promises = [];
+
+      const errFn = response => {
+        this.fire('page-error', {response});
+      };
+
       promises.push(this._getLoggedIn().then(loggedIn => {
         this._loggedIn = loggedIn;
         if (loggedIn) {
           this.$.restAPI.getRepoAccess(this.repo).then(access => {
+            if (!access) { return Promise.resolve(); }
+
             // If the user is not an owner, is_owner is not a property.
             this._readOnly = !access[this.repo].is_owner;
           });
         }
       }));
 
-      promises.push(this.$.restAPI.getProjectConfig(this.repo).then(
-          config => {
+      promises.push(this.$.restAPI.getProjectConfig(this.repo, errFn)
+          .then(config => {
+            if (!config) { return Promise.resolve(); }
+
             if (config.default_submit_type) {
               // The gr-select is bound to submit_type, which needs to be the
               // *configured* submit type. When default_submit_type is
@@ -147,6 +156,8 @@
           }));
 
       promises.push(this.$.restAPI.getConfig().then(config => {
+        if (!config) { return Promise.resolve(); }
+
         this._schemesObj = config.download.schemes;
         this._noteDbEnabled = !!config.note_db_enabled;
       }));
diff --git a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_test.html b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_test.html
index 9ea0177..b0c16fd 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_test.html
@@ -35,6 +35,66 @@
   suite('gr-repo tests', () => {
     let element;
     let sandbox;
+    let repoStub;
+    const repoConf = {
+      description: 'Access inherited by all other projects.',
+      use_contributor_agreements: {
+        value: false,
+        configured_value: 'FALSE',
+      },
+      use_content_merge: {
+        value: false,
+        configured_value: 'FALSE',
+      },
+      use_signed_off_by: {
+        value: false,
+        configured_value: 'FALSE',
+      },
+      create_new_change_for_all_not_in_target: {
+        value: false,
+        configured_value: 'FALSE',
+      },
+      require_change_id: {
+        value: false,
+        configured_value: 'FALSE',
+      },
+      enable_signed_push: {
+        value: false,
+        configured_value: 'FALSE',
+      },
+      require_signed_push: {
+        value: false,
+        configured_value: 'FALSE',
+      },
+      reject_implicit_merges: {
+        value: false,
+        configured_value: 'FALSE',
+      },
+      private_by_default: {
+        value: false,
+        configured_value: 'FALSE',
+      },
+      match_author_to_committer_date: {
+        value: false,
+        configured_value: 'FALSE',
+      },
+      reject_empty_commit: {
+        value: false,
+        configured_value: 'FALSE',
+      },
+      enable_reviewer_by_email: {
+        value: false,
+        configured_value: 'FALSE',
+      },
+      max_object_size_limit: {},
+      submit_type: 'MERGE_IF_NECESSARY',
+      default_submit_type: {
+        value: 'MERGE_IF_NECESSARY',
+        configured_value: 'INHERIT',
+        inherited_value: 'MERGE_IF_NECESSARY',
+      },
+    };
+
     const REPO = 'test-repo';
     const SCHEMES = {http: {}, repo: {}, ssh: {}};
 
@@ -50,71 +110,14 @@
       sandbox = sinon.sandbox.create();
       stub('gr-rest-api-interface', {
         getLoggedIn() { return Promise.resolve(false); },
-        getProjectConfig() {
-          return Promise.resolve({
-            description: 'Access inherited by all other projects.',
-            use_contributor_agreements: {
-              value: false,
-              configured_value: 'FALSE',
-            },
-            use_content_merge: {
-              value: false,
-              configured_value: 'FALSE',
-            },
-            use_signed_off_by: {
-              value: false,
-              configured_value: 'FALSE',
-            },
-            create_new_change_for_all_not_in_target: {
-              value: false,
-              configured_value: 'FALSE',
-            },
-            require_change_id: {
-              value: false,
-              configured_value: 'FALSE',
-            },
-            enable_signed_push: {
-              value: false,
-              configured_value: 'FALSE',
-            },
-            require_signed_push: {
-              value: false,
-              configured_value: 'FALSE',
-            },
-            reject_implicit_merges: {
-              value: false,
-              configured_value: 'FALSE',
-            },
-            private_by_default: {
-              value: false,
-              configured_value: 'FALSE',
-            },
-            match_author_to_committer_date: {
-              value: false,
-              configured_value: 'FALSE',
-            },
-            reject_empty_commit: {
-              value: false,
-              configured_value: 'FALSE',
-            },
-            enable_reviewer_by_email: {
-              value: false,
-              configured_value: 'FALSE',
-            },
-            max_object_size_limit: {},
-            submit_type: 'MERGE_IF_NECESSARY',
-            default_submit_type: {
-              value: 'MERGE_IF_NECESSARY',
-              configured_value: 'INHERIT',
-              inherited_value: 'MERGE_IF_NECESSARY',
-            },
-          });
-        },
         getConfig() {
           return Promise.resolve({download: {}});
         },
       });
       element = fixture('basic');
+      repoStub = sandbox.stub(element.$.restAPI, 'getProjectConfig', () => {
+        return Promise.resolve(repoConf);
+      });
     });
 
     teardown(() => {
@@ -230,6 +233,24 @@
       ]);
     });
 
+    test('fires page-error', done => {
+      repoStub.restore();
+
+      element.repo = 'test';
+
+      const response = {status: 404};
+      sandbox.stub(
+          element.$.restAPI, 'getProjectConfig', (repo, errFn) => {
+            errFn(response);
+          });
+      element.addEventListener('page-error', e => {
+        assert.deepEqual(e.detail.response, response);
+        done();
+      });
+
+      element._loadRepo();
+    });
+
     suite('admin', () => {
       setup(() => {
         element.repo = REPO;
diff --git a/polygerrit-ui/app/elements/gr-app.js b/polygerrit-ui/app/elements/gr-app.js
index 6c96fc1..fecb904 100644
--- a/polygerrit-ui/app/elements/gr-app.js
+++ b/polygerrit-ui/app/elements/gr-app.js
@@ -196,6 +196,7 @@
         '_showChangeView',
         '_showDiffView',
         '_showSettingsView',
+        '_showAdminView',
       ];
       for (const showProp of props) {
         this.set(showProp, false);
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 5666d3f..88faaba 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
@@ -238,18 +238,18 @@
       return this.fetchJSON('/config/server/info');
     },
 
-    getRepo(repo) {
+    getRepo(repo, opt_errFn) {
       // TODO(kaspern): Rename rest api from /projects/ to /repos/ once backend
       // supports it.
       return this._fetchSharedCacheURL(
-          '/projects/' + encodeURIComponent(repo));
+          '/projects/' + encodeURIComponent(repo), opt_errFn);
     },
 
-    getProjectConfig(repo) {
+    getProjectConfig(repo, opt_errFn) {
       // TODO(kaspern): Rename rest api from /projects/ to /repos/ once backend
       // supports it.
       return this._fetchSharedCacheURL(
-          '/projects/' + encodeURIComponent(repo) + '/config');
+          '/projects/' + encodeURIComponent(repo) + '/config', opt_errFn);
     },
 
     getRepoAccess(repo) {
@@ -259,11 +259,12 @@
           '/access/?project=' + encodeURIComponent(repo));
     },
 
-    getRepoDashboards(repo) {
+    getRepoDashboards(repo, opt_errFn) {
       // TODO(kaspern): Rename rest api from /projects/ to /repos/ once backend
       // supports it.
       return this._fetchSharedCacheURL(
-          `/projects/${encodeURIComponent(repo)}/dashboards?inherited`);
+          `/projects/${encodeURIComponent(repo)}/dashboards?inherited`,
+          opt_errFn);
     },
 
     saveRepoConfig(repo, config, opt_errFn, opt_ctx) {
@@ -309,9 +310,9 @@
           opt_ctx);
     },
 
-    getGroupConfig(group) {
+    getGroupConfig(group, opt_errFn) {
       const encodeName = encodeURIComponent(group);
-      return this.fetchJSON(`/groups/${encodeName}/detail`);
+      return this.fetchJSON(`/groups/${encodeName}/detail`, opt_errFn);
     },
 
     /**
@@ -393,9 +394,9 @@
           .then(configs => configs.hasOwnProperty(groupName));
     },
 
-    getGroupMembers(groupName) {
+    getGroupMembers(groupName, opt_errFn) {
       const encodeName = encodeURIComponent(groupName);
-      return this.send('GET', `/groups/${encodeName}/members/`)
+      return this.send('GET', `/groups/${encodeName}/members/`, null, opt_errFn)
           .then(response => this.getResponseObject(response));
     },
 
@@ -426,8 +427,9 @@
       return this.send('PUT', `/groups/${encodeId}/options`, options);
     },
 
-    getGroupAuditLog(group) {
-      return this._fetchSharedCacheURL('/groups/' + group + '/log.audit');
+    getGroupAuditLog(group, opt_errFn) {
+      return this._fetchSharedCacheURL(
+          '/groups/' + group + '/log.audit', opt_errFn);
     },
 
     saveGroupMembers(groupName, groupMembers) {
@@ -1167,9 +1169,10 @@
      * @param {string} repo
      * @param {number} reposBranchesPerPage
      * @param {number=} opt_offset
+     * @param {?function(?Response, string=)=} opt_errFn
      * @return {!Promise<?Object>}
      */
-    getRepoBranches(filter, repo, reposBranchesPerPage, opt_offset) {
+    getRepoBranches(filter, repo, reposBranchesPerPage, opt_offset, opt_errFn) {
       const offset = opt_offset || 0;
 
       // TODO(kaspern): Rename rest api from /projects/ to /repos/ once backend
@@ -1177,7 +1180,8 @@
       return this.fetchJSON(
           `/projects/${encodeURIComponent(repo)}/branches` +
           `?n=${reposBranchesPerPage + 1}&S=${offset}` +
-          this._computeFilter(filter)
+          this._computeFilter(filter),
+          opt_errFn
       );
     },
 
@@ -1186,9 +1190,10 @@
      * @param {string} repo
      * @param {number} reposTagsPerPage
      * @param {number=} opt_offset
+     * @param {?function(?Response, string=)=} opt_errFn
      * @return {!Promise<?Object>}
      */
-    getRepoTags(filter, repo, reposTagsPerPage, opt_offset) {
+    getRepoTags(filter, repo, reposTagsPerPage, opt_offset, opt_errFn) {
       const offset = opt_offset || 0;
 
       // TODO(kaspern): Rename rest api from /projects/ to /repos/ once backend
@@ -1196,7 +1201,8 @@
       return this.fetchJSON(
           `/projects/${encodeURIComponent(repo)}/tags` +
           `?n=${reposTagsPerPage + 1}&S=${offset}` +
-          this._computeFilter(filter)
+          this._computeFilter(filter),
+          opt_errFn
       );
     },
 
@@ -1204,21 +1210,26 @@
      * @param {string} filter
      * @param {number} pluginsPerPage
      * @param {number=} opt_offset
+     * @param {?function(?Response, string=)=} opt_errFn
      * @return {!Promise<?Object>}
      */
-    getPlugins(filter, pluginsPerPage, opt_offset) {
+    getPlugins(filter, pluginsPerPage, opt_offset, opt_errFn) {
       const offset = opt_offset || 0;
 
       return this.fetchJSON(
           `/plugins/?all&n=${pluginsPerPage + 1}&S=${offset}` +
-          this._computeFilter(filter)
+          this._computeFilter(filter),
+          opt_errFn
       );
     },
 
-    getRepoAccessRights(repoName) {
+    getRepoAccessRights(repoName, opt_errFn) {
       // TODO(kaspern): Rename rest api from /projects/ to /repos/ once backend
       // supports it.
-      return this.fetchJSON(`/projects/${encodeURIComponent(repoName)}/access`);
+      return this.fetchJSON(
+          `/projects/${encodeURIComponent(repoName)}/access`,
+          opt_errFn
+      );
     },
 
     setRepoAccessRights(repoName, repoInfo) {
@@ -2002,8 +2013,8 @@
           });
     },
 
-    getCapabilities(token) {
-      return this.fetchJSON('/config/server/capabilities');
+    getCapabilities(token, opt_errFn) {
+      return this.fetchJSON('/config/server/capabilities', opt_errFn);
     },
 
     setAssignee(changeNum, assignee) {