diff options
author | Saša Živkov <zivkov@gmail.com> | 2020-02-03 14:15:54 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2020-02-03 14:15:54 +0000 |
commit | d4ba7fb691edf0a5ff4944be339dfe4941bcf5e3 (patch) | |
tree | a8bcf53712b2933575020cfb5ab4cb624acf58b6 | |
parent | 15753c282e9fcb44fa049788136505071a339ad5 (diff) | |
parent | cfff720610374fe538649f272a762569bb785998 (diff) |
Merge changes from topic "motd" into stable-2.16
* changes:
Document MessageOfTheDay extension
Add UI element to display messages of the day
Add MessageOfTheDay-entries to ServerInfo
10 files changed, 271 insertions, 1 deletions
diff --git a/Documentation/dev-plugins.txt b/Documentation/dev-plugins.txt index 974e3706ca..64cae2d5a6 100644 --- a/Documentation/dev-plugins.txt +++ b/Documentation/dev-plugins.txt @@ -2954,6 +2954,40 @@ to change in order to be compliant. These requirements should be kept once they are met, but marked as `OK`. If the requirements were not displayed, reviewers would need to use their precious time to manually check that they were met. +[[message-of-the-day]] +== Posting Messages (Of The Day) to the UI +Gerrit provides an extension point that enables plugins to implement a method to +collect messages that will then be shown below the main header in the Gerrit UI. + +[source, java] +---- +import com.google.gerrit.extensions.systemstatus.MessageOfTheDay; + +@Singleton +class MessageOfTheDayImpl extends MessageOfTheDay { + + private final String id; + private final String msg; + + public MessageOfTheDayImpl() { + id = "hello"; + msg = "I just wanted to say <b>hello</b>."; + } + + @Override + public String getHtmlMessage() { + return msg; + } + + @Override + public String getMessageId() { + return id; + } +} +---- + +Note, that the message will be added as HTML and parsed into the DOM. Thus, +plugins using this extension should ensure that the message content is safe. == SEE ALSO diff --git a/Documentation/rest-api-config.txt b/Documentation/rest-api-config.txt index 7be8c324b4..905c3ef830 100644 --- a/Documentation/rest-api-config.txt +++ b/Documentation/rest-api-config.txt @@ -1905,6 +1905,22 @@ The maximal memory size. The value is returned with a unit abbreviation The number of open files. |============================ +[[message-of-the-day-info]] +=== MessageOfTheDayInfo +The `MessageOfTheDayInfo` entity contains information about a message +that was registered with the +link:dev-plugins.html#message-of-the-day[MessageOfTheDay]-extension by plugins. + +[options="header",cols="1,^1,5"] +|=========================== +|Field Name ||Description +|`id` ||ID of the message. +|`redisplay` || +Date and Time, when the message should be displayed again after it was dismissed +by the user. +|`html` ||Message in HTML-format. +|=========================== + [[plugin-config-info]] === PluginConfigInfo The `PluginConfigInfo` entity contains information about Gerrit @@ -1958,6 +1974,11 @@ information about Gerrit Information about the configuration from the link:config-gerrit.html#gerrit[gerrit] section as link:#gerrit-info[ GerritInfo] entity. +|`messages` || +List of messages registered with the +link:dev-plugins.html#message-of-the-day[MessageOfTheDay]-extension +containing link:#message-of-the-day-info[ +MessageOfTheDayInfo] entities. |`note_db_enabled` |not set if `false`| Whether the NoteDb storage backend is fully enabled. |`plugin` || diff --git a/java/com/google/gerrit/extensions/common/MessageOfTheDayInfo.java b/java/com/google/gerrit/extensions/common/MessageOfTheDayInfo.java new file mode 100644 index 0000000000..f752f86a64 --- /dev/null +++ b/java/com/google/gerrit/extensions/common/MessageOfTheDayInfo.java @@ -0,0 +1,27 @@ +// Copyright (C) 2020 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. + +package com.google.gerrit.extensions.common; + +import java.util.Date; + +/** REST API representation of a "message of the day". */ +public class MessageOfTheDayInfo { + /** The ID of the message. */ + public String id; + /** The date and time the message will be displayed again after being dismissed by the user. */ + public Date redisplay; + /** The message in HTML-format. */ + public String html; +} diff --git a/java/com/google/gerrit/extensions/common/ServerInfo.java b/java/com/google/gerrit/extensions/common/ServerInfo.java index 8904f0a03b..27cf529a24 100644 --- a/java/com/google/gerrit/extensions/common/ServerInfo.java +++ b/java/com/google/gerrit/extensions/common/ServerInfo.java @@ -14,6 +14,7 @@ package com.google.gerrit.extensions.common; +import java.util.List; import java.util.Map; public class ServerInfo { @@ -22,6 +23,7 @@ public class ServerInfo { public ChangeConfigInfo change; public DownloadInfo download; public GerritInfo gerrit; + public List<MessageOfTheDayInfo> messages; public Boolean noteDbEnabled; public PluginConfigInfo plugin; public SshdInfo sshd; diff --git a/java/com/google/gerrit/server/restapi/config/GetServerInfo.java b/java/com/google/gerrit/server/restapi/config/GetServerInfo.java index eca26c34a5..04f4f8a824 100644 --- a/java/com/google/gerrit/server/restapi/config/GetServerInfo.java +++ b/java/com/google/gerrit/server/restapi/config/GetServerInfo.java @@ -27,6 +27,7 @@ import com.google.gerrit.extensions.common.ChangeConfigInfo; import com.google.gerrit.extensions.common.DownloadInfo; import com.google.gerrit.extensions.common.DownloadSchemeInfo; import com.google.gerrit.extensions.common.GerritInfo; +import com.google.gerrit.extensions.common.MessageOfTheDayInfo; import com.google.gerrit.extensions.common.PluginConfigInfo; import com.google.gerrit.extensions.common.ReceiveInfo; import com.google.gerrit.extensions.common.ServerInfo; @@ -36,7 +37,9 @@ import com.google.gerrit.extensions.common.UserConfigInfo; import com.google.gerrit.extensions.config.CloneCommand; import com.google.gerrit.extensions.config.DownloadCommand; import com.google.gerrit.extensions.config.DownloadScheme; +import com.google.gerrit.extensions.registration.DynamicSet; import com.google.gerrit.extensions.restapi.RestReadView; +import com.google.gerrit.extensions.systemstatus.MessageOfTheDay; import com.google.gerrit.extensions.webui.WebUiPlugin; import com.google.gerrit.server.EnableSignedPush; import com.google.gerrit.server.account.AccountVisibilityProvider; @@ -69,6 +72,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.EnumSet; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.TimeUnit; @@ -100,6 +104,7 @@ public class GetServerInfo implements RestReadView<ConfigResource> { private final GerritOptions gerritOptions; private final ChangeIndexCollection indexes; private final SitePaths sitePaths; + private final DynamicSet<MessageOfTheDay> messages; @Inject public GetServerInfo( @@ -123,7 +128,8 @@ public class GetServerInfo implements RestReadView<ConfigResource> { AgreementJson agreementJson, GerritOptions gerritOptions, ChangeIndexCollection indexes, - SitePaths sitePaths) { + SitePaths sitePaths, + DynamicSet<MessageOfTheDay> motd) { this.config = config; this.accountVisibilityProvider = accountVisibilityProvider; this.authConfig = authConfig; @@ -145,6 +151,7 @@ public class GetServerInfo implements RestReadView<ConfigResource> { this.gerritOptions = gerritOptions; this.indexes = indexes; this.sitePaths = sitePaths; + this.messages = motd; } @Override @@ -155,6 +162,7 @@ public class GetServerInfo implements RestReadView<ConfigResource> { info.change = getChangeInfo(); info.download = getDownloadInfo(); info.gerrit = getGerritInfo(); + info.messages = getMessages(); info.noteDbEnabled = toBoolean(isNoteDbEnabled()); info.plugin = getPluginInfo(); info.defaultTheme = getDefaultTheme(); @@ -325,6 +333,20 @@ public class GetServerInfo implements RestReadView<ConfigResource> { return CharMatcher.is('/').trimTrailingFrom(docUrl) + '/'; } + private List<MessageOfTheDayInfo> getMessages() { + return this.messages.stream() + .filter(motd -> !Strings.isNullOrEmpty(motd.getHtmlMessage())) + .map( + motd -> { + MessageOfTheDayInfo m = new MessageOfTheDayInfo(); + m.id = motd.getMessageId(); + m.redisplay = motd.getRedisplay(); + m.html = motd.getHtmlMessage(); + return m; + }) + .collect(toList()); + } + private boolean isNoteDbEnabled() { return migration.readChanges(); } diff --git a/polygerrit-ui/app/elements/core/gr-message-header/gr-message-header.html b/polygerrit-ui/app/elements/core/gr-message-header/gr-message-header.html new file mode 100644 index 0000000000..b2b382ca50 --- /dev/null +++ b/polygerrit-ui/app/elements/core/gr-message-header/gr-message-header.html @@ -0,0 +1,41 @@ +<!-- +@license +Copyright (C) 2020 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-button/gr-button.html"> + +<dom-module id="gr-message-header"> + <template> + <style include="shared-styles"> + #container { + background-color: lightyellow; + display: flex; + height: fit-content; + justify-content: space-between; + padding: 1em; + } + </style> + <div id="container" hidden$="[[_hidden]]"> + <div id="message"></div> + <gr-button id="dismissMessageBtn" + link + on-tap="_handleDismissMessage">Dismiss</gr-button> + </div> + <gr-rest-api-interface id="restAPI"></gr-rest-api-interface> + </template> + <script src="../../../scripts/util.js"></script> + <script src="gr-message-header.js"></script> +</dom-module> diff --git a/polygerrit-ui/app/elements/core/gr-message-header/gr-message-header.js b/polygerrit-ui/app/elements/core/gr-message-header/gr-message-header.js new file mode 100644 index 0000000000..fac4a6a399 --- /dev/null +++ b/polygerrit-ui/app/elements/core/gr-message-header/gr-message-header.js @@ -0,0 +1,52 @@ +/** + * @license + * Copyright (C) 2020 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-message-header', + + properties: { + message: { + type: Object, + reflectToAttribute: true, + }, + _hidden: { + type: Boolean, + value: true, + }, + }, + + attached() { + if (!this.message || !this.message.html) { + return; + } + this._isHidden(); + this.$.message.innerHTML = this.message.html; + }, + + _handleDismissMessage() { + document.cookie = + `msg-${this.message.id}=1; expires=${this.message.redisplay}`; + this._hidden = true; + }, + + _isHidden() { + this._hidden = window.util.getCookie(`msg-${this.message.id}`) === '1'; + }, + }); +})(); diff --git a/polygerrit-ui/app/elements/core/gr-message-header/gr-message-header_test.html b/polygerrit-ui/app/elements/core/gr-message-header/gr-message-header_test.html new file mode 100644 index 0000000000..c275e55345 --- /dev/null +++ b/polygerrit-ui/app/elements/core/gr-message-header/gr-message-header_test.html @@ -0,0 +1,60 @@ +<!DOCTYPE html> +<!-- +@license +Copyright (C) 2020 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-message-header</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="../../../test/common-test-setup.html"/> +<link rel="import" href="gr-message-header.html"> + +<script>void(0);</script> + +<test-fixture id="basic"> + <template> + <gr-message-header></gr-message-header> + </template> +</test-fixture> + +<script> + suite('gr-message-header tests', () => { + let element; + + setup(() => { + element = fixture('basic'); + }); + + test('show message', () => { + element.message = {html: 'This is a test message.'}; + element.attached(); + assert.equal(element.$.message.innerHTML, element.message.html); + }); + + test('hide message on dismiss', () => { + element.message = {html: 'This is a test message.', id: 'test'}; + element.attached(); + MockInteractions.tap(element.$.dismissMessageBtn); + assert.isTrue(element.$.container.hidden); + assert.isTrue(document.cookie.includes('msg-test=1')); + + element.attached(); + assert.isTrue(element.$.container.hidden); + }); + }); +</script> diff --git a/polygerrit-ui/app/elements/gr-app.html b/polygerrit-ui/app/elements/gr-app.html index 3a9719d5b9..4fff9e6221 100644 --- a/polygerrit-ui/app/elements/gr-app.html +++ b/polygerrit-ui/app/elements/gr-app.html @@ -55,6 +55,7 @@ limitations under the License. <link rel="import" href="./core/gr-error-manager/gr-error-manager.html"> <link rel="import" href="./core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.html"> <link rel="import" href="./core/gr-main-header/gr-main-header.html"> +<link rel="import" href="./core/gr-message-header/gr-message-header.html"> <link rel="import" href="./core/gr-navigation/gr-navigation.html"> <link rel="import" href="./core/gr-reporting/gr-reporting.html"> <link rel="import" href="./core/gr-router/gr-router.html"> @@ -158,6 +159,12 @@ limitations under the License. class$="[[_computeShadowClass(_isShadowDom)]]"> </gr-main-header> </gr-fixed-panel> + <template + is="dom-repeat" + items="[[_getMessages(_serverConfig)]]" + as="message"> + <gr-message-header message="{{message}}"></gr-message-header> + </template> <main> <template is="dom-if" if="[[_showChangeListView]]" restamp="true"> <gr-change-list-view diff --git a/polygerrit-ui/app/elements/gr-app.js b/polygerrit-ui/app/elements/gr-app.js index f48951bd53..ea7e86dc0b 100644 --- a/polygerrit-ui/app/elements/gr-app.js +++ b/polygerrit-ui/app/elements/gr-app.js @@ -339,6 +339,10 @@ config.gerrit.web_uis && config.gerrit.web_uis.includes('GWT'); }, + _getMessages(config) { + return config.messages ? config.messages : []; + }, + _handlePageError(e) { const props = [ '_showChangeListView', |