Add ui
diff --git a/BUCK b/BUCK
index 1eb427a..2282912 100644
--- a/BUCK
+++ b/BUCK
@@ -1,12 +1,16 @@
 include_defs('//bucklets/gerrit_plugin.bucklet')
 
+MODULE = 'com.googlesource.gerrit.plugins.ci.CiForm'
+
 gerrit_plugin(
   name = 'gerrit-ci-plugin',
   srcs = glob(['src/main/java/**/*.java']),
   resources = glob(['src/main/**/*']),
+  gwt_module = MODULE,
   manifest_entries = [
     'Gerrit-PluginName: ci',
     'Gerrit-Module: com.googlesource.gerrit.plugins.ci.GlobalModule',
+    'Gerrit-HttpModule: com.googlesource.gerrit.plugins.ci.HttpModule',
     'Gerrit-SshModule: com.googlesource.gerrit.plugins.ci.SshModule',
     'Gerrit-InitStep: com.googlesource.gerrit.plugins.ci.init.InitPlugin',
     'Implementation-Title: CI plugin',
diff --git a/src/main/java/com/googlesource/gerrit/plugins/ci/CiForm.gwt.xml b/src/main/java/com/googlesource/gerrit/plugins/ci/CiForm.gwt.xml
new file mode 100644
index 0000000..cfe2695
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/ci/CiForm.gwt.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2013 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.
+-->
+<module rename-to="ci">
+  <!-- Inherit the core Web Toolkit stuff.                        -->
+  <inherits name="com.google.gwt.user.User"/>
+  <!-- Other module inherits                                      -->
+  <inherits name="com.google.gerrit.GerritGwtUICommon"/>
+  <inherits name="com.google.gerrit.Plugin"/>
+  <inherits name="com.google.gwt.http.HTTP"/>
+  <inherits name="com.google.gwt.json.JSON"/>
+  <!-- Using GWT built-in themes adds a number of static          -->
+  <!-- resources to the plugin. No theme inherits lines were      -->
+  <!-- added in order to make this plugin as simple as possible   -->
+  <!-- Specify the app entry point class.                         -->
+  <entry-point class="com.googlesource.gerrit.plugins.ci.client.CiPlugin"/>
+  <stylesheet src="ci.css"/>
+</module>
diff --git a/src/main/java/com/googlesource/gerrit/plugins/ci/GlobalModule.java b/src/main/java/com/googlesource/gerrit/plugins/ci/GlobalModule.java
index 8513818..6362d11 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/ci/GlobalModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/ci/GlobalModule.java
@@ -15,8 +15,10 @@
 package com.googlesource.gerrit.plugins.ci;
 
 import static com.google.inject.Scopes.SINGLETON;
+import static com.google.gerrit.server.change.RevisionResource.REVISION_KIND;
 
 import com.google.gerrit.extensions.config.FactoryModule;
+import com.google.gerrit.extensions.restapi.RestApiModule;
 import com.google.gerrit.lifecycle.LifecycleModule;
 import com.google.inject.Inject;
 import com.google.inject.Injector;
@@ -24,6 +26,8 @@
 import com.google.inject.Module;
 import com.google.inject.name.Names;
 
+import com.googlesource.gerrit.plugins.ci.server.GetVerifications;
+import com.googlesource.gerrit.plugins.ci.server.PostVerification;
 import com.googlesource.gerrit.plugins.ci.server.schema.CiDataSourceModule;
 import com.googlesource.gerrit.plugins.ci.server.schema.CiDataSourceProvider;
 import com.googlesource.gerrit.plugins.ci.server.schema.CiDataSourceType;
@@ -35,8 +39,7 @@
 
 import javax.sql.DataSource;
 
-public class GlobalModule extends FactoryModule {
-
+class GlobalModule extends FactoryModule {
   private final Injector injector;
 
   @Inject
@@ -74,5 +77,12 @@
     for (Module module : modules) {
       install(module);
     }
+    install(new RestApiModule() {
+      @Override
+      protected void configure() {
+        get(REVISION_KIND, "verifications").to(GetVerifications.class);
+        post(REVISION_KIND, "verifications").to(PostVerification.class);
+      }
+    });
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/ci/HttpModule.java b/src/main/java/com/googlesource/gerrit/plugins/ci/HttpModule.java
new file mode 100644
index 0000000..57ee620
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/ci/HttpModule.java
@@ -0,0 +1,28 @@
+// Copyright (C) 2015 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.googlesource.gerrit.plugins.ci;
+
+import com.google.gerrit.extensions.registration.DynamicSet;
+import com.google.gerrit.extensions.webui.GwtPlugin;
+import com.google.gerrit.extensions.webui.WebUiPlugin;
+import com.google.gerrit.httpd.plugins.HttpPluginModule;
+
+class HttpModule extends HttpPluginModule {
+  @Override
+  protected void configureServlets() {
+    DynamicSet.bind(binder(), WebUiPlugin.class)
+        .toInstance(new GwtPlugin("ci"));
+  }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/ci/SshModule.java b/src/main/java/com/googlesource/gerrit/plugins/ci/SshModule.java
index 2d7d16c..6fc1822 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/ci/SshModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/ci/SshModule.java
@@ -20,7 +20,7 @@
 import com.googlesource.gerrit.plugins.ci.commands.CiQueryShell;
 import com.googlesource.gerrit.plugins.ci.commands.VerifyCommand;
 
-public class SshModule extends PluginCommandModule {
+class SshModule extends PluginCommandModule {
   @Override
   protected void configureCommands() {
     command(CiAdminQueryShell.class);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/ci/client/BuildsDropDownPanel.java b/src/main/java/com/googlesource/gerrit/plugins/ci/client/BuildsDropDownPanel.java
new file mode 100644
index 0000000..6db5bc2
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/ci/client/BuildsDropDownPanel.java
@@ -0,0 +1,100 @@
+// Copyright (C) 2015 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.googlesource.gerrit.plugins.ci.client;
+
+import com.google.gerrit.client.GerritUiExtensionPoint;
+import com.google.gerrit.client.info.ChangeInfo;
+import com.google.gerrit.client.rpc.NativeMap;
+import com.google.gerrit.plugin.client.Plugin;
+import com.google.gerrit.plugin.client.extension.Panel;
+import com.google.gerrit.plugin.client.rpc.RestApi;
+import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.Grid;
+import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.Image;
+import com.google.gwt.user.client.ui.InlineHyperlink;
+import com.google.gwt.user.client.ui.InlineLabel;
+
+/**
+ * Extension for change screen that displays a status in the header bar.
+ */
+public class BuildsDropDownPanel extends FlowPanel {
+  static class Factory implements Panel.EntryPoint {
+    @Override
+    public void onLoad(Panel panel) {
+    }
+  }
+
+  BuildsDropDownPanel(final Panel panel) {
+    ChangeInfo change =
+        panel.getObject(GerritUiExtensionPoint.Key.CHANGE_INFO).cast();
+    new RestApi("config")
+      .id("server")
+      .view(Plugin.get().getPluginName(), "verifications")
+      .get(new AsyncCallback<NativeMap<VerificationInfo>>() {
+        @Override
+        public void onSuccess(NativeMap<VerificationInfo> map) {
+          map.copyKeysIntoChildren("category");
+          // TODO only rendern when not empty
+          panel.setWidget(new BuildsDropDownPanel());
+        }
+
+        @Override
+        public void onFailure(Throwable caught) {
+          // never invoked
+        }
+      });
+  }
+
+  BuildsDropDownPanel() {
+    Grid g = new Grid(3, 4);
+    g.addStyleName("infoBlock");
+    CellFormatter fmt = g.getCellFormatter();
+
+    g.setText(0, 0, "State");
+    fmt.addStyleName(0, 0, "header");
+    g.setText(0, 1, "PS");
+    fmt.addStyleName(0, 1, "header");
+    g.setText(0, 2, "Date");
+    fmt.addStyleName(0, 2, "header");
+    g.setText(0, 3, "Log");
+    fmt.addStyleName(0, 3, "header");
+
+    HorizontalPanel p = new HorizontalPanel();
+    p.add(new Image(CiPlugin.RESOURCES.greenCheck()));
+    p.add(new InlineLabel("OK"));
+    g.setWidget(1, 0, p);
+    g.setWidget(1, 1, new InlineLabel("2"));
+    g.setWidget(1, 2, new InlineLabel("2015-07-09 11:06:13"));
+    g.setWidget(1, 3, new InlineHyperlink("Build Log", "TODO"));
+
+    p = new HorizontalPanel();
+    p.add(new Image(CiPlugin.RESOURCES.redNot()));
+    p.add(new InlineLabel("FAILED"));
+    g.setWidget(2, 0, p);
+    g.setWidget(2, 1, new InlineLabel("1"));
+    g.setWidget(2, 2, new InlineLabel("2015-07-09 09:17:28"));
+    g.setWidget(2, 3, new InlineHyperlink("Build Log", "TODO"));
+
+    fmt.addStyleName(0, 0, "topmost");
+    fmt.addStyleName(0, 1, "topmost");
+    fmt.addStyleName(0, 2, "topmost");
+    fmt.addStyleName(0, 3, "topmost");
+
+    add(new PopDownButton("Builds", g));
+  }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/ci/client/CiPlugin.java b/src/main/java/com/googlesource/gerrit/plugins/ci/client/CiPlugin.java
new file mode 100644
index 0000000..3d53957
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/ci/client/CiPlugin.java
@@ -0,0 +1,32 @@
+// Copyright (C) 2013 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.googlesource.gerrit.plugins.ci.client;
+
+import com.google.gerrit.client.GerritUiExtensionPoint;
+import com.google.gerrit.client.Resources;
+import com.google.gerrit.plugin.client.Plugin;
+import com.google.gerrit.plugin.client.PluginEntryPoint;
+import com.google.gwt.core.client.GWT;
+
+public class CiPlugin extends PluginEntryPoint {
+  public static final Resources RESOURCES = GWT.create(Resources.class);
+
+  @Override
+  public void onPluginLoad() {
+    Plugin.get().panel(
+        GerritUiExtensionPoint.CHANGE_SCREEN_HEADER_RIGHT_OF_POP_DOWNS,
+        new BuildsDropDownPanel.Factory());
+  }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/ci/client/PopDownButton.java b/src/main/java/com/googlesource/gerrit/plugins/ci/client/PopDownButton.java
new file mode 100644
index 0000000..f26c6a3
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/ci/client/PopDownButton.java
@@ -0,0 +1,101 @@
+// Copyright (C) 2015 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.googlesource.gerrit.plugins.ci.client;
+
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.Style;
+import com.google.gwt.dom.client.Style.FontWeight;
+import com.google.gwt.dom.client.Style.Unit;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.logical.shared.CloseEvent;
+import com.google.gwt.event.logical.shared.CloseHandler;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.PopupPanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.google.gwtexpui.globalkey.client.GlobalKey;
+import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
+
+/**
+ * Pop down button for header line in change screen.
+ *
+ * This class implements a button that on click opens a pop down panel with the
+ * provided widget, similar to the "Patch Sets", "Download" or "Included In" pop
+ * down panels on the change screen.
+ *
+ * This class can *only* be used within a panel that extends the header line of
+ * the change screen, but will not work standalone.
+ */
+public class PopDownButton extends Button {
+  private final Widget widget;
+  private PopupPanel popup;
+
+  public PopDownButton(String text, Widget widget) {
+    // Create Button with inner div. This is required to get proper styling
+    // in the context of the change screen.
+    super((new SafeHtmlBuilder()).openDiv().append(text).closeDiv());
+    getElement().removeClassName("gwt-Button");
+    addClickHandler(new ClickHandler() {
+      @Override
+      public void onClick(ClickEvent event) {
+        show();
+      }
+    });
+    this.widget = widget;
+  }
+
+  private void show() {
+    if (popup != null) {
+      getElement().getStyle().clearFontWeight();
+      popup.hide();
+      return;
+    }
+
+    final Widget relativeTo = getParent();
+    final PopupPanel p = new PopupPanel(true) {
+      @Override
+      public void setPopupPosition(int left, int top) {
+        top -= Document.get().getBodyOffsetTop();
+
+        int w = Window.getScrollLeft() + Window.getClientWidth();
+        int r = relativeTo.getAbsoluteLeft() + relativeTo.getOffsetWidth();
+        int right = w - r;
+        Style style = getElement().getStyle();
+        style.clearProperty("left");
+        style.setPropertyPx("right", right);
+        style.setPropertyPx("top", top);
+      }
+    };
+    Style popupStyle = p.getElement().getStyle();
+    popupStyle.setBorderWidth(0, Unit.PX);
+    popupStyle.setBackgroundColor("#EEEEEE");
+    p.addAutoHidePartner(getElement());
+    p.addCloseHandler(new CloseHandler<PopupPanel>() {
+      @Override
+      public void onClose(CloseEvent<PopupPanel> event) {
+        if (popup == p) {
+          getElement().getStyle().clearFontWeight();
+          popup = null;
+        }
+      }
+    });
+    p.add(widget);
+    p.showRelativeTo(relativeTo);
+    GlobalKey.dialog(p);
+    getElement().getStyle().setFontWeight(FontWeight.BOLD);
+    popup = p;
+  }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/ci/client/VerificationInfo.java b/src/main/java/com/googlesource/gerrit/plugins/ci/client/VerificationInfo.java
new file mode 100644
index 0000000..f847819
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/ci/client/VerificationInfo.java
@@ -0,0 +1,14 @@
+package com.googlesource.gerrit.plugins.ci.client;
+
+import com.google.gwt.core.client.JavaScriptObject;
+
+public class VerificationInfo extends JavaScriptObject {
+
+  public final native String category() /*-{ return this.category; }-*/;
+  public final native String url() /*-{ return this.url; }-*/;
+  public final native String granted() /*-{ return this.granted; }-*/;
+  public final native int value() /*-{ return this.value; }-*/;
+
+  protected VerificationInfo() {
+  }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/ci/common/VerificationInfo.java b/src/main/java/com/googlesource/gerrit/plugins/ci/common/VerificationInfo.java
index 58a05c7..7e1eac2 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/ci/common/VerificationInfo.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/ci/common/VerificationInfo.java
@@ -19,4 +19,5 @@
   public Short value;
   public String verifier;
   public String comment;
+  public String granted;
 }
\ No newline at end of file
diff --git a/src/main/java/com/googlesource/gerrit/plugins/ci/public/ci.css b/src/main/java/com/googlesource/gerrit/plugins/ci/public/ci.css
new file mode 100644
index 0000000..8385649
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/ci/public/ci.css
@@ -0,0 +1,4 @@
+.ci-panel {
+  border-spacing: 0px 5px;
+}
+
diff --git a/src/main/java/com/googlesource/gerrit/plugins/ci/server/GetVerifications.java b/src/main/java/com/googlesource/gerrit/plugins/ci/server/GetVerifications.java
index efff050..04b144e 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/ci/server/GetVerifications.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/ci/server/GetVerifications.java
@@ -25,10 +25,14 @@
 import com.googlesource.gerrit.plugins.ci.common.VerificationInfo;
 
 import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Locale;
 import java.util.Map;
 
 @Singleton
 public class GetVerifications implements RestReadView<RevisionResource> {
+  private static final SimpleDateFormat DATE_FORMAT =
+      new SimpleDateFormat("d MMM yyyy HH:mm:ss", Locale.US);
   private final SchemaFactory<CiDb> schemaFactory;
 
   @Inject
@@ -48,6 +52,7 @@
         info.url = v.getUrl();
         info.verifier = v.getVerifier();
         info.comment = v.getComment();
+        info.granted = DATE_FORMAT.format(v.getGranted());
         out.put(v.getLabelId().get(), info);
       }
     }