Add its-jira configuration to the new PolyGerrit UI

This change adds the missing configuration fields for its-jira for
Gerrit 2.16. The uploadvalidator plugin was used as an example to come
up with the new files which add the configuration to the new PolyGerrit
UI.

Feature: Issue 11319
Change-Id: I87c9da2838ac0ff0202a06b07a3dc446eafff25b
diff --git a/BUILD b/BUILD
index eca48a1..6f00197 100644
--- a/BUILD
+++ b/BUILD
@@ -5,6 +5,8 @@
     "PLUGIN_DEPS",
     "PLUGIN_TEST_DEPS",
 )
+load("//tools/bzl:genrule2.bzl", "genrule2")
+load("//tools/bzl:js.bzl", "polygerrit_plugin")
 
 gerrit_plugin(
     name = "its-jira",
@@ -17,12 +19,36 @@
         "Implementation-Title: Jira ITS Plugin",
         "Implementation-URL: http://www.gerritforge.com",
     ],
+    resource_jars = [":cs-its-jira-static"],
     resources = glob(["src/main/resources/**/*"]),
     deps = [
         "//plugins/its-base",
     ],
 )
 
+genrule2(
+    name = "cs-its-jira-static",
+    srcs = [
+        ":cs-its-jira-config",
+    ],
+    outs = ["cs-its-jira-static.jar"],
+    cmd = " && ".join([
+        "mkdir $$TMP/static",
+        "cp -r $(locations :cs-its-jira-config) $$TMP/static",
+        "cd $$TMP",
+        "zip -Drq $$ROOT/$@ -g .",
+    ]),
+)
+
+polygerrit_plugin(
+    name = "cs-its-jira-config",
+    srcs = glob([
+        "cs-its-jira-config/*.html",
+        "cs-its-jira-config/*.js",
+    ]),
+    app = "plugin-config.html",
+)
+
 junit_tests(
     name = "its_jira_tests",
     testonly = 1,
diff --git a/cs-its-jira-config/cs-its-jira-config.html b/cs-its-jira-config/cs-its-jira-config.html
new file mode 100644
index 0000000..c4f9f41
--- /dev/null
+++ b/cs-its-jira-config/cs-its-jira-config.html
@@ -0,0 +1,82 @@
+<!--
+@license
+Copyright (C) 2021 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.
+-->
+
+<dom-module id="cs-its-jira-config">
+  <template>
+    <style include="shared-styles"></style>
+    <style include="gr-form-styles"></style>
+    <fieldset class="gr-form-styles">
+      <h2 class="sectionTitle">its-jira plugin</h2>
+      <section>
+        <section>
+          <span class="title">Enable its-jira integration</span>
+          <span class="value">
+            <gr-select id="enabled"
+                       bind-value="{{_changedConfig.enabled.value}}"
+                       on-change="_handlePrefsChanged">
+              <select disabled$="[[readOnly]]">
+                <option value="true">true</option>
+                <option value="false">false</option>
+                <option value="enforced">enforced</option>
+              </select>
+            </gr-select>
+          </span>
+        </section>
+        <section>
+          <span class="title">Server URL</span>
+          <span class="value">
+            <iron-input bind-value="{{_changedConfig.instanceUrl.value}}">
+              <input id="instanceUrl"
+                     value="{{_changedConfig.instanceUrl.value::input}}"
+                     on-keypress="_handlePrefsChanged"
+                     on-change="_handlePrefsChanged"
+                     type="text">
+            </iron-input>
+          </span>
+        </section>
+        <section>
+          <span class="title">JIRA username</span>
+          <span class="value">
+            <iron-input bind-value="{{_changedConfig.username.value}}">
+              <input id="username"
+                     value="{{_changedConfig.username.value::input}}"
+                     on-keypress="_handlePrefsChanged"
+                     on-change="_handlePrefsChanged"
+                     type="text">
+            </iron-input>
+          </span>
+        </section>
+        <section>
+          <span class="title">JIRA password</span>
+          <span class="value">
+            <iron-input bind-value="{{_changedConfig.password.value}}">
+              <input id="password"
+                     value="{{_changedConfig.password.value::input}}"
+                     on-keypress="_handlePrefsChanged"
+                     on-change="_handlePrefsChanged"
+                     type="password">
+            </iron-input>
+          </span>
+        </section>
+        <gr-button
+            id="saveButton"
+            on-click="_handlePrefsSave"
+            disabled="[[!_prefsChanged]]">
+          Save Changes
+        </gr-button>
+      </section>
+    </fieldset>
+  </template>
+  <script src="cs-its-jira-config.js"></script>
+</dom-module>
diff --git a/cs-its-jira-config/cs-its-jira-config.js b/cs-its-jira-config/cs-its-jira-config.js
new file mode 100644
index 0000000..49b53b7
--- /dev/null
+++ b/cs-its-jira-config/cs-its-jira-config.js
@@ -0,0 +1,75 @@
+// Copyright (C) 2021 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: 'cs-its-jira-config',
+
+    properties: {
+      repoName: String,
+      readOnly: {
+        type: Boolean,
+        value: true,
+      },
+      _config: Object,
+      _changedConfig: Object,
+      _prefsChanged: {
+        type: Boolean,
+        value: false,
+      },
+      _projectRestApi: Object,
+    },
+
+    attached() {
+      this._projectRestApi = this.plugin.restApi('/projects/');
+      this._getPreferences().then(() => {
+        this._changedConfig = Object.assign({}, this._config);
+      })
+    },
+
+    _getPreferences() {
+      return this._projectRestApi.get(`${encodeURIComponent(this.repoName)}/config`)
+        .then(config => {
+          if (!config) {
+            return;
+          }
+          if (config.plugin_config && config.plugin_config["its-jira"]) {
+            this._config = config.plugin_config["its-jira"];
+          }
+        })
+    },
+
+    _handleListDataChanged(event) {
+      this._changedConfig[event.target.id] = { values: event.detail.allEntries };
+      this._handlePrefsChanged();
+    },
+
+    _handlePrefsChanged() {
+      this._prefsChanged = true;
+    },
+
+    _handlePrefsSave() {
+      let body = { plugin_config_values: {} };
+      body.plugin_config_values['its-jira'] = this._changedConfig;
+      this._projectRestApi.put(`${encodeURIComponent(this.repoName)}/config`, body)
+        .then(() => {
+          this._prefsChanged = false;
+        }).catch(response => {
+          this.fire('show-error', { message: response });
+        });
+    },
+  });
+})();
diff --git a/plugin-config.html b/plugin-config.html
new file mode 100644
index 0000000..22913ed
--- /dev/null
+++ b/plugin-config.html
@@ -0,0 +1,27 @@
+<!--
+Copyright (C) 2021 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="./cs-its-jira-config/cs-its-jira-config.html">
+
+<dom-module id="repo-its-jira-config">
+  <script>
+    if(window.Polymer) {
+      Gerrit.install(plugin => {
+        plugin.registerCustomComponent('repo-config', 'cs-its-jira-config');
+      });
+    }
+  </script>
+</dom-module>
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraModule.java b/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraModule.java
index 65026bc..94d631e 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/jira/JiraModule.java
@@ -20,6 +20,9 @@
 
 import com.google.gerrit.extensions.annotations.Exports;
 import com.google.gerrit.extensions.annotations.PluginName;
+import com.google.gerrit.extensions.registration.DynamicSet;
+import com.google.gerrit.extensions.webui.JavaScriptPlugin;
+import com.google.gerrit.extensions.webui.WebUiPlugin;
 import com.google.gerrit.lifecycle.LifecycleModule;
 import com.google.gerrit.server.config.PluginConfigFactory;
 import com.google.gerrit.server.config.ProjectConfigEntry;
@@ -61,6 +64,8 @@
     install(new ItsHookModule(pluginName, pluginCfgFactory));
     install(JiraItsServerCacheImpl.module());
     listener().to(JiraItsStartupHealthcheck.class);
+    DynamicSet.bind(binder(), WebUiPlugin.class)
+        .toInstance(new JavaScriptPlugin("cs-its-jira-config.html"));
 
     LOG.info("JIRA is configured as ITS");
   }