Add MessageOfTheDay extension point for plugins
Allow plugins to contribute messages to the UI during initial page load. Gerrit displays the messages in a butter bar at the top of the page and allows users to hide them with the "Dismiss" button. Messages are hidden per-browser using a cookie named after the message id, set to expire at a date supplied by the server. After this date the same message could redisplay if the server sends the same message again. Change-Id: I0bcca845f501cbeb8c31356fff398c3adb43099a
This commit is contained in:
parent
17bb675699
commit
dfbe6d6ead
@ -17,6 +17,7 @@ package com.google.gerrit.common.data;
|
||||
import com.google.gerrit.reviewdb.client.Account;
|
||||
import com.google.gerrit.reviewdb.client.AccountDiffPreference;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/** Data sent as part of the host page, to bootstrap the UI. */
|
||||
@ -28,6 +29,7 @@ public class HostPageData {
|
||||
public GerritConfig config;
|
||||
public Theme theme;
|
||||
public List<String> plugins;
|
||||
public List<Message> messages;
|
||||
|
||||
public static class Theme {
|
||||
public String backgroundColor;
|
||||
@ -39,4 +41,10 @@ public class HostPageData {
|
||||
public String tableOddRowColor;
|
||||
public String tableEvenRowColor;
|
||||
}
|
||||
|
||||
public static class Message {
|
||||
public String id;
|
||||
public Date redisplay;
|
||||
public String html;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,69 @@
|
||||
// Copyright (C) 2014 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.systemstatus;
|
||||
|
||||
import com.google.gerrit.extensions.annotations.ExtensionPoint;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* Supplies a message of the day when the page is first loaded.
|
||||
*
|
||||
* <pre>
|
||||
* DynamicSet.bind(binder(), MessageOfTheDay.class).to(MyMessage.class);
|
||||
* </pre>
|
||||
*/
|
||||
@ExtensionPoint
|
||||
public abstract class MessageOfTheDay {
|
||||
/**
|
||||
* Retrieve the message of the day as an HTML fragment.
|
||||
*
|
||||
* @return message as an HTML fragment; null if no message is available.
|
||||
*/
|
||||
public abstract String getHtmlMessage();
|
||||
|
||||
/**
|
||||
* Unique identifier for this message.
|
||||
* <p>
|
||||
* Messages with the same identifier will be hidden from the user until
|
||||
* redisplay has occurred.
|
||||
* </p>
|
||||
*
|
||||
* @return unique message identifier. This identifier should be unique within
|
||||
* the server.
|
||||
*/
|
||||
public abstract String getMessageId();
|
||||
|
||||
/**
|
||||
* When should the message be displayed?
|
||||
*
|
||||
* <p>
|
||||
* Default implementation returns {@code tomorrow at 00:00:00 GMT}.
|
||||
* </p>
|
||||
*
|
||||
* @return a future date after which the message should be redisplayed.
|
||||
*/
|
||||
public Date getRedisplay() {
|
||||
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
|
||||
cal.set(Calendar.HOUR_OF_DAY, 0);
|
||||
cal.set(Calendar.MINUTE, 0);
|
||||
cal.set(Calendar.SECOND, 0);
|
||||
cal.set(Calendar.MILLISECOND, 0);
|
||||
cal.add(Calendar.DAY_OF_MONTH, 1);
|
||||
return cal.getTime();
|
||||
}
|
||||
}
|
@ -565,6 +565,9 @@ public class Gerrit implements EntryPoint {
|
||||
}
|
||||
|
||||
saveDefaultTheme();
|
||||
if (hpd.messages != null) {
|
||||
new MessageOfTheDayBar(hpd.messages).show();
|
||||
}
|
||||
PluginLoader.load(hpd.plugins, token);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,89 @@
|
||||
// Copyright (C) 2014 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.client;
|
||||
|
||||
import com.google.gerrit.common.data.HostPageData;
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.uibinder.client.UiBinder;
|
||||
import com.google.gwt.uibinder.client.UiField;
|
||||
import com.google.gwt.uibinder.client.UiHandler;
|
||||
import com.google.gwt.user.client.Cookies;
|
||||
import com.google.gwt.user.client.ui.Anchor;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.HTML;
|
||||
import com.google.gwt.user.client.ui.HTMLPanel;
|
||||
import com.google.gwt.user.client.ui.RootPanel;
|
||||
import com.google.gwtexpui.safehtml.client.SafeHtml;
|
||||
import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/** Displays pending messages from the server. */
|
||||
class MessageOfTheDayBar extends Composite {
|
||||
interface Binder extends UiBinder<HTMLPanel, MessageOfTheDayBar> {}
|
||||
private static final Binder uiBinder = GWT.create(Binder.class);
|
||||
|
||||
private final List<HostPageData.Message> motd;
|
||||
@UiField HTML message;
|
||||
@UiField Anchor dismiss;
|
||||
|
||||
MessageOfTheDayBar(List<HostPageData.Message> motd) {
|
||||
this.motd = filter(motd);
|
||||
initWidget(uiBinder.createAndBindUi(this));
|
||||
|
||||
SafeHtmlBuilder b = new SafeHtmlBuilder();
|
||||
if (motd.size() == 1) {
|
||||
b.append(SafeHtml.asis(motd.get(0).html));
|
||||
} else {
|
||||
for (HostPageData.Message m : motd) {
|
||||
b.openDiv();
|
||||
b.append(SafeHtml.asis(m.html));
|
||||
b.closeDiv();
|
||||
}
|
||||
}
|
||||
message.setHTML(b);
|
||||
}
|
||||
|
||||
void show() {
|
||||
if (!motd.isEmpty()) {
|
||||
RootPanel.get().add(this);
|
||||
}
|
||||
}
|
||||
|
||||
@UiHandler("dismiss")
|
||||
void onDismiss(ClickEvent e) {
|
||||
removeFromParent();
|
||||
|
||||
for (HostPageData.Message m : motd) {
|
||||
Cookies.setCookie(cookieName(m), "1", m.redisplay);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<HostPageData.Message> filter(List<HostPageData.Message> in) {
|
||||
List<HostPageData.Message> show = new ArrayList<HostPageData.Message>();
|
||||
for (HostPageData.Message m : in) {
|
||||
if (Cookies.getCookie(cookieName(m)) == null) {
|
||||
show.add(m);
|
||||
}
|
||||
}
|
||||
return show;
|
||||
}
|
||||
|
||||
private static String cookieName(HostPageData.Message m) {
|
||||
return "msg-" + m.id;
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright (C) 2014 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.
|
||||
-->
|
||||
<ui:UiBinder
|
||||
xmlns:ui='urn:ui:com.google.gwt.uibinder'
|
||||
xmlns:c='urn:import:com.google.gwtexpui.globalkey.client'
|
||||
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
|
||||
<ui:style>
|
||||
.popup {
|
||||
position: fixed;
|
||||
top: 5px;
|
||||
left: 50%;
|
||||
margin-left: -200px;
|
||||
z-index: 201;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
background: #FFF1A8;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
@if user.agent safari {
|
||||
.popup {
|
||||
\-webkit-border-radius: 10px;
|
||||
}
|
||||
}
|
||||
@if user.agent gecko1_8 {
|
||||
.popup {
|
||||
\-moz-border-radius: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.message {
|
||||
display: inline;
|
||||
}
|
||||
.message a {
|
||||
color: #222;
|
||||
text-decoration: underline;
|
||||
}
|
||||
a.action {
|
||||
color: #222;
|
||||
text-decoration: underline;
|
||||
display: inline-block;
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
</ui:style>
|
||||
<g:HTMLPanel styleName='{style.popup}'>
|
||||
<g:HTML ui:field='message' styleName='{style.message}'/>
|
||||
<g:Anchor ui:field='dismiss'
|
||||
styleName='{style.action}'
|
||||
href='javascript:;'
|
||||
title='Hide this message'>
|
||||
<ui:attribute name='title'/>
|
||||
Dismiss
|
||||
</g:Anchor>
|
||||
</g:HTMLPanel>
|
||||
</ui:UiBinder>
|
@ -14,6 +14,7 @@
|
||||
|
||||
package com.google.gerrit.httpd.raw;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.hash.Hasher;
|
||||
import com.google.common.hash.Hashing;
|
||||
@ -22,6 +23,7 @@ import com.google.gerrit.common.Version;
|
||||
import com.google.gerrit.common.data.GerritConfig;
|
||||
import com.google.gerrit.common.data.HostPageData;
|
||||
import com.google.gerrit.extensions.registration.DynamicSet;
|
||||
import com.google.gerrit.extensions.systemstatus.MessageOfTheDay;
|
||||
import com.google.gerrit.extensions.webui.WebUiPlugin;
|
||||
import com.google.gerrit.httpd.HtmlDomUtil;
|
||||
import com.google.gerrit.httpd.WebSession;
|
||||
@ -51,6 +53,7 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -74,6 +77,7 @@ public class HostPageServlet extends HttpServlet {
|
||||
private final Provider<WebSession> session;
|
||||
private final GerritConfig config;
|
||||
private final DynamicSet<WebUiPlugin> plugins;
|
||||
private final DynamicSet<MessageOfTheDay> messages;
|
||||
private final HostPageData.Theme signedOutTheme;
|
||||
private final HostPageData.Theme signedInTheme;
|
||||
private final SitePaths site;
|
||||
@ -89,6 +93,7 @@ public class HostPageServlet extends HttpServlet {
|
||||
final SitePaths sp, final ThemeFactory themeFactory,
|
||||
final GerritConfig gc, final ServletContext servletContext,
|
||||
final DynamicSet<WebUiPlugin> webUiPlugins,
|
||||
final DynamicSet<MessageOfTheDay> motd,
|
||||
@GerritServerConfig final Config cfg,
|
||||
final StaticServlet ss)
|
||||
throws IOException, ServletException {
|
||||
@ -96,6 +101,7 @@ public class HostPageServlet extends HttpServlet {
|
||||
session = w;
|
||||
config = gc;
|
||||
plugins = webUiPlugins;
|
||||
messages = motd;
|
||||
signedOutTheme = themeFactory.getSignedOutTheme();
|
||||
signedInTheme = themeFactory.getSignedInTheme();
|
||||
site = sp;
|
||||
@ -201,6 +207,7 @@ public class HostPageServlet extends HttpServlet {
|
||||
w.write(";");
|
||||
}
|
||||
plugins(w);
|
||||
messages(w);
|
||||
|
||||
final byte[] hpd = w.toString().getBytes("UTF-8");
|
||||
final byte[] raw = Bytes.concat(page.part1, hpd, page.part2);
|
||||
@ -238,6 +245,25 @@ public class HostPageServlet extends HttpServlet {
|
||||
}
|
||||
}
|
||||
|
||||
private void messages(StringWriter w) {
|
||||
List<HostPageData.Message> list = new ArrayList<>(2);
|
||||
for (MessageOfTheDay motd : messages) {
|
||||
String html = motd.getHtmlMessage();
|
||||
if (!Strings.isNullOrEmpty(html)) {
|
||||
HostPageData.Message m = new HostPageData.Message();
|
||||
m.id = motd.getMessageId();
|
||||
m.redisplay = motd.getRedisplay();
|
||||
m.html = html;
|
||||
list.add(m);
|
||||
}
|
||||
}
|
||||
if (!list.isEmpty()) {
|
||||
w.write(HPD_ID + ".messages=");
|
||||
json(list, w);
|
||||
w.write(";");
|
||||
}
|
||||
}
|
||||
|
||||
private Page.Content select(HttpServletRequest req) {
|
||||
Page pg = get();
|
||||
if ("1".equals(req.getParameter("dbg"))) {
|
||||
|
@ -30,6 +30,7 @@ import com.google.gerrit.extensions.events.ProjectDeletedListener;
|
||||
import com.google.gerrit.extensions.registration.DynamicItem;
|
||||
import com.google.gerrit.extensions.registration.DynamicMap;
|
||||
import com.google.gerrit.extensions.registration.DynamicSet;
|
||||
import com.google.gerrit.extensions.systemstatus.MessageOfTheDay;
|
||||
import com.google.gerrit.extensions.webui.TopMenu;
|
||||
import com.google.gerrit.rules.PrologModule;
|
||||
import com.google.gerrit.rules.RulesCache;
|
||||
@ -260,6 +261,7 @@ public class GerritGlobalModule extends FactoryModule {
|
||||
DynamicItem.itemOf(binder(), AvatarProvider.class);
|
||||
DynamicSet.setOf(binder(), LifecycleListener.class);
|
||||
DynamicSet.setOf(binder(), TopMenu.class);
|
||||
DynamicSet.setOf(binder(), MessageOfTheDay.class);
|
||||
DynamicMap.mapOf(binder(), DownloadScheme.class);
|
||||
DynamicMap.mapOf(binder(), DownloadCommand.class);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user