Skip to content

Commit

Permalink
Merge changes from topic "motd" into stable-2.16
Browse files Browse the repository at this point in the history
* changes:
  Document MessageOfTheDay extension
  Add UI element to display messages of the day
  Add MessageOfTheDay-entries to ServerInfo
  • Loading branch information
zivkov authored and Gerrit Code Review committed Feb 3, 2020
2 parents 15753c2 + cfff720 commit d4ba7fb
Show file tree
Hide file tree
Showing 10 changed files with 271 additions and 1 deletion.
34 changes: 34 additions & 0 deletions Documentation/dev-plugins.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
21 changes: 21 additions & 0 deletions Documentation/rest-api-config.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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` ||
Expand Down
27 changes: 27 additions & 0 deletions java/com/google/gerrit/extensions/common/MessageOfTheDayInfo.java
Original file line number Diff line number Diff line change
@@ -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;
}
2 changes: 2 additions & 0 deletions java/com/google/gerrit/extensions/common/ServerInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

package com.google.gerrit.extensions.common;

import java.util.List;
import java.util.Map;

public class ServerInfo {
Expand All @@ -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;
Expand Down
24 changes: 23 additions & 1 deletion java/com/google/gerrit/server/restapi/config/GetServerInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
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;
Expand All @@ -36,7 +37,9 @@
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;
Expand Down Expand Up @@ -69,6 +72,7 @@
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;
Expand Down Expand Up @@ -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(
Expand All @@ -123,7 +128,8 @@ public GetServerInfo(
AgreementJson agreementJson,
GerritOptions gerritOptions,
ChangeIndexCollection indexes,
SitePaths sitePaths) {
SitePaths sitePaths,
DynamicSet<MessageOfTheDay> motd) {
this.config = config;
this.accountVisibilityProvider = accountVisibilityProvider;
this.authConfig = authConfig;
Expand All @@ -145,6 +151,7 @@ public GetServerInfo(
this.gerritOptions = gerritOptions;
this.indexes = indexes;
this.sitePaths = sitePaths;
this.messages = motd;
}

@Override
Expand All @@ -155,6 +162,7 @@ public ServerInfo apply(ConfigResource rsrc) throws PermissionBackendException {
info.change = getChangeInfo();
info.download = getDownloadInfo();
info.gerrit = getGerritInfo();
info.messages = getMessages();
info.noteDbEnabled = toBoolean(isNoteDbEnabled());
info.plugin = getPluginInfo();
info.defaultTheme = getDefaultTheme();
Expand Down Expand Up @@ -325,6 +333,20 @@ private String getDocUrl() {
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();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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>
Original file line number Diff line number Diff line change
@@ -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';
},
});
})();
Original file line number Diff line number Diff line change
@@ -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>
7 changes: 7 additions & 0 deletions polygerrit-ui/app/elements/gr-app.html
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
<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">
Expand Down Expand Up @@ -158,6 +159,12 @@
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
Expand Down
4 changes: 4 additions & 0 deletions polygerrit-ui/app/elements/gr-app.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down

0 comments on commit d4ba7fb

Please sign in to comment.