Merge "Partial revert of I3cf5f9c823d74da58a8b1326153a672959fa3f13"
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.html b/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.html
index 69c8d96..ab9158d 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.html
+++ b/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.html
@@ -45,7 +45,7 @@
             class$="[[computeLoadingClass(_loading)]]">
           <tr class="table">
             <td class="name">
-              <a href$="[[getUrl(path, item.group_id)]]">[[item.name]]</a>
+              <a href$="[[_computeGroupUrl(item.group_id)]]">[[item.name]]</a>
             </td>
             <td class="description">[[item.description]]</td>
             <td class="visibleToAll">[[_visibleToAll(item)]]</td>
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.js b/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.js
index a270a69..130e4f4 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.js
+++ b/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.js
@@ -76,6 +76,10 @@
           this._offset);
     },
 
+    _computeGroupUrl(id) {
+      return this.getUrl(this._path, id);
+    },
+
     _getGroups(filter, groupsPerPage, offset) {
       this._groups = [];
       return this.$.restAPI.getGroups(filter, groupsPerPage, offset)
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-plugin-list/gr-admin-plugin-list.html b/polygerrit-ui/app/elements/admin/gr-admin-plugin-list/gr-admin-plugin-list.html
new file mode 100644
index 0000000..67a89d4
--- /dev/null
+++ b/polygerrit-ui/app/elements/admin/gr-admin-plugin-list/gr-admin-plugin-list.html
@@ -0,0 +1,52 @@
+<!--
+Copyright (C) 2017 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<link rel="import" href="../../../behaviors/gr-list-view-behavior/gr-list-view-behavior.html">
+<link rel="import" href="../../../bower_components/polymer/polymer.html">
+<link rel="import" href="../../shared/gr-list-view/gr-styled-table.html">
+<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
+
+<link rel="import" href="../../../styles/shared-styles.html">
+
+<dom-module id="gr-admin-plugin-list">
+  <template>
+    <style include="shared-styles"></style>
+    <gr-styled-table>
+      <table id="list">
+        <tr class="headerRow">
+          <th class="name topHeader">Plugin Name</th>
+          <th class="version topHeader">Version</th>
+          <th class="status topHeader">Status</th>
+        </tr>
+        <tr id="loading" class$="loadingMsg [[computeLoadingClass(_loading)]]">
+          <td>Loading...</td>
+        </tr>
+        <template is="dom-repeat" items="[[_plugins]]"
+            class$="[[computeLoadingClass(_loading)]]">
+          <tr class="table">
+            <td class="name">
+              <a href$="[[_computePluginUrl(item.index_url)]]">[[item.id]]</a>
+            </td>
+            <td class="version">[[item.version]]</td>
+            <td class="status">[[_status(item)]]</td>
+          </tr>
+        </template>
+      </table>
+    </gr-styled-table>
+    <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
+  </template>
+  <script src="gr-admin-plugin-list.js"></script>
+</dom-module>
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-plugin-list/gr-admin-plugin-list.js b/polygerrit-ui/app/elements/admin/gr-admin-plugin-list/gr-admin-plugin-list.js
new file mode 100644
index 0000000..1885bb0
--- /dev/null
+++ b/polygerrit-ui/app/elements/admin/gr-admin-plugin-list/gr-admin-plugin-list.js
@@ -0,0 +1,58 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+(function() {
+  'use strict';
+
+  Polymer({
+    is: 'gr-admin-plugin-list',
+
+    properties: {
+      _plugins: Array,
+      _loading: {
+        type: Boolean,
+        value: true,
+      },
+    },
+
+    behaviors: [
+      Gerrit.ListViewBehavior,
+    ],
+
+    ready() {
+      return this.$.restAPI.getPlugins()
+          .then(plugins => {
+            if (!plugins) {
+              this._plugins = [];
+              return;
+            }
+            this._plugins = Object.keys(plugins)
+             .map(key => {
+               const plugin = plugins[key];
+               plugin.name = key;
+               return plugin;
+             });
+            this._loading = false;
+          });
+    },
+
+
+    _status(item) {
+      return item.disabled === true ? 'Disabled' : 'Enabled';
+    },
+
+    _computePluginUrl(id) {
+      return this.getUrl('/', id);
+    },
+  });
+})();
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-plugin-list/gr-admin-plugin-list_test.html b/polygerrit-ui/app/elements/admin/gr-admin-plugin-list/gr-admin-plugin-list_test.html
new file mode 100644
index 0000000..b946854
--- /dev/null
+++ b/polygerrit-ui/app/elements/admin/gr-admin-plugin-list/gr-admin-plugin-list_test.html
@@ -0,0 +1,86 @@
+<!DOCTYPE html>
+<!--
+Copyright (C) 2017 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+<title>gr-admin-plugin-list</title>
+
+<script src="../../../bower_components/page/page.js"></script>
+<script src="../../../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
+<script src="../../../bower_components/web-component-tester/browser.js"></script>
+<link rel="import" href="../../../test/common-test-setup.html"/>
+<link rel="import" href="gr-admin-plugin-list.html">
+
+<script>void(0);</script>
+
+<test-fixture id="basic">
+  <template>
+    <gr-admin-plugin-list></gr-admin-plugin-list>
+  </template>
+</test-fixture>
+
+<script>
+  let counter = 0;
+  const pluginGenerator = () => {
+    return {
+      id: `test${++counter}`,
+      index_url: `plugins/test${counter}/`,
+      version: '3.0-SNAPSHOT',
+      disabled: false,
+    };
+  };
+
+  suite('gr-admin-plugin-list tests', () => {
+    let element;
+    let plugins;
+    let sandbox;
+
+    setup(() => {
+      sandbox = sinon.sandbox.create();
+      element = fixture('basic');
+    });
+
+    teardown(() => {
+      sandbox.restore();
+    });
+
+    suite('list with plugins', () => {
+      setup(done => {
+        plugins = _.times(26, pluginGenerator);
+
+        stub('gr-rest-api-interface', {
+          getPlugins() {
+            return Promise.resolve(plugins);
+          },
+        });
+
+        flush(done);
+      });
+
+      test('test for a test plugin in the list', done => {
+        element._plugins = plugins;
+
+        flush(() => {
+          assert.equal(element._plugins[2].id, 'test3');
+          assert.equal(element._plugins[2].index_url, 'plugins/test3/');
+          assert.equal(element._plugins[2].version, '3.0-SNAPSHOT');
+          assert.equal(element._plugins[2].disabled, false);
+          done();
+        });
+      });
+    });
+  });
+</script>
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-project-list/gr-admin-project-list.html b/polygerrit-ui/app/elements/admin/gr-admin-project-list/gr-admin-project-list.html
index 8d1e1ca..05b30e2 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-project-list/gr-admin-project-list.html
+++ b/polygerrit-ui/app/elements/admin/gr-admin-project-list/gr-admin-project-list.html
@@ -47,7 +47,7 @@
             class$="[[computeLoadingClass(_loading)]]">
           <tr class="table">
             <td class="name">
-              <a href$="[[getUrl(path, item.name)]]">[[item.name]]</a>
+              <a href$="[[_computeProjectUrl(item.name)]]">[[item.name]]</a>
             </td>
             <td class="description">[[item.description]]</td>
             <td class="repositoryBrowser">
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-project-list/gr-admin-project-list.js b/polygerrit-ui/app/elements/admin/gr-admin-project-list/gr-admin-project-list.js
index 67629bb..41a4737 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-project-list/gr-admin-project-list.js
+++ b/polygerrit-ui/app/elements/admin/gr-admin-project-list/gr-admin-project-list.js
@@ -71,6 +71,10 @@
           this._offset);
     },
 
+    _computeProjectUrl(name) {
+      return this.getUrl(this._path, name);
+    },
+
     _getProjects(filter, projectsPerPage, offset) {
       this._projects = [];
       return this.$.restAPI.getProjects(filter, projectsPerPage, offset)
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 4087e41..b1f6ecf 100644
--- a/polygerrit-ui/app/elements/core/gr-router/gr-router.js
+++ b/polygerrit-ui/app/elements/core/gr-router/gr-router.js
@@ -182,6 +182,18 @@
       };
     });
 
+    page(/^\/admin\/plugins(\/)?$/, loadUser, data => {
+      restAPI.getLoggedIn().then(loggedIn => {
+        if (loggedIn) {
+          app.params = {
+            view: 'gr-admin-plugin-list',
+          };
+        } else {
+          page.redirect('/login/' + encodeURIComponent(data.canonicalPath));
+        }
+      });
+    });
+
     page('/admin/(.*)', loadUser, data => {
       restAPI.getLoggedIn().then(loggedIn => {
         if (loggedIn) {
diff --git a/polygerrit-ui/app/elements/gr-app.html b/polygerrit-ui/app/elements/gr-app.html
index 1160162..f70a16c 100644
--- a/polygerrit-ui/app/elements/gr-app.html
+++ b/polygerrit-ui/app/elements/gr-app.html
@@ -21,6 +21,7 @@
 <link rel="import" href="./admin/gr-admin-group-list/gr-admin-group-list.html">
 <link rel="import" href="./admin/gr-admin-project-list/gr-admin-project-list.html">
 <link rel="import" href="./admin/gr-admin-project/gr-admin-project.html">
+<link rel="import" href="./admin/gr-admin-plugin-list/gr-admin-plugin-list.html">
 <link rel="import" href="./admin/gr-admin-view/gr-admin-view.html">
 <link rel="import" href="./change-list/gr-change-list-view/gr-change-list-view.html">
 <link rel="import" href="./change-list/gr-dashboard-view/gr-dashboard-view.html">
@@ -154,6 +155,9 @@
       <template is="dom-if" if="[[_showAdminProject]]" restamp="true">
         <gr-admin-project project="[[params.project]]"></gr-admin-project>
       </template>
+      <template is="dom-if" if="[[_showPluginListView]]" restamp="true">
+        <gr-admin-plugin-list id="pluginList"></gr-admin-plugin-list>
+      </template>
       <template is="dom-if" if="[[_showAdminView]]" restamp="true">
         <gr-admin-view path="[[_path]]"></gr-admin-view>
       </template>
diff --git a/polygerrit-ui/app/elements/gr-app.js b/polygerrit-ui/app/elements/gr-app.js
index 7f63330..7011202 100644
--- a/polygerrit-ui/app/elements/gr-app.js
+++ b/polygerrit-ui/app/elements/gr-app.js
@@ -50,6 +50,7 @@
       _showSettingsView: Boolean,
       _showProjectListView: Boolean,
       _showAdminProject: Boolean,
+      _showPluginListView: Boolean,
       _showAdminView: Boolean,
       _showCLAView: Boolean,
       _viewState: Object,
@@ -141,6 +142,7 @@
       this.set('_showGroupListView', view === 'gr-admin-group-list');
       this.set('_showProjectListView', view === 'gr-admin-project-list');
       this.set('_showAdminProject', view === 'gr-admin-project');
+      this.set('_showPluginListView', view === 'gr-admin-plugin-list');
       this.set('_showAdminView', view === 'gr-admin-view');
       this.set('_showCLAView', view === 'gr-cla-view');
       if (this.params.justRegistered) {
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 4f89535..ae25a81 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
@@ -515,6 +515,10 @@
       );
     },
 
+    getPlugins() {
+      return this._fetchSharedCacheURL('/plugins/?all');
+    },
+
     getSuggestedGroups(inputVal, opt_n, opt_errFn, opt_ctx) {
       const params = {s: inputVal};
       if (opt_n) { params.n = opt_n; }
diff --git a/polygerrit-ui/app/test/index.html b/polygerrit-ui/app/test/index.html
index 8414e9f..f499389 100644
--- a/polygerrit-ui/app/test/index.html
+++ b/polygerrit-ui/app/test/index.html
@@ -31,6 +31,7 @@
     // beginning.
     'gr-app_test.html',
     'admin/gr-admin-group-list/gr-admin-group-list_test.html',
+    'admin/gr-admin-plugin-list/gr-admin-plugin-list_test.html',
     'admin/gr-admin-project/gr-admin-project_test.html',
     'admin/gr-admin-project-list/gr-admin-project-list_test.html',
     'change-list/gr-change-list-item/gr-change-list-item_test.html',