Expose reply dialog and label score value to plugins.
Provides sample plugin that sets Code-Review+1 on entering LGTM into reply dialog. Adds a getLabelValue(labelName) to plugin.changeReply(). Adds support for plugin dom hooks in general, and for reply dialog text area as a first instance. Adds plugin.changeReply().addReplyTextChangedCallback() which uses dom plugin hook. Feature: Issue 6280 Change-Id: I2b8d52c0d8000ea5d217268f6e6d7ef4137b2213
This commit is contained in:
@@ -14,12 +14,13 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<link rel="import" href="../../../bower_components/polymer/polymer.html">
|
||||
<link rel="import" href="../../../behaviors/base-url-behavior/base-url-behavior.html">
|
||||
<link rel="import" href="../../../behaviors/gr-patch-set-behavior/gr-patch-set-behavior.html">
|
||||
<link rel="import" href="../../../behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.html">
|
||||
<link rel="import" href="../../../behaviors/rest-client-behavior/rest-client-behavior.html">
|
||||
<link rel="import" href="../../../bower_components/polymer/polymer.html">
|
||||
<link rel="import" href="../../../bower_components/iron-autogrow-textarea/iron-autogrow-textarea.html">
|
||||
<link rel="import" href="../../plugins/gr-endpoint-decorator/gr-endpoint-decorator.html">
|
||||
<link rel="import" href="../../shared/gr-account-chip/gr-account-chip.html">
|
||||
<link rel="import" href="../../shared/gr-button/gr-button.html">
|
||||
<link rel="import" href="../../shared/gr-formatted-text/gr-formatted-text.html">
|
||||
@@ -95,6 +96,9 @@ limitations under the License.
|
||||
min-height: 6em;
|
||||
position: relative;
|
||||
}
|
||||
.textareaContainer > * {
|
||||
flex: 1;
|
||||
}
|
||||
iron-autogrow-textarea {
|
||||
padding: 0;
|
||||
font-family: var(--monospace-font-family);
|
||||
@@ -202,17 +206,19 @@ limitations under the License.
|
||||
</gr-overlay>
|
||||
</section>
|
||||
<section class="textareaContainer">
|
||||
<iron-autogrow-textarea
|
||||
id="textarea"
|
||||
class="message"
|
||||
autocomplete="on"
|
||||
placeholder=[[_messagePlaceholder]]
|
||||
disabled="{{disabled}}"
|
||||
rows="4"
|
||||
max-rows="15"
|
||||
bind-value="{{draft}}"
|
||||
on-bind-value-changed="_handleHeightChanged">
|
||||
</iron-autogrow-textarea>
|
||||
<gr-endpoint-decorator name="reply-text">
|
||||
<iron-autogrow-textarea
|
||||
id="textarea"
|
||||
class="message"
|
||||
autocomplete="on"
|
||||
placeholder=[[_messagePlaceholder]]
|
||||
disabled="{{disabled}}"
|
||||
rows="4"
|
||||
max-rows="15"
|
||||
bind-value="{{draft}}"
|
||||
on-bind-value-changed="_handleHeightChanged">
|
||||
</iron-autogrow-textarea>
|
||||
</gr-endpoint-decorator>
|
||||
</section>
|
||||
<section class="previewContainer">
|
||||
<label>
|
||||
|
@@ -198,14 +198,24 @@
|
||||
|
||||
setLabelValue(label, value) {
|
||||
const selectorEl =
|
||||
this.$.labelScores.$$('iron-selector[data-label="' + label + '"]');
|
||||
this.$.labelScores.$$(`iron-selector[data-label="${label}"]`);
|
||||
// The selector may not be present if it’s not at the latest patch set.
|
||||
if (!selectorEl) { return; }
|
||||
const item = selectorEl.$$('gr-button[data-value="' + value + '"]');
|
||||
const item = selectorEl.$$(`gr-button[data-value="${value}"]`);
|
||||
if (!item) { return; }
|
||||
selectorEl.selectIndex(selectorEl.indexOf(item));
|
||||
},
|
||||
|
||||
getLabelValue(label) {
|
||||
const selectorEl =
|
||||
this.$.labelScores.$$(`iron-selector[data-label="${label}"]`);
|
||||
// The selector may not be present if it’s not at the latest patch set.
|
||||
if (!selectorEl) { return null; }
|
||||
const item = selectorEl.querySelector('gr-button.iron-selected');
|
||||
if (!item) { return null; }
|
||||
return item.getAttribute('data-value');
|
||||
},
|
||||
|
||||
_handleEscKey(e) {
|
||||
this.cancel();
|
||||
},
|
||||
|
@@ -211,6 +211,26 @@ limitations under the License.
|
||||
});
|
||||
});
|
||||
|
||||
test('getlabelValue returns value', done => {
|
||||
flush(() => {
|
||||
MockInteractions.tap(element.$$('gr-label-scores').$$(
|
||||
'iron-selector[data-label="Verified"] > ' +
|
||||
'gr-button[data-value="-1"]'));
|
||||
assert.equal('-1', element.getLabelValue('Verified'));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('getlabelValue when no score is selected', done => {
|
||||
flush(() => {
|
||||
MockInteractions.tap(element.$$('gr-label-scores').$$(
|
||||
'iron-selector[data-label="Code-Review"] > ' +
|
||||
'gr-button[data-value="-1"]'));
|
||||
assert.isNull(element.getLabelValue('Verified'));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('setlabelValue', () => {
|
||||
element._account = {_account_id: 1};
|
||||
flushAsynchronousOperations();
|
||||
|
@@ -0,0 +1,25 @@
|
||||
<!--
|
||||
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="../../../bower_components/polymer/polymer.html">
|
||||
<link rel="import" href="../../shared/gr-js-api-interface/gr-js-api-interface.html">
|
||||
|
||||
<dom-module id="gr-endpoint-decorator">
|
||||
<template>
|
||||
<content></content>
|
||||
</template>
|
||||
<script src="gr-endpoint-decorator.js"></script>
|
||||
</dom-module>
|
@@ -0,0 +1,49 @@
|
||||
// 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-endpoint-decorator',
|
||||
|
||||
properties: {
|
||||
name: String,
|
||||
},
|
||||
|
||||
_import(url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.importHref(url, resolve, reject);
|
||||
});
|
||||
},
|
||||
|
||||
_initPluginDomHook(name, plugin) {
|
||||
const el = document.createElement(name);
|
||||
el.plugin = plugin;
|
||||
el.content = this.getContentChildren()[0];
|
||||
return Polymer.dom(this.root).appendChild(el);
|
||||
},
|
||||
|
||||
ready() {
|
||||
Gerrit.awaitPluginsLoaded().then(() => Promise.all(
|
||||
Gerrit._getPluginsForEndpoint(this.name).map(
|
||||
pluginUrl => this._import(pluginUrl)))
|
||||
).then(() => {
|
||||
const modulesData = Gerrit._getEndpointDetails(this.name);
|
||||
for (const {moduleName, plugin} of modulesData) {
|
||||
this._initPluginDomHook(moduleName, plugin);
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
})();
|
@@ -0,0 +1,71 @@
|
||||
<!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-endpoint-decorator</title>
|
||||
|
||||
<script src="../../../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
|
||||
<script src="../../../bower_components/web-component-tester/browser.js"></script>
|
||||
|
||||
<link rel="import" href="../../../bower_components/iron-test-helpers/iron-test-helpers.html">
|
||||
<link rel="import" href="gr-endpoint-decorator.html">
|
||||
|
||||
<test-fixture id="basic">
|
||||
<template>
|
||||
<gr-endpoint-decorator name="foo"></gr-endpoint-decorator>
|
||||
</template>
|
||||
</test-fixture>
|
||||
|
||||
<script>
|
||||
suite('gr-endpoint-decorator', () => {
|
||||
let sandbox;
|
||||
let element;
|
||||
let plugin;
|
||||
|
||||
setup(done => {
|
||||
sandbox = sinon.sandbox.create();
|
||||
|
||||
// NB: Order is important.
|
||||
Gerrit.install(p => {
|
||||
plugin = p;
|
||||
plugin.registerCustomComponent('foo', 'some-module');
|
||||
}, '0.1', 'http://some/plugin/url.html');
|
||||
|
||||
sandbox.stub(Gerrit, 'awaitPluginsLoaded').returns(Promise.resolve());
|
||||
|
||||
element = fixture('basic');
|
||||
sandbox.stub(element, '_initPluginDomHook');
|
||||
sandbox.stub(element, 'importHref', (url, resolve) => { resolve(); });
|
||||
|
||||
flush(done);
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
test('imports plugin-provided module', () => {
|
||||
assert.isTrue(
|
||||
element.importHref.calledWith(new URL('http://some/plugin/url.html')));
|
||||
});
|
||||
|
||||
test('inits plugin-provided dom hook', () => {
|
||||
assert.isTrue(
|
||||
element._initPluginDomHook.calledWith('some-module', plugin));
|
||||
});
|
||||
});
|
||||
</script>
|
@@ -34,24 +34,13 @@
|
||||
},
|
||||
|
||||
ready() {
|
||||
Gerrit.awaitPluginsLoaded().then(() => {
|
||||
const sharedStyles = Gerrit._styleModules[this.name];
|
||||
if (sharedStyles) {
|
||||
const pluginUrls = [];
|
||||
const moduleNames = [];
|
||||
sharedStyles.reduce((result, item) => {
|
||||
if (!result.pluginUrls.includes(item.pluginUrl)) {
|
||||
result.pluginUrls.push(item.pluginUrl);
|
||||
}
|
||||
result.moduleNames.push(item.moduleName);
|
||||
return result;
|
||||
}, {pluginUrls, moduleNames});
|
||||
Promise.all(pluginUrls.map(this._import.bind(this)))
|
||||
.then(() => {
|
||||
for (const name of moduleNames) {
|
||||
this._applyStyle(name);
|
||||
}
|
||||
});
|
||||
Gerrit.awaitPluginsLoaded().then(() => Promise.all(
|
||||
Gerrit._getPluginsForEndpoint(this.name).map(
|
||||
pluginUrl => this._import(pluginUrl)))
|
||||
).then(() => {
|
||||
const moduleNames = Gerrit._getModulesForEndoint(this.name);
|
||||
for (const name of moduleNames) {
|
||||
this._applyStyle(name);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
@@ -31,18 +31,26 @@ limitations under the License.
|
||||
</test-fixture>
|
||||
|
||||
<script>
|
||||
suite('gr-change-metadata integration tests', () => {
|
||||
suite('gr-external-style integration tests', () => {
|
||||
let sandbox;
|
||||
let element;
|
||||
|
||||
setup(done => {
|
||||
sandbox = sinon.sandbox.create();
|
||||
|
||||
// NB: Order is important.
|
||||
let plugin;
|
||||
Gerrit.install(p => {
|
||||
plugin = p;
|
||||
plugin.registerStyleModule('foo', 'some-module');
|
||||
}, '0.1', 'http://some/plugin/url.html');
|
||||
|
||||
sandbox.stub(Gerrit, 'awaitPluginsLoaded').returns(Promise.resolve());
|
||||
Gerrit._styleModules = {foo: [{pluginUrl: 'bar', moduleName: 'baz'}]};
|
||||
|
||||
element = fixture('basic');
|
||||
sandbox.stub(element, '_applyStyle');
|
||||
sandbox.stub(element, 'importHref', (url, resolve) => { resolve(); });
|
||||
|
||||
flush(done);
|
||||
});
|
||||
|
||||
@@ -51,11 +59,12 @@ limitations under the License.
|
||||
});
|
||||
|
||||
test('imports plugin-provided module', () => {
|
||||
assert.isTrue(element.importHref.calledWith('bar'));
|
||||
assert.isTrue(element.importHref.calledWith(
|
||||
new URL('http://some/plugin/url.html')));
|
||||
});
|
||||
|
||||
test('applies plugin-provided styles', () => {
|
||||
assert.isTrue(element._applyStyle.calledWith('baz'));
|
||||
assert.isTrue(element._applyStyle.calledWith('some-module'));
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
@@ -14,17 +14,44 @@
|
||||
(function(window) {
|
||||
'use strict';
|
||||
|
||||
function GrChangeReplyInterface(el) {
|
||||
this._el = el;
|
||||
/**
|
||||
* Don't add new API methods to GrChangeReplyInterfaceOld.
|
||||
* All new API should be added to GrChangeReplyInterface.
|
||||
* @deprecated
|
||||
*/
|
||||
class GrChangeReplyInterfaceOld {
|
||||
constructor(el) {
|
||||
this._el = el;
|
||||
}
|
||||
|
||||
getLabelValue(label) {
|
||||
return this._el.getLabelValue(label);
|
||||
}
|
||||
|
||||
setLabelValue(label, value) {
|
||||
this._el.setLabelValue(label, value);
|
||||
}
|
||||
|
||||
send(opt_includeComments) {
|
||||
return this._el.send(opt_includeComments);
|
||||
}
|
||||
}
|
||||
|
||||
GrChangeReplyInterface.prototype.setLabelValue = function(label, value) {
|
||||
this._el.setLabelValue(label, value);
|
||||
};
|
||||
class GrChangeReplyInterface extends GrChangeReplyInterfaceOld {
|
||||
constructor(plugin, el) {
|
||||
super(el);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
GrChangeReplyInterface.prototype.send = function(opt_includeComments) {
|
||||
return this._el.send(opt_includeComments);
|
||||
};
|
||||
addReplyTextChangedCallback(handler) {
|
||||
this.plugin.getDomHook('reply-text').then(el => {
|
||||
if (!el.content) { return; }
|
||||
el.content.addEventListener('value-changed', e => {
|
||||
handler(e.detail.value);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
window.GrChangeReplyInterface = GrChangeReplyInterface;
|
||||
})(window);
|
||||
|
@@ -23,9 +23,9 @@ limitations under the License.
|
||||
|
||||
<link rel="import" href="../../../bower_components/iron-test-helpers/iron-test-helpers.html">
|
||||
<!--
|
||||
This must refer to the element this interface is wrapping around. Otherwise
|
||||
breaking changes to gr-reply-dialog won’t be noticed.
|
||||
-->
|
||||
This must refer to the element this interface is wrapping around. Otherwise
|
||||
breaking changes to gr-reply-dialog won’t be noticed.
|
||||
-->
|
||||
<link rel="import" href="../../change/gr-reply-dialog/gr-reply-dialog.html">
|
||||
|
||||
<script>void(0);</script>
|
||||
@@ -61,13 +61,17 @@ limitations under the License.
|
||||
});
|
||||
|
||||
test('calls', () => {
|
||||
const setLabelValueStub = sinon.stub(element, 'setLabelValue');
|
||||
changeReply.setLabelValue('My-Label', '+1337');
|
||||
assert(setLabelValueStub.calledWithExactly('My-Label', '+1337'));
|
||||
sandbox.stub(element, 'getLabelValue').returns('+123');
|
||||
assert.equal(changeReply.getLabelValue('My-Label'), '+123');
|
||||
|
||||
const sendStub = sinon.stub(element, 'send');
|
||||
sandbox.stub(element, 'setLabelValue');
|
||||
changeReply.setLabelValue('My-Label', '+1337');
|
||||
assert.isTrue(
|
||||
element.setLabelValue.calledWithExactly('My-Label', '+1337'));
|
||||
|
||||
sandbox.stub(element, 'send');
|
||||
changeReply.send(false);
|
||||
assert(sendStub.calledWithExactly(false));
|
||||
assert.isTrue(element.send.calledWithExactly(false));
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
@@ -34,6 +34,11 @@
|
||||
|
||||
const API_VERSION = '0.1';
|
||||
|
||||
const EndpointType = {
|
||||
STYLE: 'style',
|
||||
DOM_DECORATION: 'dom',
|
||||
};
|
||||
|
||||
// GWT JSNI uses $wnd to refer to window.
|
||||
// http://www.gwtproject.org/doc/latest/DevGuideCodingBasicsJSNI.html
|
||||
window.$wnd = window;
|
||||
@@ -52,6 +57,8 @@
|
||||
return;
|
||||
}
|
||||
this._name = this._url.pathname.split('/')[2];
|
||||
this._generatedHookNames = [];
|
||||
this._hooks = [];
|
||||
}
|
||||
|
||||
Plugin._sharedAPIElement = document.createElement('gr-js-api-interface');
|
||||
@@ -62,14 +69,27 @@
|
||||
return this._name;
|
||||
};
|
||||
|
||||
Plugin.prototype.registerStyleModule = function(stylingEndpointName,
|
||||
moduleName) {
|
||||
if (!Gerrit._styleModules[stylingEndpointName]) {
|
||||
Gerrit._styleModules[stylingEndpointName] = [];
|
||||
Plugin.prototype.registerStyleModule = function(endpointName, moduleName) {
|
||||
this._registerEndpointModule(
|
||||
endpointName, EndpointType.STYLE, moduleName);
|
||||
};
|
||||
|
||||
Plugin.prototype.registerCustomComponent =
|
||||
function(endpointName, moduleName) {
|
||||
this._registerEndpointModule(
|
||||
endpointName, EndpointType.DOM_DECORATION, moduleName);
|
||||
};
|
||||
|
||||
Plugin.prototype._registerEndpointModule = function(endpoint, type, module) {
|
||||
const endpoints = Gerrit._endpoints;
|
||||
if (!endpoints[endpoint]) {
|
||||
endpoints[endpoint] = [];
|
||||
}
|
||||
Gerrit._styleModules[stylingEndpointName].push({
|
||||
endpoints[endpoint].push({
|
||||
moduleName: module,
|
||||
plugin: this,
|
||||
pluginUrl: this._url,
|
||||
moduleName,
|
||||
type,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -105,8 +125,37 @@
|
||||
};
|
||||
|
||||
Plugin.prototype.changeReply = function() {
|
||||
return new GrChangeReplyInterface(Plugin._sharedAPIElement.getElement(
|
||||
Plugin._sharedAPIElement.Element.REPLY_DIALOG));
|
||||
return new GrChangeReplyInterface(this,
|
||||
Plugin._sharedAPIElement.getElement(
|
||||
Plugin._sharedAPIElement.Element.REPLY_DIALOG));
|
||||
};
|
||||
|
||||
Plugin.prototype._getGeneratedHookName = function(endpointName) {
|
||||
if (!this._generatedHookNames[endpointName]) {
|
||||
this._generatedHookNames[endpointName] = this.getPluginName() +
|
||||
'-autogenerated-' + endpointName;
|
||||
}
|
||||
return this._generatedHookNames[endpointName];
|
||||
};
|
||||
|
||||
Plugin.prototype.getDomHook = function(endpointName) {
|
||||
const hookName = this._getGeneratedHookName(endpointName);
|
||||
if (!this._hooks[hookName]) {
|
||||
this._hooks[hookName] = new Promise((resolve, reject) => {
|
||||
Polymer({
|
||||
is: hookName,
|
||||
properties: {
|
||||
plugin: Object,
|
||||
content: Object,
|
||||
},
|
||||
attached() {
|
||||
resolve(this);
|
||||
},
|
||||
});
|
||||
this.registerCustomComponent(endpointName, hookName);
|
||||
});
|
||||
}
|
||||
return this._hooks[hookName];
|
||||
};
|
||||
|
||||
const Gerrit = window.Gerrit || {};
|
||||
@@ -114,8 +163,8 @@
|
||||
// Number of plugins to initialize, -1 means 'not yet known'.
|
||||
Gerrit._pluginsPending = -1;
|
||||
|
||||
// Hash of style modules to be applied, insertion point to shared style name.
|
||||
Gerrit._styleModules = {};
|
||||
// Hash of custom components to be instantiated for extension endpoints.
|
||||
Gerrit._endpoints = {};
|
||||
|
||||
Gerrit.getPluginName = function() {
|
||||
console.warn('Gerrit.getPluginName is not supported in PolyGerrit.',
|
||||
@@ -204,5 +253,67 @@
|
||||
return Gerrit._pluginsPending === 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get detailed information about modules registered with an extension
|
||||
* endpoint.
|
||||
* @param {string} name Endpoint name.
|
||||
* @param {?{
|
||||
* type: (string|undefined),
|
||||
* moduleName: (string|undefined)
|
||||
* }} opt_options
|
||||
* @return {{
|
||||
* moduleName: string,
|
||||
* plugin: Plugin,
|
||||
* pluginUrl: String,
|
||||
* type: EndpointType,
|
||||
* }}
|
||||
*/
|
||||
Gerrit._getEndpointDetails = function(name, opt_options) {
|
||||
const type = opt_options && opt_options.type;
|
||||
const moduleName = opt_options && opt_options.moduleName;
|
||||
if (!Gerrit._endpoints[name]) {
|
||||
return [];
|
||||
}
|
||||
return Gerrit._endpoints[name]
|
||||
.filter(item => (!type || item.type === type) &&
|
||||
(!moduleName || moduleName == item.moduleName));
|
||||
};
|
||||
|
||||
/**
|
||||
* Get detailed module names for instantiating at the endpoint
|
||||
* @param {string} name Endpoint name.
|
||||
* @param {?{
|
||||
* type: (string|undefined),
|
||||
* moduleName: (string|undefined)
|
||||
* }} opt_options
|
||||
* @return {!Array<string>}
|
||||
*/
|
||||
Gerrit._getModulesForEndoint = function(name, opt_options) {
|
||||
const modulesData = Gerrit._getEndpointDetails(name, opt_options);
|
||||
if (!modulesData.length) {
|
||||
return [];
|
||||
}
|
||||
return modulesData.map(m => m.moduleName);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get .html plugin URLs with element and module definitions.
|
||||
* @param {string} name Endpoint name.
|
||||
* @param {?{
|
||||
* type: (string|undefined),
|
||||
* moduleName: (string|undefined)
|
||||
* }} opt_options
|
||||
* @return {!Array<!URL>}
|
||||
*/
|
||||
Gerrit._getPluginsForEndpoint = function(name, opt_options) {
|
||||
const modulesData =
|
||||
Gerrit._getEndpointDetails(name, opt_options).filter(
|
||||
data => data.pluginUrl.pathname.indexOf('.html') !== -1);
|
||||
if (!modulesData.length) {
|
||||
return [];
|
||||
}
|
||||
return Array.from(new Set(modulesData.map(m => m.pluginUrl)));
|
||||
};
|
||||
|
||||
window.Gerrit = Gerrit;
|
||||
})(window);
|
||||
|
16
polygerrit-ui/app/samples/lgtm-plugin.html
Normal file
16
polygerrit-ui/app/samples/lgtm-plugin.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<dom-module id="lgtm-plugin">
|
||||
<script>
|
||||
Gerrit.install(plugin => {
|
||||
const replyApi = plugin.changeReply();
|
||||
replyApi.addReplyTextChangedCallback(text => {
|
||||
const label = 'Code-Review';
|
||||
const labelValue = replyApi.getLabelValue(label);
|
||||
if (labelValue &&
|
||||
labelValue === ' 0' &&
|
||||
text.indexOf('LGTM') === 0) {
|
||||
replyApi.setLabelValue(label, '+1');
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</dom-module>
|
Reference in New Issue
Block a user