Redesign change screen on new REST API
The new screen exists at #/c2/<id> as it is missing a large number of features. The proposal is to include the screen as-is and iterate in tree, similar to the CodeMirror work. This allows power users to start trying the screen out by editing the URL. Missing features: - Add reviewer(s) - Remove reviewer(s) - Edit commit message - Diff files in two patch sets - Dependencies and dependents - Download links by URL and action (cherry-pick, checkout, etc.) Change-Id: Ie957fb85c873d044c947000f0f0207a66f87c784
This commit is contained in:
@@ -54,6 +54,14 @@ public class PageLinks {
|
|||||||
return "/c/" + c + "/";
|
return "/c/" + c + "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String toChange2(final Change.Id c) {
|
||||||
|
return "/c2/" + c + "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String toChange2(Change.Id c, String p) {
|
||||||
|
return "/c2/" + c + "/" + p;
|
||||||
|
}
|
||||||
|
|
||||||
public static String toChange(final PatchSet.Id ps) {
|
public static String toChange(final PatchSet.Id ps) {
|
||||||
return "/c/" + ps.getParentKey() + "/" + ps.get();
|
return "/c/" + ps.getParentKey() + "/" + ps.get();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ import com.google.gerrit.client.admin.ProjectDashboardsScreen;
|
|||||||
import com.google.gerrit.client.admin.ProjectInfoScreen;
|
import com.google.gerrit.client.admin.ProjectInfoScreen;
|
||||||
import com.google.gerrit.client.admin.ProjectListScreen;
|
import com.google.gerrit.client.admin.ProjectListScreen;
|
||||||
import com.google.gerrit.client.admin.ProjectScreen;
|
import com.google.gerrit.client.admin.ProjectScreen;
|
||||||
|
import com.google.gerrit.client.change.ChangeScreen2;
|
||||||
import com.google.gerrit.client.changes.AccountDashboardScreen;
|
import com.google.gerrit.client.changes.AccountDashboardScreen;
|
||||||
import com.google.gerrit.client.changes.ChangeScreen;
|
import com.google.gerrit.client.changes.ChangeScreen;
|
||||||
import com.google.gerrit.client.changes.CustomDashboardScreen;
|
import com.google.gerrit.client.changes.CustomDashboardScreen;
|
||||||
@@ -190,6 +191,9 @@ public class Dispatcher {
|
|||||||
} else if (matchPrefix("/c/", token)) {
|
} else if (matchPrefix("/c/", token)) {
|
||||||
change(token);
|
change(token);
|
||||||
|
|
||||||
|
} else if (matchPrefix("/c2/", token)) {
|
||||||
|
change2(token);
|
||||||
|
|
||||||
} else if (matchExact(MINE, token)) {
|
} else if (matchExact(MINE, token)) {
|
||||||
Gerrit.display(token, mine(token));
|
Gerrit.display(token, mine(token));
|
||||||
|
|
||||||
@@ -504,6 +508,20 @@ public class Dispatcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void change2(final String token) {
|
||||||
|
String rest = skip(token);
|
||||||
|
Change.Id id;
|
||||||
|
int s = rest.indexOf('/');
|
||||||
|
if (0 <= s) {
|
||||||
|
id = Change.Id.parse(rest.substring(0, s));
|
||||||
|
rest = rest.substring(s + 1);
|
||||||
|
} else {
|
||||||
|
id = Change.Id.parse(rest);
|
||||||
|
rest = "";
|
||||||
|
}
|
||||||
|
Gerrit.display(token, new ChangeScreen2(id, rest));
|
||||||
|
}
|
||||||
|
|
||||||
private static void publish(final PatchSet.Id ps) {
|
private static void publish(final PatchSet.Id ps) {
|
||||||
String token = toPublish(ps);
|
String token = toPublish(ps);
|
||||||
new AsyncSplit(token) {
|
new AsyncSplit(token) {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
package com.google.gerrit.client;
|
package com.google.gerrit.client;
|
||||||
|
|
||||||
|
import com.google.gerrit.client.changes.ChangeInfo.RevisionInfo;
|
||||||
import com.google.gerrit.common.data.GitWebType;
|
import com.google.gerrit.common.data.GitWebType;
|
||||||
import com.google.gerrit.common.data.ParameterizedString;
|
import com.google.gerrit.common.data.ParameterizedString;
|
||||||
import com.google.gerrit.reviewdb.client.Branch;
|
import com.google.gerrit.reviewdb.client.Branch;
|
||||||
@@ -45,19 +46,26 @@ public class GitwebLink {
|
|||||||
return !ps.isDraft() || type.getLinkDrafts();
|
return !ps.isDraft() || type.getLinkDrafts();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean canLink(RevisionInfo revision) {
|
||||||
|
return revision.draft() || type.getLinkDrafts();
|
||||||
|
}
|
||||||
|
|
||||||
public String getLinkName() {
|
public String getLinkName() {
|
||||||
return "(" + type.getLinkName() + ")";
|
return "(" + type.getLinkName() + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toRevision(final Project.NameKey project, final PatchSet ps) {
|
public String toRevision(String project, String commit) {
|
||||||
ParameterizedString pattern = new ParameterizedString(type.getRevision());
|
ParameterizedString pattern = new ParameterizedString(type.getRevision());
|
||||||
|
Map<String, String> p = new HashMap<String, String>();
|
||||||
final Map<String, String> p = new HashMap<String, String>();
|
p.put("project", encode(project));
|
||||||
p.put("project", encode(project.get()));
|
p.put("commit", encode(commit));
|
||||||
p.put("commit", encode(ps.getRevision().get()));
|
|
||||||
return baseUrl + pattern.replace(p);
|
return baseUrl + pattern.replace(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String toRevision(final Project.NameKey project, final PatchSet ps) {
|
||||||
|
return toRevision(project.get(), ps.getRevision().get());
|
||||||
|
}
|
||||||
|
|
||||||
public String toProject(final Project.NameKey project) {
|
public String toProject(final Project.NameKey project) {
|
||||||
ParameterizedString pattern = new ParameterizedString(type.getProject());
|
ParameterizedString pattern = new ParameterizedString(type.getProject());
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
// 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.google.gerrit.client.change;
|
||||||
|
|
||||||
|
import com.google.gerrit.client.Gerrit;
|
||||||
|
import com.google.gerrit.client.changes.ChangeApi;
|
||||||
|
import com.google.gerrit.client.changes.ChangeInfo;
|
||||||
|
import com.google.gerrit.client.rpc.GerritCallback;
|
||||||
|
import com.google.gerrit.common.PageLinks;
|
||||||
|
import com.google.gerrit.reviewdb.client.Change;
|
||||||
|
import com.google.gwt.user.client.ui.Button;
|
||||||
|
|
||||||
|
class AbandonAction extends ActionMessageBox {
|
||||||
|
private final Change.Id id;
|
||||||
|
|
||||||
|
AbandonAction(Button b, Change.Id id) {
|
||||||
|
super(b);
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void send(String message) {
|
||||||
|
ChangeApi.abandon(id.get(), message, new GerritCallback<ChangeInfo>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(ChangeInfo result) {
|
||||||
|
Gerrit.display(PageLinks.toChange2(id));
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
// 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.google.gerrit.client.change;
|
||||||
|
|
||||||
|
import com.google.gerrit.client.ConfirmationCallback;
|
||||||
|
import com.google.gerrit.client.ConfirmationDialog;
|
||||||
|
import com.google.gerrit.client.ErrorDialog;
|
||||||
|
import com.google.gerrit.client.changes.ChangeApi;
|
||||||
|
import com.google.gerrit.client.changes.ChangeInfo.ActionInfo;
|
||||||
|
import com.google.gerrit.client.rpc.NativeString;
|
||||||
|
import com.google.gerrit.client.rpc.RestApi;
|
||||||
|
import com.google.gerrit.reviewdb.client.Change;
|
||||||
|
import com.google.gwt.core.client.JavaScriptObject;
|
||||||
|
import com.google.gwt.event.dom.client.ClickEvent;
|
||||||
|
import com.google.gwt.event.dom.client.ClickHandler;
|
||||||
|
import com.google.gwt.user.client.Window;
|
||||||
|
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||||
|
import com.google.gwt.user.client.ui.Button;
|
||||||
|
import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
|
||||||
|
|
||||||
|
class ActionButton extends Button implements ClickHandler {
|
||||||
|
private final Change.Id changeId;
|
||||||
|
private final String revision;
|
||||||
|
private final ActionInfo action;
|
||||||
|
|
||||||
|
ActionButton(Change.Id changeId, ActionInfo action) {
|
||||||
|
this(changeId, null, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionButton(Change.Id changeId, String revision, ActionInfo action) {
|
||||||
|
super(new SafeHtmlBuilder()
|
||||||
|
.openDiv()
|
||||||
|
.append(action.label())
|
||||||
|
.closeDiv());
|
||||||
|
setStyleName("");
|
||||||
|
setTitle(action.title());
|
||||||
|
setEnabled(action.enabled());
|
||||||
|
addClickHandler(this);
|
||||||
|
|
||||||
|
this.changeId = changeId;
|
||||||
|
this.revision = revision;
|
||||||
|
this.action = action;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(ClickEvent event) {
|
||||||
|
if (action.confirmation_message() != null
|
||||||
|
&& !action.confirmation_message().isEmpty()) {
|
||||||
|
new ConfirmationDialog(
|
||||||
|
action.title(),
|
||||||
|
new SafeHtmlBuilder().append(action.confirmation_message()),
|
||||||
|
new ConfirmationCallback() {
|
||||||
|
@Override
|
||||||
|
public void onOk() {
|
||||||
|
send();
|
||||||
|
}
|
||||||
|
}).center();
|
||||||
|
} else {
|
||||||
|
send();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void send() {
|
||||||
|
setEnabled(false);
|
||||||
|
|
||||||
|
AsyncCallback<NativeString> cb = new AsyncCallback<NativeString>() {
|
||||||
|
@Override
|
||||||
|
public void onFailure(Throwable caught) {
|
||||||
|
setEnabled(true);
|
||||||
|
new ErrorDialog(caught).center();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSuccess(NativeString msg) {
|
||||||
|
setEnabled(true);
|
||||||
|
if (msg != null && !msg.asString().isEmpty()) {
|
||||||
|
// TODO Support better UI on UiCommand results.
|
||||||
|
Window.alert(msg.asString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
RestApi api = revision != null
|
||||||
|
? ChangeApi.revision(changeId.get(), revision)
|
||||||
|
: ChangeApi.change(changeId.get());
|
||||||
|
api.view(action.id());
|
||||||
|
|
||||||
|
if ("PUT".equalsIgnoreCase(action.method())) {
|
||||||
|
api.put(JavaScriptObject.createObject(), cb);
|
||||||
|
} else if ("DELETE".equalsIgnoreCase(action.method())) {
|
||||||
|
api.delete(cb);
|
||||||
|
} else {
|
||||||
|
api.post(JavaScriptObject.createObject(), cb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
// 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.google.gerrit.client.change;
|
||||||
|
|
||||||
|
import com.google.gwt.core.client.GWT;
|
||||||
|
import com.google.gwt.event.dom.client.ClickEvent;
|
||||||
|
import com.google.gwt.event.dom.client.KeyCodes;
|
||||||
|
import com.google.gwt.event.dom.client.KeyPressEvent;
|
||||||
|
import com.google.gwt.event.logical.shared.CloseEvent;
|
||||||
|
import com.google.gwt.event.logical.shared.CloseHandler;
|
||||||
|
import com.google.gwt.resources.client.CssResource;
|
||||||
|
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.ui.Button;
|
||||||
|
import com.google.gwt.user.client.ui.Composite;
|
||||||
|
import com.google.gwt.user.client.ui.HTMLPanel;
|
||||||
|
import com.google.gwt.user.client.ui.PopupPanel;
|
||||||
|
import com.google.gwtexpui.globalkey.client.GlobalKey;
|
||||||
|
import com.google.gwtexpui.globalkey.client.NpTextArea;
|
||||||
|
import com.google.gwtexpui.user.client.PluginSafePopupPanel;
|
||||||
|
|
||||||
|
abstract class ActionMessageBox extends Composite {
|
||||||
|
interface Binder extends UiBinder<HTMLPanel, ActionMessageBox> {}
|
||||||
|
private static Binder uiBinder = GWT.create(Binder.class);
|
||||||
|
|
||||||
|
static interface Style extends CssResource {
|
||||||
|
String popup();
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Button activatingButton;
|
||||||
|
private PluginSafePopupPanel popup;
|
||||||
|
|
||||||
|
@UiField Style style;
|
||||||
|
@UiField NpTextArea message;
|
||||||
|
@UiField Button send;
|
||||||
|
|
||||||
|
ActionMessageBox(Button button) {
|
||||||
|
this.activatingButton = button;
|
||||||
|
initWidget(uiBinder.createAndBindUi(this));
|
||||||
|
send.setText(button.getText());
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract void send(String message);
|
||||||
|
|
||||||
|
void show() {
|
||||||
|
if (popup != null) {
|
||||||
|
popup.hide();
|
||||||
|
popup = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final PluginSafePopupPanel p = new PluginSafePopupPanel(true);
|
||||||
|
p.setStyleName(style.popup());
|
||||||
|
p.addAutoHidePartner(activatingButton.getElement());
|
||||||
|
p.addCloseHandler(new CloseHandler<PopupPanel>() {
|
||||||
|
@Override
|
||||||
|
public void onClose(CloseEvent<PopupPanel> event) {
|
||||||
|
if (popup == p) {
|
||||||
|
popup = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
p.add(this);
|
||||||
|
p.showRelativeTo(activatingButton);
|
||||||
|
GlobalKey.dialog(p);
|
||||||
|
message.setFocus(true);
|
||||||
|
popup = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hide() {
|
||||||
|
if (popup != null) {
|
||||||
|
popup.hide();
|
||||||
|
popup = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiHandler("message")
|
||||||
|
void onMessageKey(KeyPressEvent event) {
|
||||||
|
if ((event.getCharCode() == '\n' || event.getCharCode() == KeyCodes.KEY_ENTER)
|
||||||
|
&& event.isControlKeyDown()) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
onSend(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiHandler("send")
|
||||||
|
void onSend(ClickEvent e) {
|
||||||
|
send(message.getValue().trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
<?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.
|
||||||
|
-->
|
||||||
|
<ui:UiBinder
|
||||||
|
xmlns:ui='urn:ui:com.google.gwt.uibinder'
|
||||||
|
xmlns:g='urn:import:com.google.gwt.user.client.ui'
|
||||||
|
xmlns:c='urn:import:com.google.gwtexpui.globalkey.client'>
|
||||||
|
<ui:with field='res' type='com.google.gerrit.client.change.Resources'/>
|
||||||
|
<ui:style type='com.google.gerrit.client.change.ActionMessageBox.Style'>
|
||||||
|
@eval trimColor com.google.gerrit.client.Gerrit.getTheme().trimColor;
|
||||||
|
|
||||||
|
.popup { background-color: trimColor; }
|
||||||
|
.section {
|
||||||
|
padding: 5px 5px;
|
||||||
|
border-bottom: 1px solid #b8b8b8;
|
||||||
|
}
|
||||||
|
</ui:style>
|
||||||
|
<g:HTMLPanel>
|
||||||
|
<div class='{style.section}'>
|
||||||
|
<c:NpTextArea
|
||||||
|
visibleLines='3'
|
||||||
|
characterWidth='40'
|
||||||
|
ui:field='message'/>
|
||||||
|
</div>
|
||||||
|
<div class='{style.section}'>
|
||||||
|
<g:Button ui:field='send'
|
||||||
|
title='(Shortcut: Ctrl-Enter)'
|
||||||
|
styleName='{res.style.button}'>
|
||||||
|
<ui:attribute name='title'/>
|
||||||
|
<div><ui:msg>Send</ui:msg></div>
|
||||||
|
</g:Button>
|
||||||
|
</div>
|
||||||
|
</g:HTMLPanel>
|
||||||
|
</ui:UiBinder>
|
||||||
@@ -0,0 +1,171 @@
|
|||||||
|
// 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.google.gerrit.client.change;
|
||||||
|
|
||||||
|
import com.google.gerrit.client.Gerrit;
|
||||||
|
import com.google.gerrit.client.changes.ChangeInfo;
|
||||||
|
import com.google.gerrit.client.changes.ChangeInfo.ActionInfo;
|
||||||
|
import com.google.gerrit.client.changes.ChangeInfo.CommitInfo;
|
||||||
|
import com.google.gerrit.client.changes.ChangeInfo.RevisionInfo;
|
||||||
|
import com.google.gerrit.client.rpc.NativeMap;
|
||||||
|
import com.google.gerrit.reviewdb.client.Change;
|
||||||
|
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.ui.Button;
|
||||||
|
import com.google.gwt.user.client.ui.Composite;
|
||||||
|
import com.google.gwt.user.client.ui.FlowPanel;
|
||||||
|
|
||||||
|
import java.util.TreeSet;
|
||||||
|
|
||||||
|
class Actions extends Composite {
|
||||||
|
private static final String[] CORE = {
|
||||||
|
"abandon", "restore", "revert", "topic",
|
||||||
|
"cherrypick", "submit", "rebase"};
|
||||||
|
|
||||||
|
interface Binder extends UiBinder<FlowPanel, Actions> {}
|
||||||
|
private static Binder uiBinder = GWT.create(Binder.class);
|
||||||
|
|
||||||
|
@UiField Button cherrypick;
|
||||||
|
@UiField Button rebase;
|
||||||
|
@UiField Button revert;
|
||||||
|
@UiField Button submit;
|
||||||
|
|
||||||
|
@UiField Button abandon;
|
||||||
|
private AbandonAction abandonAction;
|
||||||
|
|
||||||
|
@UiField Button restore;
|
||||||
|
private RestoreAction restoreAction;
|
||||||
|
|
||||||
|
private Change.Id changeId;
|
||||||
|
private String revision;
|
||||||
|
private String project;
|
||||||
|
private String subject;
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
Actions() {
|
||||||
|
initWidget(uiBinder.createAndBindUi(this));
|
||||||
|
getElement().setId("change_actions");
|
||||||
|
}
|
||||||
|
|
||||||
|
void display(ChangeInfo info, String revision, boolean canSubmit) {
|
||||||
|
this.revision = revision;
|
||||||
|
|
||||||
|
boolean hasUser = Gerrit.isSignedIn();
|
||||||
|
RevisionInfo revInfo = info.revision(revision);
|
||||||
|
CommitInfo commit = revInfo.commit();
|
||||||
|
changeId = info.legacy_id();
|
||||||
|
project = info.project();
|
||||||
|
subject = commit.subject();
|
||||||
|
message = commit.message();
|
||||||
|
|
||||||
|
initChangeActions(info, hasUser);
|
||||||
|
initRevisionActions(info, revInfo, canSubmit, hasUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initChangeActions(ChangeInfo info, boolean hasUser) {
|
||||||
|
NativeMap<ActionInfo> actions = info.has_actions()
|
||||||
|
? info.actions()
|
||||||
|
: NativeMap.<ActionInfo> create();
|
||||||
|
actions.copyKeysIntoChildren("id");
|
||||||
|
|
||||||
|
abandon.setVisible(hasUser && actions.containsKey("abandon"));
|
||||||
|
restore.setVisible(hasUser && actions.containsKey("restore"));
|
||||||
|
revert.setVisible(hasUser && actions.containsKey("revert"));
|
||||||
|
|
||||||
|
if (hasUser) {
|
||||||
|
for (String id : filterNonCore(actions)) {
|
||||||
|
add(new ActionButton(changeId, actions.get(id)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initRevisionActions(ChangeInfo info, RevisionInfo revInfo,
|
||||||
|
boolean canSubmit, boolean hasUser) {
|
||||||
|
boolean hasConflict = Gerrit.getConfig().testChangeMerge()
|
||||||
|
&& !info.mergeable();
|
||||||
|
|
||||||
|
NativeMap<ActionInfo> actions = revInfo.has_actions()
|
||||||
|
? revInfo.actions()
|
||||||
|
: NativeMap.<ActionInfo> create();
|
||||||
|
actions.copyKeysIntoChildren("id");
|
||||||
|
|
||||||
|
cherrypick.setVisible(hasUser && actions.containsKey("cherrypick"));
|
||||||
|
rebase.setVisible(hasUser && actions.containsKey("rebase"));
|
||||||
|
submit.setVisible(hasUser && !hasConflict
|
||||||
|
&& canSubmit
|
||||||
|
&& actions.containsKey("submit"));
|
||||||
|
|
||||||
|
if (hasUser) {
|
||||||
|
for (String id : filterNonCore(actions)) {
|
||||||
|
add(new ActionButton(changeId, revision, actions.get(id)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void add(ActionButton b) {
|
||||||
|
((FlowPanel) getWidget()).add(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TreeSet<String> filterNonCore(NativeMap<ActionInfo> m) {
|
||||||
|
TreeSet<String> ids = new TreeSet<String>(m.keySet());
|
||||||
|
for (String id : CORE) {
|
||||||
|
ids.remove(id);
|
||||||
|
}
|
||||||
|
return ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isSubmitEnabled() {
|
||||||
|
return submit.isVisible() && submit.isEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiHandler("abandon")
|
||||||
|
void onAbandon(ClickEvent e) {
|
||||||
|
if (abandonAction == null) {
|
||||||
|
abandonAction = new AbandonAction(abandon, changeId);
|
||||||
|
}
|
||||||
|
abandonAction.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiHandler("restore")
|
||||||
|
void onRestore(ClickEvent e) {
|
||||||
|
if (restoreAction == null) {
|
||||||
|
restoreAction = new RestoreAction(restore, changeId);
|
||||||
|
}
|
||||||
|
restoreAction.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiHandler("rebase")
|
||||||
|
void onRebase(ClickEvent e) {
|
||||||
|
RebaseAction.call(changeId, revision);
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiHandler("submit")
|
||||||
|
void onSubmit(ClickEvent e) {
|
||||||
|
SubmitAction.call(changeId, revision);
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiHandler("cherrypick")
|
||||||
|
void onCherryPick(ClickEvent e) {
|
||||||
|
CherryPickAction.call(cherrypick, changeId, revision, project, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiHandler("revert")
|
||||||
|
void onRevert(ClickEvent e) {
|
||||||
|
RevertAction.call(cherrypick, changeId, revision, project, subject);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
<?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.
|
||||||
|
-->
|
||||||
|
<ui:UiBinder
|
||||||
|
xmlns:ui='urn:ui:com.google.gwt.uibinder'
|
||||||
|
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
|
||||||
|
<ui:style>
|
||||||
|
#change_actions {
|
||||||
|
padding-top: 2px;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#change_actions button {
|
||||||
|
margin: 6px 3px 0 0;
|
||||||
|
border-color: rgba(0, 0, 0, 0.1);
|
||||||
|
text-align: center;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: bold;
|
||||||
|
border: 1px solid;
|
||||||
|
cursor: pointer;
|
||||||
|
color: #444;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
background-image: -webkit-linear-gradient(top, #f5f5f5, #f1f1f1);
|
||||||
|
-webkit-border-radius: 2px;
|
||||||
|
-webkit-box-sizing: content-box;
|
||||||
|
}
|
||||||
|
#change_actions button div {
|
||||||
|
color: #444;
|
||||||
|
height: 10px;
|
||||||
|
min-width: 54px;
|
||||||
|
line-height: 10px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
#change_actions button {
|
||||||
|
color: #444;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
background-image: -webkit-linear-gradient(top, #f5f5f5, #f1f1f1);
|
||||||
|
}
|
||||||
|
#change_actions button div {color: #444;}
|
||||||
|
|
||||||
|
#change_actions button.red {
|
||||||
|
color: #d14836;
|
||||||
|
background-color: #d14836;
|
||||||
|
background-image: -webkit-linear-gradient(top, #d14836, #d14836);
|
||||||
|
}
|
||||||
|
#change_actions button.red div {color: #fff;}
|
||||||
|
|
||||||
|
#change_actions button.submit {
|
||||||
|
float: right;
|
||||||
|
color: white;
|
||||||
|
background-color: #4d90fe;
|
||||||
|
background-image: -webkit-linear-gradient(top, #4d90fe, #4d90fe);
|
||||||
|
}
|
||||||
|
#change_actions button.submit div {color: #fff;}
|
||||||
|
</ui:style>
|
||||||
|
|
||||||
|
<g:FlowPanel>
|
||||||
|
<g:Button ui:field='cherrypick' styleName=''>
|
||||||
|
<div><ui:msg>Cherry Pick</ui:msg></div>
|
||||||
|
</g:Button>
|
||||||
|
<g:Button ui:field='rebase' styleName=''>
|
||||||
|
<div><ui:msg>Rebase</ui:msg></div>
|
||||||
|
</g:Button>
|
||||||
|
<g:Button ui:field='revert' styleName=''>
|
||||||
|
<div><ui:msg>Revert</ui:msg></div>
|
||||||
|
</g:Button>
|
||||||
|
|
||||||
|
<g:Button ui:field='abandon' styleName='{style.red}'>
|
||||||
|
<div><ui:msg>Abandon</ui:msg></div>
|
||||||
|
</g:Button>
|
||||||
|
<g:Button ui:field='restore' styleName='{style.red}'>
|
||||||
|
<div><ui:msg>Restore</ui:msg></div>
|
||||||
|
</g:Button>
|
||||||
|
|
||||||
|
<g:Button ui:field='submit' styleName='{style.submit}'>
|
||||||
|
<div><ui:msg>Submit</ui:msg></div>
|
||||||
|
</g:Button>
|
||||||
|
</g:FlowPanel>
|
||||||
|
</ui:UiBinder>
|
||||||
@@ -0,0 +1,462 @@
|
|||||||
|
// 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.google.gerrit.client.change;
|
||||||
|
|
||||||
|
import com.google.gerrit.client.FormatUtil;
|
||||||
|
import com.google.gerrit.client.Gerrit;
|
||||||
|
import com.google.gerrit.client.account.AccountInfo;
|
||||||
|
import com.google.gerrit.client.changes.ChangeApi;
|
||||||
|
import com.google.gerrit.client.changes.ChangeInfo;
|
||||||
|
import com.google.gerrit.client.changes.ChangeInfo.ApprovalInfo;
|
||||||
|
import com.google.gerrit.client.changes.ChangeInfo.CommitInfo;
|
||||||
|
import com.google.gerrit.client.changes.ChangeInfo.LabelInfo;
|
||||||
|
import com.google.gerrit.client.changes.ChangeInfo.MessageInfo;
|
||||||
|
import com.google.gerrit.client.changes.ChangeInfo.RevisionInfo;
|
||||||
|
import com.google.gerrit.client.changes.StarredChanges;
|
||||||
|
import com.google.gerrit.client.changes.Util;
|
||||||
|
import com.google.gerrit.client.diff.DiffApi;
|
||||||
|
import com.google.gerrit.client.diff.FileInfo;
|
||||||
|
import com.google.gerrit.client.projects.ConfigInfoCache;
|
||||||
|
import com.google.gerrit.client.projects.ConfigInfoCache.Entry;
|
||||||
|
import com.google.gerrit.client.rpc.CallbackGroup;
|
||||||
|
import com.google.gerrit.client.rpc.GerritCallback;
|
||||||
|
import com.google.gerrit.client.rpc.NativeMap;
|
||||||
|
import com.google.gerrit.client.rpc.NativeString;
|
||||||
|
import com.google.gerrit.client.rpc.Natives;
|
||||||
|
import com.google.gerrit.client.rpc.ScreenLoadCallback;
|
||||||
|
import com.google.gerrit.client.ui.ChangeLink;
|
||||||
|
import com.google.gerrit.client.ui.CommentLinkProcessor;
|
||||||
|
import com.google.gerrit.client.ui.Screen;
|
||||||
|
import com.google.gerrit.common.PageLinks;
|
||||||
|
import com.google.gerrit.common.changes.ListChangesOption;
|
||||||
|
import com.google.gerrit.reviewdb.client.Change;
|
||||||
|
import com.google.gerrit.reviewdb.client.PatchSet;
|
||||||
|
import com.google.gerrit.reviewdb.client.Project;
|
||||||
|
import com.google.gerrit.reviewdb.client.Project.SubmitType;
|
||||||
|
import com.google.gwt.core.client.GWT;
|
||||||
|
import com.google.gwt.core.client.JsArray;
|
||||||
|
import com.google.gwt.core.client.Scheduler;
|
||||||
|
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
|
||||||
|
import com.google.gwt.dom.client.AnchorElement;
|
||||||
|
import com.google.gwt.dom.client.Element;
|
||||||
|
import com.google.gwt.event.dom.client.ChangeEvent;
|
||||||
|
import com.google.gwt.event.dom.client.ClickEvent;
|
||||||
|
import com.google.gwt.event.dom.client.KeyPressEvent;
|
||||||
|
import com.google.gwt.event.logical.shared.ValueChangeEvent;
|
||||||
|
import com.google.gwt.event.shared.HandlerRegistration;
|
||||||
|
import com.google.gwt.resources.client.CssResource;
|
||||||
|
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.rpc.AsyncCallback;
|
||||||
|
import com.google.gwt.user.client.ui.Button;
|
||||||
|
import com.google.gwt.user.client.ui.FlowPanel;
|
||||||
|
import com.google.gwt.user.client.ui.HTMLPanel;
|
||||||
|
import com.google.gwt.user.client.ui.ListBox;
|
||||||
|
import com.google.gwt.user.client.ui.ToggleButton;
|
||||||
|
import com.google.gwt.user.client.ui.UIObject;
|
||||||
|
import com.google.gwtexpui.clippy.client.CopyableLabel;
|
||||||
|
import com.google.gwtexpui.globalkey.client.GlobalKey;
|
||||||
|
import com.google.gwtexpui.globalkey.client.KeyCommand;
|
||||||
|
import com.google.gwtexpui.globalkey.client.KeyCommandSet;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class ChangeScreen2 extends Screen {
|
||||||
|
interface Binder extends UiBinder<HTMLPanel, ChangeScreen2> {}
|
||||||
|
private static Binder uiBinder = GWT.create(Binder.class);
|
||||||
|
|
||||||
|
interface Style extends CssResource {
|
||||||
|
String labelName();
|
||||||
|
String label_user();
|
||||||
|
String label_ok();
|
||||||
|
String label_reject();
|
||||||
|
String label_may();
|
||||||
|
String label_need();
|
||||||
|
String replyBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Change.Id changeId;
|
||||||
|
private String revision;
|
||||||
|
private CommentLinkProcessor commentLinkProcessor;
|
||||||
|
|
||||||
|
private KeyCommandSet keysNavigation;
|
||||||
|
private KeyCommandSet keysAction;
|
||||||
|
private List<HandlerRegistration> keys = new ArrayList<HandlerRegistration>(2);
|
||||||
|
|
||||||
|
@UiField Style style;
|
||||||
|
@UiField ToggleButton star;
|
||||||
|
@UiField Reload reload;
|
||||||
|
@UiField AnchorElement permalink;
|
||||||
|
|
||||||
|
@UiField Element reviewersText;
|
||||||
|
@UiField Element ccText;
|
||||||
|
@UiField Element changeIdText;
|
||||||
|
@UiField Element ownerText;
|
||||||
|
@UiField Element statusText;
|
||||||
|
@UiField Element projectText;
|
||||||
|
@UiField Element branchText;
|
||||||
|
@UiField Element submitActionText;
|
||||||
|
@UiField Element notMergeable;
|
||||||
|
@UiField CopyableLabel idText;
|
||||||
|
@UiField Topic topic;
|
||||||
|
@UiField Element actionText;
|
||||||
|
@UiField Element actionDate;
|
||||||
|
|
||||||
|
@UiField Actions actions;
|
||||||
|
@UiField Element revisionParent;
|
||||||
|
@UiField ListBox revisionList;
|
||||||
|
@UiField Labels labels;
|
||||||
|
@UiField CommitBox commit;
|
||||||
|
@UiField FileTable files;
|
||||||
|
@UiField FlowPanel history;
|
||||||
|
|
||||||
|
@UiField Button reply;
|
||||||
|
@UiField QuickApprove quickApprove;
|
||||||
|
private ReplyAction replyAction;
|
||||||
|
|
||||||
|
public ChangeScreen2(Change.Id changeId, String revision) {
|
||||||
|
this.changeId = changeId;
|
||||||
|
this.revision = revision != null && !revision.isEmpty() ? revision : null;
|
||||||
|
add(uiBinder.createAndBindUi(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onLoad() {
|
||||||
|
super.onLoad();
|
||||||
|
ChangeApi.detail(changeId.get(),
|
||||||
|
EnumSet.of(
|
||||||
|
ListChangesOption.ALL_REVISIONS,
|
||||||
|
ListChangesOption.CURRENT_ACTIONS),
|
||||||
|
new GerritCallback<ChangeInfo>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(ChangeInfo info) {
|
||||||
|
info.init();
|
||||||
|
loadConfigInfo(info);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onUnload() {
|
||||||
|
for (HandlerRegistration h : keys) {
|
||||||
|
h.removeHandler();
|
||||||
|
}
|
||||||
|
keys.clear();
|
||||||
|
super.onUnload();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onInitUI() {
|
||||||
|
super.onInitUI();
|
||||||
|
setHeaderVisible(false);
|
||||||
|
Resources.I.style().ensureInjected();
|
||||||
|
star.setVisible(Gerrit.isSignedIn());
|
||||||
|
labels.init(style, statusText);
|
||||||
|
|
||||||
|
keysNavigation = new KeyCommandSet(Gerrit.C.sectionNavigation());
|
||||||
|
keysNavigation.add(new KeyCommand(0, 'u', Util.C.upToChangeList()) {
|
||||||
|
@Override
|
||||||
|
public void onKeyPress(final KeyPressEvent event) {
|
||||||
|
Gerrit.displayLastChangeList();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
keysNavigation.add(new KeyCommand(0, 'R', Util.C.keyReload()) {
|
||||||
|
@Override
|
||||||
|
public void onKeyPress(final KeyPressEvent event) {
|
||||||
|
reload.reload();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
keysAction = new KeyCommandSet(Gerrit.C.sectionActions());
|
||||||
|
if (Gerrit.isSignedIn()) {
|
||||||
|
keysAction.add(new KeyCommand(0, 'r', Util.C.keyPublishComments()) {
|
||||||
|
@Override
|
||||||
|
public void onKeyPress(KeyPressEvent event) {
|
||||||
|
onReply(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
keysAction.add(new KeyCommand(0, 's', Util.C.changeTableStar()) {
|
||||||
|
@Override
|
||||||
|
public void onKeyPress(KeyPressEvent event) {
|
||||||
|
star.setValue(!star.getValue(), true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerKeys() {
|
||||||
|
super.registerKeys();
|
||||||
|
keys.add(GlobalKey.add(this, keysNavigation));
|
||||||
|
keys.add(GlobalKey.add(this, keysAction));
|
||||||
|
files.registerKeys();
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiHandler("star")
|
||||||
|
void onToggleStar(ValueChangeEvent<Boolean> e) {
|
||||||
|
StarredChanges.toggleStar(changeId, e.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiHandler("revisionList")
|
||||||
|
void onChangeRevision(ChangeEvent e) {
|
||||||
|
int idx = revisionList.getSelectedIndex();
|
||||||
|
if (0 <= idx) {
|
||||||
|
String n = revisionList.getValue(idx);
|
||||||
|
revisionList.setEnabled(false);
|
||||||
|
Gerrit.display(
|
||||||
|
PageLinks.toChange2(changeId, n),
|
||||||
|
new ChangeScreen2(changeId, n));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiHandler("reply")
|
||||||
|
void onReply(ClickEvent e) {
|
||||||
|
replyAction.onReply();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadConfigInfo(final ChangeInfo info) {
|
||||||
|
info.revisions().copyKeysIntoChildren("name");
|
||||||
|
final RevisionInfo rev = resolveRevisionToDisplay(info);
|
||||||
|
|
||||||
|
CallbackGroup group = new CallbackGroup();
|
||||||
|
loadDiff(rev, group);
|
||||||
|
loadCommit(rev, group);
|
||||||
|
ConfigInfoCache.get(info.project_name_key(),
|
||||||
|
group.add(new ScreenLoadCallback<ConfigInfoCache.Entry>(this) {
|
||||||
|
@Override
|
||||||
|
protected void preDisplay(Entry result) {
|
||||||
|
commentLinkProcessor = result.getCommentLinkProcessor();
|
||||||
|
setTheme(result.getTheme());
|
||||||
|
renderChangeInfo(info);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
group.done();
|
||||||
|
|
||||||
|
if (info.status().isOpen() && rev.name().equals(info.current_revision())) {
|
||||||
|
loadSubmitAction(rev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadDiff(final RevisionInfo rev, CallbackGroup group) {
|
||||||
|
DiffApi.list(changeId.get(),
|
||||||
|
rev.name(),
|
||||||
|
group.add(new AsyncCallback<NativeMap<FileInfo>>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(NativeMap<FileInfo> m) {
|
||||||
|
files.setRevisions(null, new PatchSet.Id(changeId, rev._number()));
|
||||||
|
files.setValue(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Throwable caught) {
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadCommit(final RevisionInfo rev, CallbackGroup group) {
|
||||||
|
ChangeApi.revision(changeId.get(), rev.name())
|
||||||
|
.view("commit")
|
||||||
|
.get(group.add(new AsyncCallback<CommitInfo>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(CommitInfo info) {
|
||||||
|
rev.set_commit(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Throwable caught) {
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadSubmitAction(final RevisionInfo rev) {
|
||||||
|
// Submit action is less important than other data.
|
||||||
|
// Defer so browser can start other requests first.
|
||||||
|
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
|
||||||
|
@Override
|
||||||
|
public void execute() {
|
||||||
|
ChangeApi.revision(changeId.get(), rev.name())
|
||||||
|
.view("submit_type")
|
||||||
|
.get(new AsyncCallback<NativeString>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(NativeString result) {
|
||||||
|
String action = result.asString();
|
||||||
|
try {
|
||||||
|
SubmitType type = Project.SubmitType.valueOf(action);
|
||||||
|
submitActionText.setInnerText(
|
||||||
|
com.google.gerrit.client.admin.Util.toLongString(type));
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
submitActionText.setInnerText(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Throwable caught) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private RevisionInfo resolveRevisionToDisplay(ChangeInfo info) {
|
||||||
|
if (revision == null) {
|
||||||
|
revision = info.current_revision();
|
||||||
|
} else if (!info.revisions().containsKey(revision)) {
|
||||||
|
JsArray<RevisionInfo> list = info.revisions().values();
|
||||||
|
for (int i = 0; i < list.length(); i++) {
|
||||||
|
RevisionInfo r = list.get(i);
|
||||||
|
if (revision.equals(String.valueOf(r._number()))) {
|
||||||
|
revision = r.name();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return info.revision(revision);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderChangeInfo(ChangeInfo info) {
|
||||||
|
statusText.setInnerText(Util.toLongString(info.status()));
|
||||||
|
boolean canSubmit = labels.set(info);
|
||||||
|
|
||||||
|
renderOwner(info);
|
||||||
|
renderReviewers(info);
|
||||||
|
renderActionTextDate(info);
|
||||||
|
renderRevisions(info);
|
||||||
|
renderHistory(info);
|
||||||
|
actions.display(info, revision, canSubmit);
|
||||||
|
|
||||||
|
star.setValue(info.starred());
|
||||||
|
permalink.setHref(ChangeLink.permalink(changeId));
|
||||||
|
changeIdText.setInnerText(String.valueOf(info.legacy_id()));
|
||||||
|
projectText.setInnerText(info.project());
|
||||||
|
branchText.setInnerText(info.branch());
|
||||||
|
idText.setText("Change-Id: " + info.change_id());
|
||||||
|
idText.setPreviewText(info.change_id());
|
||||||
|
reload.set(info);
|
||||||
|
topic.set(info);
|
||||||
|
commit.set(commentLinkProcessor, info, revision);
|
||||||
|
quickApprove.set(info, revision);
|
||||||
|
|
||||||
|
boolean hasConflict = Gerrit.getConfig().testChangeMerge() && !info.mergeable();
|
||||||
|
setVisible(notMergeable, hasConflict);
|
||||||
|
|
||||||
|
if (Gerrit.isSignedIn()) {
|
||||||
|
replyAction = new ReplyAction(info, revision, style, reply);
|
||||||
|
if (topic.canEdit()) {
|
||||||
|
keysAction.add(new KeyCommand(0, 't', Util.C.keyEditTopic()) {
|
||||||
|
@Override
|
||||||
|
public void onKeyPress(KeyPressEvent event) {
|
||||||
|
topic.onEdit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reply.setVisible(replyAction != null);
|
||||||
|
|
||||||
|
if (canSubmit && !hasConflict && actions.isSubmitEnabled()) {
|
||||||
|
statusText.setInnerText(Util.C.readyToSubmit());
|
||||||
|
} else if (canSubmit && hasConflict) {
|
||||||
|
statusText.setInnerText(Util.C.mergeConflict());
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append(Util.M.changeScreenTitleId(info.id_abbreviated()));
|
||||||
|
if (info.subject() != null) {
|
||||||
|
sb.append(": ");
|
||||||
|
sb.append(info.subject());
|
||||||
|
}
|
||||||
|
setWindowTitle(sb.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderReviewers(ChangeInfo info) {
|
||||||
|
// TODO Fix approximation of reviewers and CC list(s).
|
||||||
|
Map<Integer, AccountInfo> r = new HashMap<Integer, AccountInfo>();
|
||||||
|
Map<Integer, AccountInfo> cc = new HashMap<Integer, AccountInfo>();
|
||||||
|
for (LabelInfo label : Natives.asList(info.all_labels().values())) {
|
||||||
|
if (label.all() != null) {
|
||||||
|
for (ApprovalInfo ai : Natives.asList(label.all())) {
|
||||||
|
(ai.value() != 0 ? r : cc).put(ai._account_id(), ai);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (Integer i : r.keySet()) {
|
||||||
|
cc.remove(i);
|
||||||
|
}
|
||||||
|
reviewersText.setInnerSafeHtml(labels.formatUserList(r.values()));
|
||||||
|
ccText.setInnerSafeHtml(labels.formatUserList(cc.values()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderRevisions(ChangeInfo info) {
|
||||||
|
if (info.revisions().size() == 1) {
|
||||||
|
UIObject.setVisible(revisionParent, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsArray<RevisionInfo> list = info.revisions().values();
|
||||||
|
Collections.sort(Natives.asList(list), new Comparator<RevisionInfo>() {
|
||||||
|
@Override
|
||||||
|
public int compare(RevisionInfo a, RevisionInfo b) {
|
||||||
|
return a._number() - b._number();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
int selected = -1;
|
||||||
|
for (int i = 0; i < list.length(); i++) {
|
||||||
|
RevisionInfo r = list.get(i);
|
||||||
|
revisionList.addItem(
|
||||||
|
r._number() + ": " + r.name().substring(0, 6),
|
||||||
|
"" + r._number());
|
||||||
|
if (revision.equals(r.name())) {
|
||||||
|
selected = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (0 <= selected) {
|
||||||
|
revisionList.setSelectedIndex(selected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderOwner(ChangeInfo info) {
|
||||||
|
// TODO info card hover
|
||||||
|
ownerText.setInnerText(info.owner().name() != null
|
||||||
|
? info.owner().name()
|
||||||
|
: Gerrit.getConfig().getAnonymousCowardName());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderActionTextDate(ChangeInfo info) {
|
||||||
|
String action;
|
||||||
|
if (info.created().equals(info.updated())) {
|
||||||
|
action = Util.C.changeInfoBlockUploaded();
|
||||||
|
} else {
|
||||||
|
action = Util.C.changeInfoBlockUpdated();
|
||||||
|
}
|
||||||
|
actionText.setInnerText(action);
|
||||||
|
actionDate.setInnerText(FormatUtil.relativeFormat(info.updated()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderHistory(ChangeInfo info) {
|
||||||
|
JsArray<MessageInfo> messages = info.messages();
|
||||||
|
if (messages != null) {
|
||||||
|
for (int i = 0; i < messages.length(); i++) {
|
||||||
|
history.add(new Message(commentLinkProcessor, messages.get(i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,283 @@
|
|||||||
|
<?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.
|
||||||
|
-->
|
||||||
|
<ui:UiBinder
|
||||||
|
xmlns:ui='urn:ui:com.google.gwt.uibinder'
|
||||||
|
xmlns:c='urn:import:com.google.gerrit.client.change'
|
||||||
|
xmlns:g='urn:import:com.google.gwt.user.client.ui'
|
||||||
|
xmlns:clippy='urn:import:com.google.gwtexpui.clippy.client'>
|
||||||
|
<ui:with field='res' type='com.google.gerrit.client.change.Resources'/>
|
||||||
|
<ui:style type='com.google.gerrit.client.change.ChangeScreen2.Style'>
|
||||||
|
@eval textColor com.google.gerrit.client.Gerrit.getTheme().textColor;
|
||||||
|
@eval trimColor com.google.gerrit.client.Gerrit.getTheme().trimColor;
|
||||||
|
|
||||||
|
@def INFO_WIDTH 450px;
|
||||||
|
@def HEADER_HEIGHT 29px;
|
||||||
|
|
||||||
|
.headerLine {
|
||||||
|
position: relative;
|
||||||
|
background-color: trimColor;
|
||||||
|
height: HEADER_HEIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sectionHeader {
|
||||||
|
background-color: trimColor;
|
||||||
|
font-weight: bold;
|
||||||
|
color: textColor;
|
||||||
|
padding: 7px 10px;
|
||||||
|
}
|
||||||
|
.historyHeader {
|
||||||
|
width: 1150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idBlock {
|
||||||
|
position: relative;
|
||||||
|
width: INFO_WIDTH;
|
||||||
|
height: HEADER_HEIGHT;
|
||||||
|
background-color: trimColor;
|
||||||
|
color: textColor;
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.star {
|
||||||
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
position: absolute;
|
||||||
|
left: 5px;
|
||||||
|
top: 5px;
|
||||||
|
}
|
||||||
|
.idLine, .idStatus {
|
||||||
|
line-height: HEADER_HEIGHT;
|
||||||
|
}
|
||||||
|
.idLine {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 29px;
|
||||||
|
}
|
||||||
|
.idStatus {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 26px;
|
||||||
|
}
|
||||||
|
.reload {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: 7px;
|
||||||
|
right: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.headerButtons {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: INFO_WIDTH;
|
||||||
|
height: HEADER_HEIGHT;
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.revisionList {
|
||||||
|
position: absolute;
|
||||||
|
top: 2px;
|
||||||
|
right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.headerTable {
|
||||||
|
border-spacing: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.headerTable th {
|
||||||
|
width: 60px;
|
||||||
|
color: #444;
|
||||||
|
font-weight: normal;
|
||||||
|
vertical-align: top;
|
||||||
|
text-align: left;
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clippy div {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.infoColumn {
|
||||||
|
width: 440px;
|
||||||
|
padding-right: 10px;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
#change_infoTable {
|
||||||
|
border-spacing: 0;
|
||||||
|
width: 100%;
|
||||||
|
margin-left: 2px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notMergeable {
|
||||||
|
float: right;
|
||||||
|
font-weight: bold;
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.commitColumn {
|
||||||
|
padding: 0;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
.labels {
|
||||||
|
border-spacing: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.labelName {
|
||||||
|
color: #444;
|
||||||
|
vertical-align: top;
|
||||||
|
text-align: left;
|
||||||
|
padding-right: 5px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.label_user {white-space: nowrap;}
|
||||||
|
.label_ok {color: #060;}
|
||||||
|
.label_reject {color: #d14836;}
|
||||||
|
.label_need {color: rgb(189, 189, 67);}
|
||||||
|
.label_may {color: #fff;}
|
||||||
|
|
||||||
|
.headerButtons button {
|
||||||
|
margin: 6px 3px 0 0;
|
||||||
|
border-color: rgba(0, 0, 0, 0.1);
|
||||||
|
text-align: center;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: bold;
|
||||||
|
border: 1px solid;
|
||||||
|
cursor: pointer;
|
||||||
|
color: #444;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
background-image: -webkit-linear-gradient(top, #f5f5f5, #f1f1f1);
|
||||||
|
-webkit-border-radius: 2px;
|
||||||
|
-webkit-box-sizing: content-box;
|
||||||
|
}
|
||||||
|
.headerButtons button div {
|
||||||
|
color: #444;
|
||||||
|
height: 10px;
|
||||||
|
min-width: 54px;
|
||||||
|
line-height: 10px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
button.quickApprove {
|
||||||
|
color: #d14836;
|
||||||
|
background-color: #d14836;
|
||||||
|
background-image: -webkit-linear-gradient(top, #d14836, #d14836);
|
||||||
|
}
|
||||||
|
button.quickApprove div { color: #fff; }
|
||||||
|
|
||||||
|
.replyBox {
|
||||||
|
background-color: trimColor;
|
||||||
|
}
|
||||||
|
</ui:style>
|
||||||
|
|
||||||
|
<g:HTMLPanel>
|
||||||
|
<div class='{style.headerLine}'>
|
||||||
|
<div class='{style.idBlock}'>
|
||||||
|
<c:StarIcon ui:field='star' styleName='{style.star}'/>
|
||||||
|
<div class='{style.idLine}'>
|
||||||
|
<ui:msg>Change <span ui:field='changeIdText'/> by <span ui:field='ownerText'/></ui:msg>
|
||||||
|
</div>
|
||||||
|
<div ui:field='statusText' class='{style.idStatus}'/>
|
||||||
|
<a ui:field='permalink' class='{style.reload}'>
|
||||||
|
<c:Reload ui:field='reload'
|
||||||
|
title='Reload the change (Shortcut: R)'>
|
||||||
|
<ui:attribute name='title'/>
|
||||||
|
</c:Reload>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class='{style.headerButtons}'>
|
||||||
|
<g:Button ui:field='reply'
|
||||||
|
styleName=''
|
||||||
|
title='Reply and score (Shortcut: r)'>
|
||||||
|
<ui:attribute name='title'/>
|
||||||
|
<div><ui:msg>Reply…</ui:msg></div>
|
||||||
|
</g:Button>
|
||||||
|
<c:QuickApprove ui:field='quickApprove'
|
||||||
|
styleName='{style.quickApprove}'
|
||||||
|
title='Apply score with one click'>
|
||||||
|
<ui:attribute name='title'/>
|
||||||
|
</c:QuickApprove>
|
||||||
|
</div>
|
||||||
|
<div class='{style.revisionList}' ui:field='revisionParent'>
|
||||||
|
<ui:msg>Revision <g:ListBox ui:field='revisionList'/></ui:msg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class='{style.headerTable}'>
|
||||||
|
<tr>
|
||||||
|
<td class='{style.infoColumn}'>
|
||||||
|
<table id='change_infoTable'>
|
||||||
|
<tr>
|
||||||
|
<th><ui:msg>Reviewers</ui:msg></th>
|
||||||
|
<td ui:field='reviewersText'/>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th><ui:msg>CC</ui:msg></th>
|
||||||
|
<td ui:field='ccText'/>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th><ui:msg>Project</ui:msg></th>
|
||||||
|
<td ui:field='projectText'/>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th><ui:msg>Branch</ui:msg></th>
|
||||||
|
<td ui:field='branchText'/>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th><ui:msg>Strategy</ui:msg></th>
|
||||||
|
<td>
|
||||||
|
<span ui:field='submitActionText'/>
|
||||||
|
<div ui:field='notMergeable' class='{style.notMergeable}'>
|
||||||
|
<ui:msg>Cannot Merge</ui:msg>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan='2'><c:Actions ui:field='actions'/></td></tr>
|
||||||
|
<tr>
|
||||||
|
<th ui:field='actionText'/>
|
||||||
|
<td ui:field='actionDate'/>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th><ui:msg>Id</ui:msg></th>
|
||||||
|
<td><clippy:CopyableLabel styleName='{style.clippy}' ui:field='idText'/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th><ui:msg>Topic</ui:msg></th>
|
||||||
|
<td><c:Topic ui:field='topic'/></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr/>
|
||||||
|
<c:Labels ui:field='labels' styleName='{style.labels}'/>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class='{style.commitColumn}'>
|
||||||
|
<c:CommitBox ui:field='commit'/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class='{style.sectionHeader}'
|
||||||
|
><ui:msg>Files</ui:msg></div>
|
||||||
|
<c:FileTable ui:field='files'/>
|
||||||
|
|
||||||
|
<div class='{style.sectionHeader} {style.historyHeader}'
|
||||||
|
><ui:msg>History</ui:msg></div>
|
||||||
|
<g:FlowPanel ui:field='history'/>
|
||||||
|
</g:HTMLPanel>
|
||||||
|
</ui:UiBinder>
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
// 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.google.gerrit.client.change;
|
||||||
|
|
||||||
|
import com.google.gerrit.client.Gerrit;
|
||||||
|
import com.google.gerrit.client.changes.ChangeApi;
|
||||||
|
import com.google.gerrit.client.changes.ChangeInfo;
|
||||||
|
import com.google.gerrit.client.changes.Util;
|
||||||
|
import com.google.gerrit.client.rpc.GerritCallback;
|
||||||
|
import com.google.gerrit.client.ui.CherryPickDialog;
|
||||||
|
import com.google.gerrit.common.PageLinks;
|
||||||
|
import com.google.gerrit.reviewdb.client.Change;
|
||||||
|
import com.google.gerrit.reviewdb.client.Project;
|
||||||
|
import com.google.gwt.user.client.ui.Button;
|
||||||
|
|
||||||
|
class CherryPickAction {
|
||||||
|
static void call(Button b, final Change.Id id, final String revision,
|
||||||
|
String project, final String commitMessage) {
|
||||||
|
// TODO Replace CherryPickDialog with a nicer looking display.
|
||||||
|
b.setEnabled(false);
|
||||||
|
new CherryPickDialog(b, new Project.NameKey(project)) {
|
||||||
|
{
|
||||||
|
sendButton.setText(Util.C.buttonCherryPickChangeSend());
|
||||||
|
message.setText(Util.M.cherryPickedChangeDefaultMessage(
|
||||||
|
commitMessage.trim(),
|
||||||
|
revision));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSend() {
|
||||||
|
ChangeApi.cherrypick(id.get(), revision,
|
||||||
|
getDestinationBranch(),
|
||||||
|
getMessageText(),
|
||||||
|
new GerritCallback<ChangeInfo>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(ChangeInfo result) {
|
||||||
|
sent = true;
|
||||||
|
hide();
|
||||||
|
Gerrit.display(PageLinks.toChange2(result.legacy_id()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Throwable caught) {
|
||||||
|
enableButtons(true);
|
||||||
|
super.onFailure(caught);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}.center();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
// 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.google.gerrit.client.change;
|
||||||
|
|
||||||
|
import com.google.gerrit.client.FormatUtil;
|
||||||
|
import com.google.gerrit.client.Gerrit;
|
||||||
|
import com.google.gerrit.client.GitwebLink;
|
||||||
|
import com.google.gerrit.client.changes.ChangeInfo;
|
||||||
|
import com.google.gerrit.client.changes.ChangeInfo.CommitInfo;
|
||||||
|
import com.google.gerrit.client.changes.ChangeInfo.GitPerson;
|
||||||
|
import com.google.gerrit.client.changes.ChangeInfo.RevisionInfo;
|
||||||
|
import com.google.gerrit.client.ui.CommentLinkProcessor;
|
||||||
|
import com.google.gwt.core.client.GWT;
|
||||||
|
import com.google.gwt.dom.client.AnchorElement;
|
||||||
|
import com.google.gwt.dom.client.Element;
|
||||||
|
import com.google.gwt.uibinder.client.UiBinder;
|
||||||
|
import com.google.gwt.uibinder.client.UiField;
|
||||||
|
import com.google.gwt.user.client.ui.Composite;
|
||||||
|
import com.google.gwt.user.client.ui.HTMLPanel;
|
||||||
|
import com.google.gwt.user.client.ui.UIObject;
|
||||||
|
import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
|
||||||
|
|
||||||
|
class CommitBox extends Composite {
|
||||||
|
interface Binder extends UiBinder<HTMLPanel, CommitBox> {}
|
||||||
|
private static Binder uiBinder = GWT.create(Binder.class);
|
||||||
|
|
||||||
|
@UiField Element commitName;
|
||||||
|
@UiField AnchorElement browserLink;
|
||||||
|
@UiField Element authorNameEmail;
|
||||||
|
@UiField Element authorDate;
|
||||||
|
@UiField Element committerNameEmail;
|
||||||
|
@UiField Element committerDate;
|
||||||
|
@UiField Element commitMessageText;
|
||||||
|
|
||||||
|
CommitBox() {
|
||||||
|
initWidget(uiBinder.createAndBindUi(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
void set(CommentLinkProcessor commentLinkProcessor,
|
||||||
|
ChangeInfo change,
|
||||||
|
String revision) {
|
||||||
|
RevisionInfo revInfo = change.revision(revision);
|
||||||
|
CommitInfo commit = revInfo.commit();
|
||||||
|
|
||||||
|
commitName.setInnerText(revision);
|
||||||
|
format(commit.author(), authorNameEmail, authorDate);
|
||||||
|
format(commit.committer(), committerNameEmail, committerDate);
|
||||||
|
commitMessageText.setInnerSafeHtml(commentLinkProcessor.apply(
|
||||||
|
new SafeHtmlBuilder().append(commit.message()).linkify()));
|
||||||
|
|
||||||
|
GitwebLink gw = Gerrit.getGitwebLink();
|
||||||
|
if (gw != null && gw.canLink(revInfo)) {
|
||||||
|
browserLink.setInnerText(gw.getLinkName());
|
||||||
|
browserLink.setHref(gw.toRevision(change.project(), revision));
|
||||||
|
} else {
|
||||||
|
UIObject.setVisible(browserLink, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void format(GitPerson person, Element name, Element date) {
|
||||||
|
name.setInnerText(person.name() + " <" + person.email() + ">");
|
||||||
|
date.setInnerText(FormatUtil.mediumFormat(person.date()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
<?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.
|
||||||
|
-->
|
||||||
|
<ui:UiBinder
|
||||||
|
xmlns:ui='urn:ui:com.google.gwt.uibinder'
|
||||||
|
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
|
||||||
|
<ui:style>
|
||||||
|
.commitHeader {
|
||||||
|
border-spacing: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 564px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.commitHeader th { width: 70px; }
|
||||||
|
.commitHeader td { white-space: pre; }
|
||||||
|
|
||||||
|
.commitMessageBox { margin: 2px; }
|
||||||
|
.commitMessage {
|
||||||
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||||
|
border: 1px solid white;
|
||||||
|
background-color: white;
|
||||||
|
font-family: monospace;
|
||||||
|
white-space: pre;
|
||||||
|
width: 47em;
|
||||||
|
}
|
||||||
|
</ui:style>
|
||||||
|
<g:HTMLPanel>
|
||||||
|
<table class='{style.commitHeader}'>
|
||||||
|
<tr>
|
||||||
|
<th><ui:msg>Commit</ui:msg></th>
|
||||||
|
<td ui:field='commitName'/>
|
||||||
|
<td><a ui:field='browserLink' href=""/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th><ui:msg>Author</ui:msg></th>
|
||||||
|
<td ui:field='authorNameEmail'/>
|
||||||
|
<td ui:field='authorDate'/>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th><ui:msg>Committer</ui:msg></th>
|
||||||
|
<td ui:field='committerNameEmail'/>
|
||||||
|
<td ui:field='committerDate'/>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class='{style.commitMessageBox}'>
|
||||||
|
<div class='{style.commitMessage}' ui:field='commitMessageText'/>
|
||||||
|
</div>
|
||||||
|
</g:HTMLPanel>
|
||||||
|
</ui:UiBinder>
|
||||||
@@ -0,0 +1,354 @@
|
|||||||
|
// 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.google.gerrit.client.change;
|
||||||
|
|
||||||
|
import com.google.gerrit.client.Gerrit;
|
||||||
|
import com.google.gerrit.client.changes.Util;
|
||||||
|
import com.google.gerrit.client.diff.FileInfo;
|
||||||
|
import com.google.gerrit.client.rpc.NativeMap;
|
||||||
|
import com.google.gerrit.client.rpc.Natives;
|
||||||
|
import com.google.gerrit.client.ui.NavigationTable;
|
||||||
|
import com.google.gerrit.reviewdb.client.Change;
|
||||||
|
import com.google.gerrit.reviewdb.client.Patch;
|
||||||
|
import com.google.gerrit.reviewdb.client.PatchSet;
|
||||||
|
import com.google.gwt.core.client.GWT;
|
||||||
|
import com.google.gwt.core.client.JsArray;
|
||||||
|
import com.google.gwt.core.client.Scheduler;
|
||||||
|
import com.google.gwt.core.client.Scheduler.RepeatingCommand;
|
||||||
|
import com.google.gwt.event.dom.client.KeyCodes;
|
||||||
|
import com.google.gwt.resources.client.ClientBundle;
|
||||||
|
import com.google.gwt.resources.client.CssResource;
|
||||||
|
import com.google.gwt.user.client.ui.FlowPanel;
|
||||||
|
import com.google.gwtexpui.progress.client.ProgressBar;
|
||||||
|
import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
|
||||||
|
import com.google.gwtorm.client.KeyUtil;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
|
class FileTable extends FlowPanel {
|
||||||
|
private static final FileTableResources R = GWT
|
||||||
|
.create(FileTableResources.class);
|
||||||
|
|
||||||
|
interface FileTableResources extends ClientBundle {
|
||||||
|
@Source("file_table.css")
|
||||||
|
FileTableCss css();
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FileTableCss extends CssResource {
|
||||||
|
String pointer();
|
||||||
|
String pathColumn();
|
||||||
|
String deltaColumn1();
|
||||||
|
String deltaColumn2();
|
||||||
|
String inserted();
|
||||||
|
String deleted();
|
||||||
|
}
|
||||||
|
|
||||||
|
private PatchSet.Id base;
|
||||||
|
private PatchSet.Id curr;
|
||||||
|
private MyTable table;
|
||||||
|
private boolean register;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onLoad() {
|
||||||
|
super.onLoad();
|
||||||
|
R.css().ensureInjected();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setRevisions(PatchSet.Id base, PatchSet.Id curr) {
|
||||||
|
this.base = base;
|
||||||
|
this.curr = curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setValue(NativeMap<FileInfo> fileMap) {
|
||||||
|
JsArray<FileInfo> list = fileMap.values();
|
||||||
|
Collections.sort(Natives.asList(list), new Comparator<FileInfo>() {
|
||||||
|
@Override
|
||||||
|
public int compare(FileInfo a, FileInfo b) {
|
||||||
|
if (Patch.COMMIT_MSG.equals(a.path())) {
|
||||||
|
return -1;
|
||||||
|
} else if (Patch.COMMIT_MSG.equals(b.path())) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return a.path().compareTo(b.path());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
DisplayCommand cmd = new DisplayCommand(list);
|
||||||
|
if (cmd.execute()) {
|
||||||
|
cmd.showProgressBar();
|
||||||
|
Scheduler.get().scheduleIncremental(cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void registerKeys() {
|
||||||
|
register = true;
|
||||||
|
|
||||||
|
if (table != null) {
|
||||||
|
table.setRegisterKeys(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setTable(MyTable table) {
|
||||||
|
clear();
|
||||||
|
add(table);
|
||||||
|
this.table = table;
|
||||||
|
if (register) {
|
||||||
|
table.setRegisterKeys(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String url(FileInfo info) {
|
||||||
|
// TODO(sop): Switch to Dispatcher.toPatchSideBySide.
|
||||||
|
Change.Id c = curr.getParentKey();
|
||||||
|
StringBuilder p = new StringBuilder();
|
||||||
|
p.append("/c/").append(c).append('/');
|
||||||
|
if (base != null) {
|
||||||
|
p.append(base.get()).append("..");
|
||||||
|
}
|
||||||
|
p.append(curr.get()).append('/').append(KeyUtil.encode(info.path()));
|
||||||
|
p.append(info.binary() ? ",unified" : ",codemirror");
|
||||||
|
return p.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class MyTable extends NavigationTable<FileInfo> {
|
||||||
|
private final JsArray<FileInfo> list;
|
||||||
|
|
||||||
|
MyTable(JsArray<FileInfo> list) {
|
||||||
|
this.list = list;
|
||||||
|
table.setWidth("");
|
||||||
|
|
||||||
|
keysNavigation.add(new PrevKeyCommand(0, 'k', Util.C.patchTablePrev()));
|
||||||
|
keysNavigation.add(new NextKeyCommand(0, 'j', Util.C.patchTableNext()));
|
||||||
|
keysNavigation.add(new OpenKeyCommand(0, 'o', Util.C.patchTableOpenDiff()));
|
||||||
|
keysNavigation.add(new OpenKeyCommand(0, KeyCodes.KEY_ENTER,
|
||||||
|
Util.C.patchTableOpenDiff()));
|
||||||
|
|
||||||
|
setSavePointerId(
|
||||||
|
(base != null ? base.toString() + ".." : "")
|
||||||
|
+ curr.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Object getRowItemKey(FileInfo item) {
|
||||||
|
return item.path();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected FileInfo getRowItem(int row) {
|
||||||
|
if (1 <= row && row <= list.length()) {
|
||||||
|
return list.get(row - 1);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onOpenRow(int row) {
|
||||||
|
if (1 <= row && row <= list.length()) {
|
||||||
|
Gerrit.display(url(list.get(row - 1)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class DisplayCommand implements RepeatingCommand {
|
||||||
|
private final SafeHtmlBuilder sb = new SafeHtmlBuilder();
|
||||||
|
private final MyTable table;
|
||||||
|
private final JsArray<FileInfo> list;
|
||||||
|
private boolean attached;
|
||||||
|
private int row;
|
||||||
|
private double start;
|
||||||
|
private ProgressBar meter;
|
||||||
|
|
||||||
|
private int inserted;
|
||||||
|
private int deleted;
|
||||||
|
|
||||||
|
private DisplayCommand(JsArray<FileInfo> list) {
|
||||||
|
this.table = new MyTable(list);
|
||||||
|
this.list = list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean execute() {
|
||||||
|
boolean attachedNow = isAttached();
|
||||||
|
if (!attached && attachedNow) {
|
||||||
|
// Remember that we have been attached at least once. If
|
||||||
|
// later we find we aren't attached we should stop running.
|
||||||
|
attached = true;
|
||||||
|
} else if (attached && !attachedNow) {
|
||||||
|
// If the user navigated away, we aren't in the DOM anymore.
|
||||||
|
// Don't continue to render.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
start = System.currentTimeMillis();
|
||||||
|
if (row == 0) {
|
||||||
|
header(sb);
|
||||||
|
computeInsertedDeleted();
|
||||||
|
}
|
||||||
|
while (row < list.length()) {
|
||||||
|
render(sb, list.get(row));
|
||||||
|
if ((++row % 10) == 0 && longRunning()) {
|
||||||
|
updateMeter();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
footer(sb);
|
||||||
|
table.resetHtml(sb);
|
||||||
|
table.finishDisplay();
|
||||||
|
setTable(table);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void computeInsertedDeleted() {
|
||||||
|
inserted = 0;
|
||||||
|
deleted = 0;
|
||||||
|
for (int i = 0; i < list.length(); i++) {
|
||||||
|
FileInfo info = list.get(i);
|
||||||
|
if (!Patch.COMMIT_MSG.equals(info.path()) && !info.binary()) {
|
||||||
|
inserted += info.lines_inserted();
|
||||||
|
deleted += info.lines_deleted();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void showProgressBar() {
|
||||||
|
if (meter == null) {
|
||||||
|
meter = new ProgressBar(Util.M.loadingPatchSet(curr.get()));
|
||||||
|
FileTable.this.clear();
|
||||||
|
FileTable.this.add(meter);
|
||||||
|
}
|
||||||
|
updateMeter();
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateMeter() {
|
||||||
|
if (meter != null) {
|
||||||
|
int n = list.length();
|
||||||
|
meter.setValue((100 * row) / n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean longRunning() {
|
||||||
|
return System.currentTimeMillis() - start > 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void header(SafeHtmlBuilder sb) {
|
||||||
|
sb.openTr();
|
||||||
|
sb.openTh().setStyleName(Gerrit.RESOURCES.css().iconCell()).closeTh();
|
||||||
|
sb.openTh().append(Util.C.patchTableColumnName()).closeTh();
|
||||||
|
sb.openTh()
|
||||||
|
.setAttribute("colspan", 2)
|
||||||
|
.append(Util.C.patchTableColumnSize())
|
||||||
|
.closeTh();
|
||||||
|
sb.closeTr();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void render(SafeHtmlBuilder sb, FileInfo info) {
|
||||||
|
sb.openTr();
|
||||||
|
sb.openTd().setStyleName(R.css().pointer()).closeTd();
|
||||||
|
columnPath(sb, info);
|
||||||
|
columnDelta1(sb, info);
|
||||||
|
columnDelta2(sb, info);
|
||||||
|
sb.closeTr();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void columnPath(SafeHtmlBuilder sb, FileInfo info) {
|
||||||
|
// TODO(sop): Use JS to link, avoiding early URL update.
|
||||||
|
sb.openTd()
|
||||||
|
.setStyleName(R.css().pathColumn())
|
||||||
|
.openAnchor()
|
||||||
|
.setAttribute("href", "#" + url(info))
|
||||||
|
.append(Patch.COMMIT_MSG.equals(info.path())
|
||||||
|
? Util.C.commitMessage()
|
||||||
|
: info.path())
|
||||||
|
.closeAnchor()
|
||||||
|
.closeTd();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void columnDelta1(SafeHtmlBuilder sb, FileInfo info) {
|
||||||
|
sb.openTd().setStyleName(R.css().deltaColumn1());
|
||||||
|
if (!Patch.COMMIT_MSG.equals(info.path()) && !info.binary()) {
|
||||||
|
sb.append(info.lines_inserted() - info.lines_deleted());
|
||||||
|
}
|
||||||
|
sb.closeTd();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void columnDelta2(SafeHtmlBuilder sb, FileInfo info) {
|
||||||
|
sb.openTd().setStyleName(R.css().deltaColumn2());
|
||||||
|
if (!Patch.COMMIT_MSG.equals(info.path()) && !info.binary()
|
||||||
|
&& (info.lines_inserted() != 0 || info.lines_deleted() != 0)) {
|
||||||
|
int w = 80;
|
||||||
|
int t = inserted + deleted;
|
||||||
|
int i = Math.max(5, (int) (((double) w) * info.lines_inserted() / t));
|
||||||
|
int d = Math.max(5, (int) (((double) w) * info.lines_deleted() / t));
|
||||||
|
|
||||||
|
sb.setAttribute(
|
||||||
|
"title",
|
||||||
|
Util.M.patchTableSize_LongModify(info.lines_inserted(),
|
||||||
|
info.lines_deleted()));
|
||||||
|
|
||||||
|
if (0 < info.lines_inserted()) {
|
||||||
|
sb.openDiv()
|
||||||
|
.setStyleName(R.css().inserted())
|
||||||
|
.setAttribute("style", "width:" + i + "px")
|
||||||
|
.closeDiv();
|
||||||
|
}
|
||||||
|
if (0 < info.lines_deleted()) {
|
||||||
|
sb.openDiv()
|
||||||
|
.setStyleName(R.css().deleted())
|
||||||
|
.setAttribute("style", "width:" + d + "px")
|
||||||
|
.closeDiv();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sb.closeTd();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void footer(SafeHtmlBuilder sb) {
|
||||||
|
sb.openTr();
|
||||||
|
sb.openTd().setStyleName(Gerrit.RESOURCES.css().iconCell()).closeTd();
|
||||||
|
sb.openTd().closeTd(); // path
|
||||||
|
|
||||||
|
// delta1
|
||||||
|
sb.openTh().setStyleName(R.css().deltaColumn1())
|
||||||
|
.append(Util.M.patchTableSize_Modify(inserted, deleted))
|
||||||
|
.closeTh();
|
||||||
|
|
||||||
|
// delta2
|
||||||
|
sb.openTh().setStyleName(R.css().deltaColumn2());
|
||||||
|
int w = 80;
|
||||||
|
int t = inserted + deleted;
|
||||||
|
int i = Math.max(1, (int) (((double) w) * inserted / t));
|
||||||
|
int d = Math.max(1, (int) (((double) w) * deleted / t));
|
||||||
|
if (i + d > w && i > d) {
|
||||||
|
i = w - d;
|
||||||
|
} else if (i + d > w && d > i) {
|
||||||
|
d = w - i;
|
||||||
|
}
|
||||||
|
if (0 < inserted) {
|
||||||
|
sb.openDiv()
|
||||||
|
.setStyleName(R.css().inserted())
|
||||||
|
.setAttribute("style", "width:" + i + "px")
|
||||||
|
.closeDiv();
|
||||||
|
}
|
||||||
|
if (0 < deleted) {
|
||||||
|
sb.openDiv()
|
||||||
|
.setStyleName(R.css().deleted())
|
||||||
|
.setAttribute("style", "width:" + d + "px")
|
||||||
|
.closeDiv();
|
||||||
|
}
|
||||||
|
sb.closeTh();
|
||||||
|
|
||||||
|
sb.closeTr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,211 @@
|
|||||||
|
// 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.google.gerrit.client.change;
|
||||||
|
|
||||||
|
import com.google.gerrit.client.account.AccountInfo;
|
||||||
|
import com.google.gerrit.client.changes.ChangeInfo;
|
||||||
|
import com.google.gerrit.client.changes.ChangeInfo.ApprovalInfo;
|
||||||
|
import com.google.gerrit.client.changes.ChangeInfo.LabelInfo;
|
||||||
|
import com.google.gerrit.client.rpc.Natives;
|
||||||
|
import com.google.gerrit.common.data.LabelValue;
|
||||||
|
import com.google.gerrit.reviewdb.client.Change;
|
||||||
|
import com.google.gwt.dom.client.Element;
|
||||||
|
import com.google.gwt.user.client.ui.Grid;
|
||||||
|
import com.google.gwt.user.client.ui.Widget;
|
||||||
|
import com.google.gwtexpui.safehtml.client.SafeHtml;
|
||||||
|
import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/** Displays a table of label and reviewer scores. */
|
||||||
|
class Labels extends Grid {
|
||||||
|
private ChangeScreen2.Style style;
|
||||||
|
private Element statusText;
|
||||||
|
|
||||||
|
void init(ChangeScreen2.Style style, Element statusText) {
|
||||||
|
this.style = style;
|
||||||
|
this.statusText = statusText;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean set(ChangeInfo info) {
|
||||||
|
List<String> names = new ArrayList<String>(info.labels());
|
||||||
|
Collections.sort(names);
|
||||||
|
|
||||||
|
boolean canSubmit = info.status().isOpen();
|
||||||
|
resize(names.size(), 2);
|
||||||
|
|
||||||
|
for (int row = 0; row < names.size(); row++) {
|
||||||
|
String name = names.get(row);
|
||||||
|
LabelInfo label = info.label(name);
|
||||||
|
setText(row, 0, name);
|
||||||
|
if (label.all() != null) {
|
||||||
|
setWidget(row, 1, renderUsers(label));
|
||||||
|
}
|
||||||
|
getCellFormatter().setStyleName(row, 0, style.labelName());
|
||||||
|
getCellFormatter().addStyleName(row, 0, getStyleForLabel(label));
|
||||||
|
|
||||||
|
if (canSubmit && info.status() == Change.Status.NEW) {
|
||||||
|
switch (label.status()) {
|
||||||
|
case NEED:
|
||||||
|
statusText.setInnerText("Needs " + name);
|
||||||
|
canSubmit = false;
|
||||||
|
break;
|
||||||
|
case REJECT:
|
||||||
|
case IMPOSSIBLE:
|
||||||
|
statusText.setInnerText("Not " + name);
|
||||||
|
canSubmit = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return canSubmit;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Widget renderUsers(LabelInfo label) {
|
||||||
|
Map<Integer, List<ApprovalInfo>> m = new HashMap<Integer, List<ApprovalInfo>>(4);
|
||||||
|
int approved = 0, rejected = 0;
|
||||||
|
|
||||||
|
for (ApprovalInfo ai : Natives.asList(label.all())) {
|
||||||
|
if (ai.value() != 0) {
|
||||||
|
List<ApprovalInfo> l = m.get(Integer.valueOf(ai.value()));
|
||||||
|
if (l == null) {
|
||||||
|
l = new ArrayList<ApprovalInfo>(label.all().length());
|
||||||
|
m.put(Integer.valueOf(ai.value()), l);
|
||||||
|
}
|
||||||
|
l.add(ai);
|
||||||
|
|
||||||
|
if (isRejected(label, ai)) {
|
||||||
|
rejected = ai.value();
|
||||||
|
} else if (isApproved(label, ai)) {
|
||||||
|
approved = ai.value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SafeHtmlBuilder html = new SafeHtmlBuilder();
|
||||||
|
for (Integer v : sort(m.keySet(), approved, rejected)) {
|
||||||
|
if (!html.isEmpty()) {
|
||||||
|
html.append("; ");
|
||||||
|
}
|
||||||
|
|
||||||
|
String val = LabelValue.formatValue(v.shortValue());
|
||||||
|
html.openSpan();
|
||||||
|
html.setAttribute("title", label.value_text(val));
|
||||||
|
if (v.intValue() == approved) {
|
||||||
|
html.setStyleName(style.label_ok());
|
||||||
|
} else if (v.intValue() == rejected) {
|
||||||
|
html.setStyleName(style.label_reject());
|
||||||
|
}
|
||||||
|
html.append(val).append(" ");
|
||||||
|
html.append(formatUserList(m.get(v)));
|
||||||
|
html.closeSpan();
|
||||||
|
}
|
||||||
|
return html.toBlockWidget();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Integer> sort(Set<Integer> keySet, int a, int b) {
|
||||||
|
List<Integer> r = new ArrayList<Integer>(keySet);
|
||||||
|
Collections.sort(r);
|
||||||
|
if (keySet.contains(a)) {
|
||||||
|
r.remove(Integer.valueOf(a));
|
||||||
|
r.add(0, a);
|
||||||
|
} else if (keySet.contains(b)) {
|
||||||
|
r.remove(Integer.valueOf(b));
|
||||||
|
r.add(0, b);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isApproved(LabelInfo label, ApprovalInfo ai) {
|
||||||
|
return label.approved() != null
|
||||||
|
&& label.approved()._account_id() == ai._account_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isRejected(LabelInfo label, ApprovalInfo ai) {
|
||||||
|
return label.rejected() != null
|
||||||
|
&& label.rejected()._account_id() == ai._account_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getStyleForLabel(LabelInfo label) {
|
||||||
|
switch (label.status()) {
|
||||||
|
case OK:
|
||||||
|
return style.label_ok();
|
||||||
|
case NEED:
|
||||||
|
return style.label_need();
|
||||||
|
case REJECT:
|
||||||
|
case IMPOSSIBLE:
|
||||||
|
return style.label_reject();
|
||||||
|
default:
|
||||||
|
case MAY:
|
||||||
|
return style.label_may();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SafeHtml formatUserList(Collection<? extends AccountInfo> in) {
|
||||||
|
List<AccountInfo> users = new ArrayList<AccountInfo>(in);
|
||||||
|
Collections.sort(users, new Comparator<AccountInfo>() {
|
||||||
|
@Override
|
||||||
|
public int compare(AccountInfo a, AccountInfo b) {
|
||||||
|
String as = name(a);
|
||||||
|
String bs = name(b);
|
||||||
|
if (as.isEmpty()) {
|
||||||
|
return 1;
|
||||||
|
} else if (bs.isEmpty()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return as.compareTo(bs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String name(AccountInfo a) {
|
||||||
|
if (a.name() != null) {
|
||||||
|
return a.name();
|
||||||
|
} else if (a.email() != null) {
|
||||||
|
return a.email();
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
SafeHtmlBuilder html = new SafeHtmlBuilder();
|
||||||
|
Iterator<? extends AccountInfo> itr = users.iterator();
|
||||||
|
while (itr.hasNext()) {
|
||||||
|
AccountInfo ai = itr.next();
|
||||||
|
html.openSpan();
|
||||||
|
html.setStyleName(style.label_user());
|
||||||
|
if (ai.name() != null) {
|
||||||
|
html.append(ai.name());
|
||||||
|
} else if (ai.email() != null) {
|
||||||
|
html.append(ai.email());
|
||||||
|
} else {
|
||||||
|
html.append(ai._account_id());
|
||||||
|
}
|
||||||
|
html.closeSpan();
|
||||||
|
if (itr.hasNext()) {
|
||||||
|
html.append(", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
// 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.google.gerrit.client.change;
|
||||||
|
|
||||||
|
import com.google.gerrit.client.AvatarImage;
|
||||||
|
import com.google.gerrit.client.FormatUtil;
|
||||||
|
import com.google.gerrit.client.Gerrit;
|
||||||
|
import com.google.gerrit.client.changes.ChangeInfo.MessageInfo;
|
||||||
|
import com.google.gerrit.client.changes.Util;
|
||||||
|
import com.google.gerrit.client.ui.CommentLinkProcessor;
|
||||||
|
import com.google.gwt.core.client.GWT;
|
||||||
|
import com.google.gwt.dom.client.Element;
|
||||||
|
import com.google.gwt.event.dom.client.ClickEvent;
|
||||||
|
import com.google.gwt.event.dom.client.ClickHandler;
|
||||||
|
import com.google.gwt.resources.client.CssResource;
|
||||||
|
import com.google.gwt.uibinder.client.UiBinder;
|
||||||
|
import com.google.gwt.uibinder.client.UiField;
|
||||||
|
import com.google.gwt.user.client.ui.Composite;
|
||||||
|
import com.google.gwt.user.client.ui.HTMLPanel;
|
||||||
|
import com.google.gwt.user.client.ui.UIObject;
|
||||||
|
import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
|
||||||
|
|
||||||
|
class Message extends Composite {
|
||||||
|
interface Binder extends UiBinder<HTMLPanel, Message> {}
|
||||||
|
private static Binder uiBinder = GWT.create(Binder.class);
|
||||||
|
|
||||||
|
static interface Style extends CssResource {
|
||||||
|
String closed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiField Style style;
|
||||||
|
@UiField Element name;
|
||||||
|
@UiField Element summary;
|
||||||
|
@UiField Element date;
|
||||||
|
@UiField Element message;
|
||||||
|
|
||||||
|
@UiField(provided = true)
|
||||||
|
AvatarImage avatar;
|
||||||
|
|
||||||
|
Message(CommentLinkProcessor clp, MessageInfo info) {
|
||||||
|
if (info.author() != null) {
|
||||||
|
avatar = new AvatarImage(info.author(), 26);
|
||||||
|
avatar.setSize("", "");
|
||||||
|
} else {
|
||||||
|
avatar = new AvatarImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
initWidget(uiBinder.createAndBindUi(this));
|
||||||
|
addDomHandler(new ClickHandler() {
|
||||||
|
@Override
|
||||||
|
public void onClick(ClickEvent event) {
|
||||||
|
setOpen(!isOpen());
|
||||||
|
}
|
||||||
|
}, ClickEvent.getType());
|
||||||
|
|
||||||
|
name.setInnerText(authorName(info));
|
||||||
|
date.setInnerText(FormatUtil.shortFormatDayTime(info.date()));
|
||||||
|
if (info.message() != null) {
|
||||||
|
String msg = info.message().trim();
|
||||||
|
summary.setInnerText(msg);
|
||||||
|
message.setInnerSafeHtml(clp.apply(
|
||||||
|
new SafeHtmlBuilder().append(msg).wikify()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isOpen() {
|
||||||
|
return UIObject.isVisible(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setOpen(boolean open) {
|
||||||
|
UIObject.setVisible(summary, !open);
|
||||||
|
UIObject.setVisible(message, open);
|
||||||
|
if (open) {
|
||||||
|
removeStyleName(style.closed());
|
||||||
|
} else {
|
||||||
|
addStyleName(style.closed());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String authorName(MessageInfo info) {
|
||||||
|
if (info.author() != null) {
|
||||||
|
if (info.author().name() != null) {
|
||||||
|
return info.author().name();
|
||||||
|
}
|
||||||
|
return Gerrit.getConfig().getAnonymousCowardName();
|
||||||
|
}
|
||||||
|
return Util.C.messageNoAuthor();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
<?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.
|
||||||
|
-->
|
||||||
|
<ui:UiBinder
|
||||||
|
xmlns:ui='urn:ui:com.google.gwt.uibinder'
|
||||||
|
xmlns:c='urn:import:com.google.gerrit.client'
|
||||||
|
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
|
||||||
|
<ui:style type='com.google.gerrit.client.change.Message.Style'>
|
||||||
|
.messageBox {
|
||||||
|
width: 1168px;
|
||||||
|
border-left: 1px solid #e3e9ff;
|
||||||
|
border-right: 1px solid #e3e9ff;
|
||||||
|
border-bottom: 1px solid #e3e9ff;
|
||||||
|
-webkit-border-bottom-left-radius: 8px;
|
||||||
|
-webkit-border-bottom-right-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
width: 26px;
|
||||||
|
height: 26px;
|
||||||
|
}
|
||||||
|
.closed .avatar {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contents {
|
||||||
|
margin-left: 28px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contents p {
|
||||||
|
-webkit-margin-before: 0;
|
||||||
|
-webkit-margin-after: 0.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
white-space: nowrap;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.closed .name {
|
||||||
|
width: 120px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary {
|
||||||
|
color: #777;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 120px;
|
||||||
|
width: 915px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date {
|
||||||
|
white-space: nowrap;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 5px;
|
||||||
|
}
|
||||||
|
</ui:style>
|
||||||
|
|
||||||
|
<g:HTMLPanel
|
||||||
|
styleName='{style.messageBox}'
|
||||||
|
addStyleNames='{style.closed}'>
|
||||||
|
<c:AvatarImage ui:field='avatar' styleName='{style.avatar}'/>
|
||||||
|
<div class='{style.contents}'>
|
||||||
|
<div class='{style.name}' ui:field='name'/>
|
||||||
|
<div ui:field='summary' class='{style.summary}'/>
|
||||||
|
<div class='{style.date}' ui:field='date'/>
|
||||||
|
<div ui:field='message'
|
||||||
|
aria-hidden='true'
|
||||||
|
style='display: NONE'/>
|
||||||
|
</div>
|
||||||
|
</g:HTMLPanel>
|
||||||
|
</ui:UiBinder>
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
// 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.google.gerrit.client.change;
|
||||||
|
|
||||||
|
import com.google.gerrit.client.Gerrit;
|
||||||
|
import com.google.gerrit.client.changes.ChangeApi;
|
||||||
|
import com.google.gerrit.client.changes.ChangeInfo;
|
||||||
|
import com.google.gerrit.client.changes.ChangeInfo.LabelInfo;
|
||||||
|
import com.google.gerrit.client.changes.ReviewInput;
|
||||||
|
import com.google.gerrit.client.rpc.GerritCallback;
|
||||||
|
import com.google.gerrit.client.rpc.Natives;
|
||||||
|
import com.google.gerrit.common.PageLinks;
|
||||||
|
import com.google.gerrit.reviewdb.client.Change;
|
||||||
|
import com.google.gwt.core.client.JsArrayString;
|
||||||
|
import com.google.gwt.event.dom.client.ClickEvent;
|
||||||
|
import com.google.gwt.event.dom.client.ClickHandler;
|
||||||
|
import com.google.gwt.user.client.ui.Button;
|
||||||
|
import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
|
||||||
|
|
||||||
|
/** Applies a label with one mouse click. */
|
||||||
|
class QuickApprove extends Button implements ClickHandler {
|
||||||
|
private Change.Id changeId;
|
||||||
|
private String revision;
|
||||||
|
private ReviewInput input;
|
||||||
|
|
||||||
|
QuickApprove() {
|
||||||
|
addClickHandler(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set(ChangeInfo info, String commit) {
|
||||||
|
if (!info.has_permitted_labels() || !info.status().isOpen()) {
|
||||||
|
// Quick approve needs at least one label on an open change.
|
||||||
|
setVisible(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String qName = null;
|
||||||
|
String qValueStr = null;
|
||||||
|
short qValue = 0;
|
||||||
|
|
||||||
|
for (LabelInfo label : Natives.asList(info.all_labels().values())) {
|
||||||
|
if (!info.permitted_labels().containsKey(label.name())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsArrayString values = info.permitted_values(label.name());
|
||||||
|
if (values.length() == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (label.status()) {
|
||||||
|
case NEED: // Label is required for submit.
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OK: // Label already applied.
|
||||||
|
case MAY: // Label is not required.
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case REJECT: // Submit cannot happen, do not quick approve.
|
||||||
|
case IMPOSSIBLE:
|
||||||
|
setVisible(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String s = values.get(values.length() - 1);
|
||||||
|
short v = LabelInfo.parseValue(s);
|
||||||
|
if (v > 0 && s.equals(label.max_value())) {
|
||||||
|
if (qName != null) {
|
||||||
|
// Quick approve is available for one label only.
|
||||||
|
setVisible(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qName = label.name();
|
||||||
|
qValueStr = s;
|
||||||
|
qValue = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qName != null) {
|
||||||
|
changeId = info.legacy_id();
|
||||||
|
revision = commit;
|
||||||
|
input = ReviewInput.create();
|
||||||
|
input.label(qName, qValue);
|
||||||
|
setText(qName + qValueStr);
|
||||||
|
} else {
|
||||||
|
setVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setText(String text) {
|
||||||
|
setHTML(new SafeHtmlBuilder().openDiv().append(text).closeDiv());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(ClickEvent event) {
|
||||||
|
ChangeApi.revision(changeId.get(), revision)
|
||||||
|
.view("review")
|
||||||
|
.post(input, new GerritCallback<ReviewInput>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(ReviewInput result) {
|
||||||
|
Gerrit.display(PageLinks.toChange2(changeId));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
// 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.google.gerrit.client.change;
|
||||||
|
|
||||||
|
import com.google.gerrit.client.Gerrit;
|
||||||
|
import com.google.gerrit.client.changes.ChangeApi;
|
||||||
|
import com.google.gerrit.client.changes.ChangeInfo;
|
||||||
|
import com.google.gerrit.client.rpc.GerritCallback;
|
||||||
|
import com.google.gerrit.common.PageLinks;
|
||||||
|
import com.google.gerrit.reviewdb.client.Change;
|
||||||
|
|
||||||
|
class RebaseAction {
|
||||||
|
static void call(final Change.Id id, String revision) {
|
||||||
|
ChangeApi.rebase(id.get(), revision,
|
||||||
|
new GerritCallback<ChangeInfo>() {
|
||||||
|
public void onSuccess(ChangeInfo result) {
|
||||||
|
Gerrit.display(PageLinks.toChange2(id));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package com.google.gerrit.client.change;
|
||||||
|
|
||||||
|
import com.google.gerrit.client.Gerrit;
|
||||||
|
import com.google.gerrit.client.changes.ChangeInfo;
|
||||||
|
import com.google.gerrit.common.PageLinks;
|
||||||
|
import com.google.gerrit.reviewdb.client.Change;
|
||||||
|
import com.google.gwt.event.dom.client.ClickEvent;
|
||||||
|
import com.google.gwt.event.dom.client.ClickHandler;
|
||||||
|
import com.google.gwt.event.dom.client.MouseOutEvent;
|
||||||
|
import com.google.gwt.event.dom.client.MouseOutHandler;
|
||||||
|
import com.google.gwt.event.dom.client.MouseOverEvent;
|
||||||
|
import com.google.gwt.event.dom.client.MouseOverHandler;
|
||||||
|
import com.google.gwt.user.client.ui.Image;
|
||||||
|
|
||||||
|
class Reload extends Image implements ClickHandler,
|
||||||
|
MouseOverHandler, MouseOutHandler {
|
||||||
|
private Change.Id changeId;
|
||||||
|
private boolean in;
|
||||||
|
|
||||||
|
Reload() {
|
||||||
|
setResource(Resources.I.reload_black());
|
||||||
|
addClickHandler(this);
|
||||||
|
addMouseOverHandler(this);
|
||||||
|
addMouseOutHandler(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set(ChangeInfo info) {
|
||||||
|
changeId = info.legacy_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
void reload() {
|
||||||
|
Gerrit.display(PageLinks.toChange2(changeId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMouseOver(MouseOverEvent event) {
|
||||||
|
if (!in) {
|
||||||
|
in = true;
|
||||||
|
setResource(Resources.I.reload_white());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMouseOut(MouseOutEvent event) {
|
||||||
|
if (in) {
|
||||||
|
in = false;
|
||||||
|
setResource(Resources.I.reload_black());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(ClickEvent e) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
// 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.google.gerrit.client.change;
|
||||||
|
|
||||||
|
import com.google.gerrit.client.changes.ChangeInfo;
|
||||||
|
import com.google.gerrit.client.changes.ChangeInfo.LabelInfo;
|
||||||
|
import com.google.gerrit.client.rpc.NativeMap;
|
||||||
|
import com.google.gerrit.reviewdb.client.Change;
|
||||||
|
import com.google.gwt.core.client.JsArrayString;
|
||||||
|
import com.google.gwt.event.logical.shared.CloseEvent;
|
||||||
|
import com.google.gwt.event.logical.shared.CloseHandler;
|
||||||
|
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.user.client.PluginSafePopupPanel;
|
||||||
|
|
||||||
|
class ReplyAction {
|
||||||
|
private final Change.Id changeId;
|
||||||
|
private final String revision;
|
||||||
|
private final ChangeScreen2.Style style;
|
||||||
|
private final Widget replyButton;
|
||||||
|
|
||||||
|
private NativeMap<LabelInfo> allLabels;
|
||||||
|
private NativeMap<JsArrayString> permittedLabels;
|
||||||
|
|
||||||
|
private ReplyBox replyBox;
|
||||||
|
private PopupPanel popup;
|
||||||
|
|
||||||
|
ReplyAction(
|
||||||
|
ChangeInfo info,
|
||||||
|
String revision,
|
||||||
|
ChangeScreen2.Style style,
|
||||||
|
Widget replyButton) {
|
||||||
|
this.changeId = info.legacy_id();
|
||||||
|
this.revision = revision;
|
||||||
|
this.style = style;
|
||||||
|
this.replyButton = replyButton;
|
||||||
|
|
||||||
|
allLabels = info.all_labels();
|
||||||
|
permittedLabels = info.has_permitted_labels()
|
||||||
|
? info.permitted_labels()
|
||||||
|
: NativeMap.<JsArrayString> create();
|
||||||
|
}
|
||||||
|
|
||||||
|
void onReply() {
|
||||||
|
if (popup != null) {
|
||||||
|
popup.hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (replyBox == null) {
|
||||||
|
replyBox = new ReplyBox(
|
||||||
|
changeId,
|
||||||
|
revision,
|
||||||
|
allLabels,
|
||||||
|
permittedLabels);
|
||||||
|
allLabels = null;
|
||||||
|
permittedLabels = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final PluginSafePopupPanel p = new PluginSafePopupPanel(true);
|
||||||
|
p.setStyleName(style.replyBox());
|
||||||
|
p.addAutoHidePartner(replyButton.getElement());
|
||||||
|
p.addCloseHandler(new CloseHandler<PopupPanel>() {
|
||||||
|
@Override
|
||||||
|
public void onClose(CloseEvent<PopupPanel> event) {
|
||||||
|
if (popup == p) {
|
||||||
|
popup = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
p.add(replyBox);
|
||||||
|
p.showRelativeTo(replyButton);
|
||||||
|
GlobalKey.dialog(p);
|
||||||
|
popup = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,277 @@
|
|||||||
|
// 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.google.gerrit.client.change;
|
||||||
|
|
||||||
|
import com.google.gerrit.client.Gerrit;
|
||||||
|
import com.google.gerrit.client.changes.ChangeApi;
|
||||||
|
import com.google.gerrit.client.changes.ChangeInfo.ApprovalInfo;
|
||||||
|
import com.google.gerrit.client.changes.ChangeInfo.LabelInfo;
|
||||||
|
import com.google.gerrit.client.changes.ReviewInput;
|
||||||
|
import com.google.gerrit.client.rpc.GerritCallback;
|
||||||
|
import com.google.gerrit.client.rpc.NativeMap;
|
||||||
|
import com.google.gerrit.common.PageLinks;
|
||||||
|
import com.google.gerrit.common.data.LabelValue;
|
||||||
|
import com.google.gerrit.reviewdb.client.Change;
|
||||||
|
import com.google.gwt.core.client.GWT;
|
||||||
|
import com.google.gwt.core.client.JsArrayString;
|
||||||
|
import com.google.gwt.core.client.Scheduler;
|
||||||
|
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
|
||||||
|
import com.google.gwt.dom.client.Element;
|
||||||
|
import com.google.gwt.event.dom.client.ClickEvent;
|
||||||
|
import com.google.gwt.event.dom.client.KeyCodes;
|
||||||
|
import com.google.gwt.event.dom.client.KeyPressEvent;
|
||||||
|
import com.google.gwt.event.logical.shared.ValueChangeEvent;
|
||||||
|
import com.google.gwt.event.logical.shared.ValueChangeHandler;
|
||||||
|
import com.google.gwt.resources.client.CssResource;
|
||||||
|
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.ui.Button;
|
||||||
|
import com.google.gwt.user.client.ui.CheckBox;
|
||||||
|
import com.google.gwt.user.client.ui.Composite;
|
||||||
|
import com.google.gwt.user.client.ui.Grid;
|
||||||
|
import com.google.gwt.user.client.ui.HTMLPanel;
|
||||||
|
import com.google.gwt.user.client.ui.PopupPanel;
|
||||||
|
import com.google.gwt.user.client.ui.RadioButton;
|
||||||
|
import com.google.gwt.user.client.ui.UIObject;
|
||||||
|
import com.google.gwt.user.client.ui.Widget;
|
||||||
|
import com.google.gwtexpui.globalkey.client.NpTextArea;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
|
||||||
|
class ReplyBox extends Composite {
|
||||||
|
interface Binder extends UiBinder<HTMLPanel, ReplyBox> {}
|
||||||
|
private static Binder uiBinder = GWT.create(Binder.class);
|
||||||
|
|
||||||
|
interface Styles extends CssResource {
|
||||||
|
String label_name();
|
||||||
|
String label_value();
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Change.Id changeId;
|
||||||
|
private final String revision;
|
||||||
|
private ReviewInput in = ReviewInput.create();
|
||||||
|
private List<Runnable> lgtm;
|
||||||
|
|
||||||
|
@UiField Styles style;
|
||||||
|
@UiField NpTextArea message;
|
||||||
|
@UiField Element labelsParent;
|
||||||
|
@UiField Grid labelsTable;
|
||||||
|
@UiField Button send;
|
||||||
|
@UiField CheckBox email;
|
||||||
|
|
||||||
|
ReplyBox(
|
||||||
|
Change.Id changeId,
|
||||||
|
String revision,
|
||||||
|
NativeMap<LabelInfo> all,
|
||||||
|
NativeMap<JsArrayString> permitted) {
|
||||||
|
this.changeId = changeId;
|
||||||
|
this.revision = revision;
|
||||||
|
initWidget(uiBinder.createAndBindUi(this));
|
||||||
|
|
||||||
|
List<String> names = new ArrayList<String>(permitted.keySet());
|
||||||
|
if (names.isEmpty()) {
|
||||||
|
UIObject.setVisible(labelsParent, false);
|
||||||
|
} else {
|
||||||
|
Collections.sort(names);
|
||||||
|
lgtm = new ArrayList<Runnable>(names.size());
|
||||||
|
renderLabels(names, all, permitted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onLoad() {
|
||||||
|
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
|
||||||
|
@Override
|
||||||
|
public void execute() {
|
||||||
|
message.setFocus(true);
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiHandler("message")
|
||||||
|
void onMessageKey(KeyPressEvent event) {
|
||||||
|
if ((event.getCharCode() == '\n' || event.getCharCode() == KeyCodes.KEY_ENTER)
|
||||||
|
&& event.isControlKeyDown()) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
onSend(null);
|
||||||
|
} else if (lgtm != null
|
||||||
|
&& event.getCharCode() == 'M'
|
||||||
|
&& message.getValue().equals("LGT")) {
|
||||||
|
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
|
||||||
|
@Override
|
||||||
|
public void execute() {
|
||||||
|
if (message.getValue().startsWith("LGTM")) {
|
||||||
|
for (Runnable r : lgtm) {
|
||||||
|
r.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiHandler("email")
|
||||||
|
void onEmail(ValueChangeEvent<Boolean> e) {
|
||||||
|
if (e.getValue()) {
|
||||||
|
in.notify(ReviewInput.NotifyHandling.ALL);
|
||||||
|
} else {
|
||||||
|
in.notify(ReviewInput.NotifyHandling.NONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiHandler("send")
|
||||||
|
void onSend(ClickEvent e) {
|
||||||
|
in.message(message.getText().trim());
|
||||||
|
ChangeApi.revision(changeId.get(), revision)
|
||||||
|
.view("review")
|
||||||
|
.post(in, new GerritCallback<ReviewInput>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(ReviewInput result) {
|
||||||
|
Gerrit.display(PageLinks.toChange2(changeId));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void hide() {
|
||||||
|
for (Widget w = getParent(); w != null; w = w.getParent()) {
|
||||||
|
if (w instanceof PopupPanel) {
|
||||||
|
((PopupPanel) w).hide();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderLabels(
|
||||||
|
List<String> names,
|
||||||
|
NativeMap<LabelInfo> all,
|
||||||
|
NativeMap<JsArrayString> permitted) {
|
||||||
|
TreeSet<Short> values = new TreeSet<Short>();
|
||||||
|
for (String id : names) {
|
||||||
|
JsArrayString p = permitted.get(id);
|
||||||
|
if (p != null) {
|
||||||
|
for (int i = 0; i < p.length(); i++) {
|
||||||
|
values.add(LabelInfo.parseValue(p.get(i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<Short> columns = new ArrayList<Short>(values);
|
||||||
|
|
||||||
|
labelsTable.resize(1 + permitted.size(), 1 + values.size());
|
||||||
|
for (int c = 0; c < columns.size(); c++) {
|
||||||
|
labelsTable.setText(0, 1 + c, LabelValue.formatValue(columns.get(c)));
|
||||||
|
labelsTable.getCellFormatter().setStyleName(0, 1 + c, style.label_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> checkboxes = new ArrayList<String>(permitted.size());
|
||||||
|
int row = 1;
|
||||||
|
for (String id : names) {
|
||||||
|
Set<Short> vals = all.get(id).value_set();
|
||||||
|
if (isCheckBox(vals)) {
|
||||||
|
checkboxes.add(id);
|
||||||
|
} else {
|
||||||
|
renderRadio(row++, id, columns, vals, all.get(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (String id : checkboxes) {
|
||||||
|
renderCheckBox(row++, id, all.get(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderRadio(int row, final String id,
|
||||||
|
List<Short> columns,
|
||||||
|
Set<Short> values,
|
||||||
|
LabelInfo info) {
|
||||||
|
labelsTable.setText(row, 0, id);
|
||||||
|
labelsTable.getCellFormatter().setStyleName(row, 0, style.label_name());
|
||||||
|
|
||||||
|
ApprovalInfo self = Gerrit.isSignedIn()
|
||||||
|
? info.for_user(Gerrit.getUserAccount().getId().get())
|
||||||
|
: null;
|
||||||
|
|
||||||
|
final List<RadioButton> group = new ArrayList<RadioButton>(values.size());
|
||||||
|
for (int i = 0; i < columns.size(); i++) {
|
||||||
|
final Short v = columns.get(i);
|
||||||
|
if (values.contains(v)) {
|
||||||
|
RadioButton b = new RadioButton(id);
|
||||||
|
b.setTitle(info.value_text(LabelValue.formatValue(v)));
|
||||||
|
if ((self != null && v == self.value()) || (self == null && v == 0)) {
|
||||||
|
b.setValue(true);
|
||||||
|
}
|
||||||
|
b.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
|
||||||
|
@Override
|
||||||
|
public void onValueChange(ValueChangeEvent<Boolean> event) {
|
||||||
|
if (event.getValue()) {
|
||||||
|
in.label(id, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
group.add(b);
|
||||||
|
labelsTable.setWidget(row, 1 + i, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!group.isEmpty()) {
|
||||||
|
lgtm.add(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
for (int i = 0; i < group.size() - 1; i++) {
|
||||||
|
group.get(i).setValue(false, false);
|
||||||
|
}
|
||||||
|
group.get(group.size() - 1).setValue(true, true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderCheckBox(int row, final String id, LabelInfo info) {
|
||||||
|
ApprovalInfo self = Gerrit.isSignedIn()
|
||||||
|
? info.for_user(Gerrit.getUserAccount().getId().get())
|
||||||
|
: null;
|
||||||
|
|
||||||
|
final CheckBox b = new CheckBox();
|
||||||
|
b.setText(id);
|
||||||
|
b.setTitle(info.value_text("+1"));
|
||||||
|
if (self != null && self.value() == 1) {
|
||||||
|
b.setValue(true);
|
||||||
|
}
|
||||||
|
b.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
|
||||||
|
@Override
|
||||||
|
public void onValueChange(ValueChangeEvent<Boolean> event) {
|
||||||
|
in.label(id, event.getValue() ? (short) 1 : (short) 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
b.setStyleName(style.label_name());
|
||||||
|
labelsTable.setWidget(row, 0, b);
|
||||||
|
|
||||||
|
lgtm.add(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
b.setValue(true, true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isCheckBox(Set<Short> values) {
|
||||||
|
return values.size() == 2
|
||||||
|
&& values.contains((short) 0)
|
||||||
|
&& values.contains((short) 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
<?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.
|
||||||
|
-->
|
||||||
|
<ui:UiBinder
|
||||||
|
xmlns:ui='urn:ui:com.google.gwt.uibinder'
|
||||||
|
xmlns:g='urn:import:com.google.gwt.user.client.ui'
|
||||||
|
xmlns:c='urn:import:com.google.gwtexpui.globalkey.client'>
|
||||||
|
<ui:with field='res' type='com.google.gerrit.client.change.Resources'/>
|
||||||
|
<ui:style type='com.google.gerrit.client.change.ReplyBox.Styles'>
|
||||||
|
@eval trimColor com.google.gerrit.client.Gerrit.getTheme().trimColor;
|
||||||
|
|
||||||
|
.replyBox {
|
||||||
|
max-height: 260px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section {
|
||||||
|
padding: 5px 5px;
|
||||||
|
border-bottom: 1px solid #b8b8b8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label_name {
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.label_name input { margin-left: 0; }
|
||||||
|
|
||||||
|
.label_value {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.email {
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 2em;
|
||||||
|
}
|
||||||
|
</ui:style>
|
||||||
|
<g:HTMLPanel styleName='{style.replyBox}'>
|
||||||
|
<div class='{style.section}'>
|
||||||
|
<c:NpTextArea
|
||||||
|
visibleLines='5'
|
||||||
|
characterWidth='70'
|
||||||
|
ui:field='message'/>
|
||||||
|
</div>
|
||||||
|
<div class='{style.section}' ui:field='labelsParent'>
|
||||||
|
<g:Grid ui:field='labelsTable'/>
|
||||||
|
</div>
|
||||||
|
<div class='{style.section}'>
|
||||||
|
<g:Button ui:field='send'
|
||||||
|
title='Send reply (Shortcut: Ctrl-Enter)'
|
||||||
|
styleName='{res.style.button}'>
|
||||||
|
<ui:attribute name='title'/>
|
||||||
|
<div><ui:msg>Send</ui:msg></div>
|
||||||
|
</g:Button>
|
||||||
|
|
||||||
|
<div class='{style.email}'>
|
||||||
|
<ui:msg>and <g:CheckBox ui:field='email' value='true'>send email</g:CheckBox></ui:msg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</g:HTMLPanel>
|
||||||
|
</ui:UiBinder>
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
// 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.google.gerrit.client.change;
|
||||||
|
|
||||||
|
import com.google.gwt.core.client.GWT;
|
||||||
|
import com.google.gwt.resources.client.ClientBundle;
|
||||||
|
import com.google.gwt.resources.client.CssResource;
|
||||||
|
import com.google.gwt.resources.client.ImageResource;
|
||||||
|
|
||||||
|
interface Resources extends ClientBundle {
|
||||||
|
static final Resources I = GWT.create(Resources.class);
|
||||||
|
|
||||||
|
@Source("star_open.png") ImageResource star_open();
|
||||||
|
@Source("star_filled.png") ImageResource star_filled();
|
||||||
|
@Source("reload_black.png") ImageResource reload_black();
|
||||||
|
@Source("reload_white.png") ImageResource reload_white();
|
||||||
|
@Source("common.css") Style style();
|
||||||
|
|
||||||
|
interface Style extends CssResource {
|
||||||
|
String button();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
// 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.google.gerrit.client.change;
|
||||||
|
|
||||||
|
import com.google.gerrit.client.Gerrit;
|
||||||
|
import com.google.gerrit.client.changes.ChangeApi;
|
||||||
|
import com.google.gerrit.client.changes.ChangeInfo;
|
||||||
|
import com.google.gerrit.client.rpc.GerritCallback;
|
||||||
|
import com.google.gerrit.common.PageLinks;
|
||||||
|
import com.google.gerrit.reviewdb.client.Change;
|
||||||
|
import com.google.gwt.user.client.ui.Button;
|
||||||
|
|
||||||
|
class RestoreAction extends ActionMessageBox {
|
||||||
|
private final Change.Id id;
|
||||||
|
|
||||||
|
RestoreAction(Button b, Change.Id id) {
|
||||||
|
super(b);
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void send(String message) {
|
||||||
|
ChangeApi.restore(id.get(), message, new GerritCallback<ChangeInfo>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(ChangeInfo result) {
|
||||||
|
Gerrit.display(PageLinks.toChange2(id));
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
// 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.google.gerrit.client.change;
|
||||||
|
|
||||||
|
import com.google.gerrit.client.Gerrit;
|
||||||
|
import com.google.gerrit.client.changes.ChangeApi;
|
||||||
|
import com.google.gerrit.client.changes.ChangeInfo;
|
||||||
|
import com.google.gerrit.client.changes.Util;
|
||||||
|
import com.google.gerrit.client.rpc.GerritCallback;
|
||||||
|
import com.google.gerrit.client.ui.ActionDialog;
|
||||||
|
import com.google.gerrit.common.PageLinks;
|
||||||
|
import com.google.gerrit.reviewdb.client.Change;
|
||||||
|
import com.google.gwt.user.client.ui.Button;
|
||||||
|
|
||||||
|
class RevertAction {
|
||||||
|
static void call(Button b, final Change.Id id, final String revision,
|
||||||
|
String project, final String commitSubject) {
|
||||||
|
// TODO Replace ActionDialog with a nicer looking display.
|
||||||
|
b.setEnabled(false);
|
||||||
|
new ActionDialog(b, false,
|
||||||
|
Util.C.revertChangeTitle(),
|
||||||
|
Util.C.headingRevertMessage()) {
|
||||||
|
{
|
||||||
|
sendButton.setText(Util.C.buttonRevertChangeSend());
|
||||||
|
message.setText(Util.M.revertChangeDefaultMessage(
|
||||||
|
commitSubject, revision));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSend() {
|
||||||
|
ChangeApi.revert(id.get(),
|
||||||
|
getMessageText(), new GerritCallback<ChangeInfo>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(ChangeInfo result) {
|
||||||
|
sent = true;
|
||||||
|
hide();
|
||||||
|
Gerrit.display(PageLinks.toChange2(result.legacy_id()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Throwable caught) {
|
||||||
|
enableButtons(true);
|
||||||
|
super.onFailure(caught);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}.center();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
// Copyright (C) 2012 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.change;
|
||||||
|
|
||||||
|
import com.google.gwt.user.client.ui.Image;
|
||||||
|
import com.google.gwt.user.client.ui.ToggleButton;
|
||||||
|
|
||||||
|
class StarIcon extends ToggleButton {
|
||||||
|
StarIcon() {
|
||||||
|
super(
|
||||||
|
new Image(Resources.I.star_open()),
|
||||||
|
new Image(Resources.I.star_filled()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
// 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.google.gerrit.client.change;
|
||||||
|
|
||||||
|
import com.google.gerrit.client.Gerrit;
|
||||||
|
import com.google.gerrit.client.changes.ChangeApi;
|
||||||
|
import com.google.gerrit.client.changes.SubmitFailureDialog;
|
||||||
|
import com.google.gerrit.client.changes.SubmitInfo;
|
||||||
|
import com.google.gerrit.client.rpc.GerritCallback;
|
||||||
|
import com.google.gerrit.common.PageLinks;
|
||||||
|
import com.google.gerrit.reviewdb.client.Change;
|
||||||
|
|
||||||
|
class SubmitAction {
|
||||||
|
static void call(final Change.Id id, String revision) {
|
||||||
|
ChangeApi.submit(id.get(), revision,
|
||||||
|
new GerritCallback<SubmitInfo>() {
|
||||||
|
public void onSuccess(SubmitInfo result) {
|
||||||
|
redisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onFailure(Throwable err) {
|
||||||
|
if (SubmitFailureDialog.isConflict(err)) {
|
||||||
|
new SubmitFailureDialog(err.getMessage()).center();
|
||||||
|
redisplay();
|
||||||
|
} else {
|
||||||
|
super.onFailure(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void redisplay() {
|
||||||
|
Gerrit.display(PageLinks.toChange2(id));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
// 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.google.gerrit.client.change;
|
||||||
|
|
||||||
|
import com.google.gerrit.client.changes.ChangeApi;
|
||||||
|
import com.google.gerrit.client.changes.ChangeInfo;
|
||||||
|
import com.google.gerrit.client.rpc.GerritCallback;
|
||||||
|
import com.google.gwt.core.client.GWT;
|
||||||
|
import com.google.gwt.dom.client.Element;
|
||||||
|
import com.google.gwt.event.dom.client.ClickEvent;
|
||||||
|
import com.google.gwt.event.dom.client.ClickHandler;
|
||||||
|
import com.google.gwt.event.dom.client.KeyCodes;
|
||||||
|
import com.google.gwt.event.dom.client.KeyDownEvent;
|
||||||
|
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.ui.Button;
|
||||||
|
import com.google.gwt.user.client.ui.Composite;
|
||||||
|
import com.google.gwt.user.client.ui.FlowPanel;
|
||||||
|
import com.google.gwt.user.client.ui.HTMLPanel;
|
||||||
|
import com.google.gwt.user.client.ui.Image;
|
||||||
|
import com.google.gwt.user.client.ui.InlineLabel;
|
||||||
|
import com.google.gwt.user.client.ui.UIObject;
|
||||||
|
import com.google.gwtexpui.globalkey.client.NpTextArea;
|
||||||
|
import com.google.gwtexpui.globalkey.client.NpTextBox;
|
||||||
|
|
||||||
|
/** Displays (and edits) the change topic string. */
|
||||||
|
class Topic extends Composite {
|
||||||
|
interface Binder extends UiBinder<HTMLPanel, Topic> {}
|
||||||
|
private static Binder uiBinder = GWT.create(Binder.class);
|
||||||
|
|
||||||
|
private int changeId;
|
||||||
|
private boolean canEdit;
|
||||||
|
|
||||||
|
@UiField FlowPanel show;
|
||||||
|
@UiField InlineLabel text;
|
||||||
|
@UiField Image editIcon;
|
||||||
|
|
||||||
|
@UiField Element form;
|
||||||
|
@UiField NpTextBox input;
|
||||||
|
@UiField NpTextArea message;
|
||||||
|
@UiField Button save;
|
||||||
|
@UiField Button cancel;
|
||||||
|
|
||||||
|
Topic() {
|
||||||
|
initWidget(uiBinder.createAndBindUi(this));
|
||||||
|
show.addDomHandler(
|
||||||
|
new ClickHandler() {
|
||||||
|
@Override
|
||||||
|
public void onClick(ClickEvent event) {
|
||||||
|
onEdit();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ClickEvent.getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
void set(ChangeInfo info) {
|
||||||
|
canEdit = info.has_actions()
|
||||||
|
&& info.actions().containsKey("topic")
|
||||||
|
&& info.actions().get("topic").enabled();
|
||||||
|
|
||||||
|
changeId = info.legacy_id().get();
|
||||||
|
text.setText(info.topic());
|
||||||
|
editIcon.setVisible(canEdit);
|
||||||
|
if (!canEdit) {
|
||||||
|
show.setTitle(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean canEdit() {
|
||||||
|
return canEdit;
|
||||||
|
}
|
||||||
|
|
||||||
|
void onEdit() {
|
||||||
|
if (canEdit) {
|
||||||
|
show.setVisible(false);
|
||||||
|
UIObject.setVisible(form, true);
|
||||||
|
|
||||||
|
input.setText(text.getText());
|
||||||
|
input.setFocus(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiHandler("cancel")
|
||||||
|
void onCancel(ClickEvent e) {
|
||||||
|
input.setFocus(false);
|
||||||
|
show.setVisible(true);
|
||||||
|
UIObject.setVisible(form, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiHandler("input")
|
||||||
|
void onKeyDownInput(KeyDownEvent e) {
|
||||||
|
if (e.getNativeKeyCode() == KeyCodes.KEY_ESCAPE) {
|
||||||
|
onCancel(null);
|
||||||
|
} else if (e.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
|
||||||
|
onSave(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiHandler("message")
|
||||||
|
void onKeyDownMessage(KeyDownEvent e) {
|
||||||
|
if (e.getNativeKeyCode() == KeyCodes.KEY_ESCAPE) {
|
||||||
|
onCancel(null);
|
||||||
|
} else if (e.getNativeKeyCode() == KeyCodes.KEY_ENTER
|
||||||
|
&& e.isControlKeyDown()) {
|
||||||
|
onSave(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiHandler("save")
|
||||||
|
void onSave(ClickEvent e) {
|
||||||
|
ChangeApi.topic(
|
||||||
|
changeId,
|
||||||
|
input.getValue().trim(),
|
||||||
|
message.getValue().trim(),
|
||||||
|
new GerritCallback<String>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(String result) {
|
||||||
|
// Cheat and just patch the UI with the current topic.
|
||||||
|
// This saves a full redraw of the change screen but
|
||||||
|
// will cause the message to be missed in the History.
|
||||||
|
text.setText(result);
|
||||||
|
onCancel(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
<?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.
|
||||||
|
-->
|
||||||
|
<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:with field='ico' type='com.google.gerrit.client.GerritResources'/>
|
||||||
|
<ui:with field='res' type='com.google.gerrit.client.change.Resources'/>
|
||||||
|
<ui:style>
|
||||||
|
.show { cursor: pointer; }
|
||||||
|
.edit, .cancel { float: right; }
|
||||||
|
</ui:style>
|
||||||
|
<g:HTMLPanel>
|
||||||
|
<g:FlowPanel ui:field='show'
|
||||||
|
styleName='{style.show}'
|
||||||
|
title='Click to edit topic (Shortcut: t)'>
|
||||||
|
<ui:attribute name='title'/>
|
||||||
|
<g:InlineLabel ui:field='text'/>
|
||||||
|
<g:Image ui:field='editIcon'
|
||||||
|
resource='{ico.edit}'
|
||||||
|
styleName='{style.edit}'/>
|
||||||
|
</g:FlowPanel>
|
||||||
|
|
||||||
|
<div ui:field='form' style='display: none' aria-hidden='true'>
|
||||||
|
<div>
|
||||||
|
<c:NpTextBox ui:field='input' visibleLength='55'/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<c:NpTextArea ui:field='message'
|
||||||
|
visibleLines='3'
|
||||||
|
characterWidth='45'/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<g:Button ui:field='save' styleName='{res.style.button}'>
|
||||||
|
<div>Update</div>
|
||||||
|
</g:Button>
|
||||||
|
<g:Button ui:field='cancel'
|
||||||
|
styleName='{res.style.button}'
|
||||||
|
addStyleNames='{style.cancel}'>
|
||||||
|
<div>Cancel</div>
|
||||||
|
</g:Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</g:HTMLPanel>
|
||||||
|
</ui:UiBinder>
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
/* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.button {
|
||||||
|
margin: 0 3px 0 0;
|
||||||
|
border-color: rgba(0, 0, 0, 0.1);
|
||||||
|
text-align: center;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: bold;
|
||||||
|
border: 1px solid;
|
||||||
|
cursor: pointer;
|
||||||
|
color: #fff;
|
||||||
|
background-color: #4d90fe;
|
||||||
|
background-image: -webkit-linear-gradient(top, #4d90fe, #4d90fe);
|
||||||
|
-webkit-border-radius: 2px;
|
||||||
|
-webkit-box-sizing: content-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button div {
|
||||||
|
width: 54px;
|
||||||
|
white-space: nowrap;
|
||||||
|
color: #fff;
|
||||||
|
height: 10px;
|
||||||
|
line-height: 10px;
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.pointer {
|
||||||
|
width: 1px;
|
||||||
|
padding: 0px;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pathColumn {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deltaColumn1 {
|
||||||
|
white-space: nowrap;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deltaColumn2 {
|
||||||
|
padding-left: 5px;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inserted {
|
||||||
|
height: 10px;
|
||||||
|
display: inline-block;
|
||||||
|
background-color: #4d4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deleted {
|
||||||
|
height: 10px;
|
||||||
|
display: inline-block;
|
||||||
|
background-color: #d44;
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 273 B |
Binary file not shown.
|
After Width: | Height: | Size: 279 B |
Binary file not shown.
|
After Width: | Height: | Size: 309 B |
Binary file not shown.
|
After Width: | Height: | Size: 278 B |
@@ -164,7 +164,7 @@ public class ChangeApi {
|
|||||||
return change(id).view("revisions").id(commit).view(action);
|
return change(id).view("revisions").id(commit).view(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static RestApi change(int id) {
|
public static RestApi change(int id) {
|
||||||
// TODO Switch to triplet project~branch~id format in URI.
|
// TODO Switch to triplet project~branch~id format in URI.
|
||||||
return new RestApi("/changes/").id(String.valueOf(id));
|
return new RestApi("/changes/").id(String.valueOf(id));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ public interface ChangeConstants extends Constants {
|
|||||||
String statusLongMerged();
|
String statusLongMerged();
|
||||||
String statusLongAbandoned();
|
String statusLongAbandoned();
|
||||||
String statusLongDraft();
|
String statusLongDraft();
|
||||||
|
String readyToSubmit();
|
||||||
|
String mergeConflict();
|
||||||
|
|
||||||
String myDashboardTitle();
|
String myDashboardTitle();
|
||||||
String unknownDashboardTitle();
|
String unknownDashboardTitle();
|
||||||
@@ -53,7 +55,9 @@ public interface ChangeConstants extends Constants {
|
|||||||
String expandCollapseDependencies();
|
String expandCollapseDependencies();
|
||||||
String previousPatchSet();
|
String previousPatchSet();
|
||||||
String nextPatchSet();
|
String nextPatchSet();
|
||||||
|
String keyReload();
|
||||||
String keyPublishComments();
|
String keyPublishComments();
|
||||||
|
String keyEditTopic();
|
||||||
|
|
||||||
String patchTableColumnName();
|
String patchTableColumnName();
|
||||||
String patchTableColumnComments();
|
String patchTableColumnComments();
|
||||||
@@ -63,6 +67,7 @@ public interface ChangeConstants extends Constants {
|
|||||||
String patchTableDiffUnified();
|
String patchTableDiffUnified();
|
||||||
String patchTableDownloadPreImage();
|
String patchTableDownloadPreImage();
|
||||||
String patchTableDownloadPostImage();
|
String patchTableDownloadPostImage();
|
||||||
|
String patchTableBinary();
|
||||||
String commitMessage();
|
String commitMessage();
|
||||||
String fileCommentHeader();
|
String fileCommentHeader();
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ statusLongSubmitted = Submitted, Merge Pending
|
|||||||
statusLongMerged = Merged
|
statusLongMerged = Merged
|
||||||
statusLongAbandoned = Abandoned
|
statusLongAbandoned = Abandoned
|
||||||
statusLongDraft = Draft
|
statusLongDraft = Draft
|
||||||
|
readyToSubmit = Ready to Submit
|
||||||
|
mergeConflict = Merge Conflict
|
||||||
|
|
||||||
starredHeading = Starred Changes
|
starredHeading = Starred Changes
|
||||||
watchedHeading = Open Changes of Watched Projects
|
watchedHeading = Open Changes of Watched Projects
|
||||||
@@ -33,7 +35,9 @@ upToChangeList = Up to change list
|
|||||||
expandCollapseDependencies = Expands / Collapses dependencies section
|
expandCollapseDependencies = Expands / Collapses dependencies section
|
||||||
previousPatchSet = Previous patch set
|
previousPatchSet = Previous patch set
|
||||||
nextPatchSet = Next patch set
|
nextPatchSet = Next patch set
|
||||||
|
keyReload = Reload change
|
||||||
keyPublishComments = Review and publish comments
|
keyPublishComments = Review and publish comments
|
||||||
|
keyEditTopic = Edit change topic
|
||||||
|
|
||||||
patchTableColumnName = File Path
|
patchTableColumnName = File Path
|
||||||
patchTableColumnComments = Comments
|
patchTableColumnComments = Comments
|
||||||
@@ -43,6 +47,7 @@ patchTableDiffSideBySide = Side-by-Side
|
|||||||
patchTableDiffUnified = Unified
|
patchTableDiffUnified = Unified
|
||||||
patchTableDownloadPreImage = old
|
patchTableDownloadPreImage = old
|
||||||
patchTableDownloadPostImage = new
|
patchTableDownloadPostImage = new
|
||||||
|
patchTableBinary = Binary
|
||||||
commitMessage = Commit Message
|
commitMessage = Commit Message
|
||||||
fileCommentHeader = File Comment:
|
fileCommentHeader = File Comment:
|
||||||
|
|
||||||
|
|||||||
@@ -15,9 +15,11 @@
|
|||||||
package com.google.gerrit.client.changes;
|
package com.google.gerrit.client.changes;
|
||||||
|
|
||||||
import com.google.gerrit.client.account.AccountInfo;
|
import com.google.gerrit.client.account.AccountInfo;
|
||||||
|
import com.google.gerrit.client.diff.FileInfo;
|
||||||
import com.google.gerrit.client.rpc.NativeMap;
|
import com.google.gerrit.client.rpc.NativeMap;
|
||||||
import com.google.gerrit.client.rpc.NativeString;
|
import com.google.gerrit.client.rpc.NativeString;
|
||||||
import com.google.gerrit.client.rpc.Natives;
|
import com.google.gerrit.client.rpc.Natives;
|
||||||
|
import com.google.gerrit.common.data.LabelValue;
|
||||||
import com.google.gerrit.common.data.SubmitRecord;
|
import com.google.gerrit.common.data.SubmitRecord;
|
||||||
import com.google.gerrit.reviewdb.client.Change;
|
import com.google.gerrit.reviewdb.client.Change;
|
||||||
import com.google.gerrit.reviewdb.client.Project;
|
import com.google.gerrit.reviewdb.client.Project;
|
||||||
@@ -28,11 +30,13 @@ import com.google.gwtjsonrpc.client.impl.ser.JavaSqlTimestamp_JsonSerializer;
|
|||||||
|
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.SortedSet;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
|
||||||
public class ChangeInfo extends JavaScriptObject {
|
public class ChangeInfo extends JavaScriptObject {
|
||||||
public final void init() {
|
public final void init() {
|
||||||
if (labels0() != null) {
|
if (all_labels() != null) {
|
||||||
labels0().copyKeysIntoChildren("_name");
|
all_labels().copyKeysIntoChildren("_name");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,7 +73,7 @@ public class ChangeInfo extends JavaScriptObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final Set<String> labels() {
|
public final Set<String> labels() {
|
||||||
return labels0().keySet();
|
return all_labels().keySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
public final native String id() /*-{ return this.id; }-*/;
|
public final native String id() /*-{ return this.id; }-*/;
|
||||||
@@ -86,22 +90,26 @@ public class ChangeInfo extends JavaScriptObject {
|
|||||||
public final native boolean starred() /*-{ return this.starred ? true : false; }-*/;
|
public final native boolean starred() /*-{ return this.starred ? true : false; }-*/;
|
||||||
public final native boolean reviewed() /*-{ return this.reviewed ? true : false; }-*/;
|
public final native boolean reviewed() /*-{ return this.reviewed ? true : false; }-*/;
|
||||||
public final native String _sortkey() /*-{ return this._sortkey; }-*/;
|
public final native String _sortkey() /*-{ return this._sortkey; }-*/;
|
||||||
private final native NativeMap<LabelInfo> labels0() /*-{ return this.labels; }-*/;
|
public final native NativeMap<LabelInfo> all_labels() /*-{ return this.labels; }-*/;
|
||||||
public final native LabelInfo label(String n) /*-{ return this.labels[n]; }-*/;
|
public final native LabelInfo label(String n) /*-{ return this.labels[n]; }-*/;
|
||||||
|
public final native String current_revision() /*-{ return this.current_revision; }-*/;
|
||||||
|
public final native NativeMap<RevisionInfo> revisions() /*-{ return this.revisions; }-*/;
|
||||||
|
public final native RevisionInfo revision(String n) /*-{ return this.revisions[n]; }-*/;
|
||||||
|
public final native JsArray<MessageInfo> messages() /*-{ return this.messages; }-*/;
|
||||||
|
|
||||||
public final native boolean has_permitted_labels()
|
public final native boolean has_permitted_labels()
|
||||||
/*-{ return this.hasOwnProperty('permitted_labels') }-*/;
|
/*-{ return this.hasOwnProperty('permitted_labels') }-*/;
|
||||||
private final native NativeMap<JavaScriptObject> _permitted_labels()
|
public final native NativeMap<JsArrayString> permitted_labels()
|
||||||
/*-{ return this.permitted_labels; }-*/;
|
/*-{ return this.permitted_labels; }-*/;
|
||||||
public final Set<String> permitted_labels() {
|
|
||||||
return Natives.keys(_permitted_labels());
|
|
||||||
}
|
|
||||||
public final native JsArrayString permitted_values(String n)
|
public final native JsArrayString permitted_values(String n)
|
||||||
/*-{ return this.permitted_labels[n]; }-*/;
|
/*-{ return this.permitted_labels[n]; }-*/;
|
||||||
|
|
||||||
public final native JsArray<AccountInfo> removable_reviewers()
|
public final native JsArray<AccountInfo> removable_reviewers()
|
||||||
/*-{ return this.removable_reviewers; }-*/;
|
/*-{ return this.removable_reviewers; }-*/;
|
||||||
|
|
||||||
|
public final native boolean has_actions() /*-{ return this.hasOwnProperty('actions') }-*/;
|
||||||
|
public final native NativeMap<ActionInfo> actions() /*-{ return this.actions; }-*/;
|
||||||
|
|
||||||
final native int _number() /*-{ return this._number; }-*/;
|
final native int _number() /*-{ return this._number; }-*/;
|
||||||
final native boolean _more_changes()
|
final native boolean _more_changes()
|
||||||
/*-{ return this._more_changes ? true : false; }-*/;
|
/*-{ return this._more_changes ? true : false; }-*/;
|
||||||
@@ -130,9 +138,17 @@ public class ChangeInfo extends JavaScriptObject {
|
|||||||
public final native AccountInfo disliked() /*-{ return this.disliked; }-*/;
|
public final native AccountInfo disliked() /*-{ return this.disliked; }-*/;
|
||||||
|
|
||||||
public final native JsArray<ApprovalInfo> all() /*-{ return this.all; }-*/;
|
public final native JsArray<ApprovalInfo> all() /*-{ return this.all; }-*/;
|
||||||
|
public final ApprovalInfo for_user(int user) {
|
||||||
|
JsArray<ApprovalInfo> all = all();
|
||||||
|
for (int i = 0; all != null && i < all.length(); i++) {
|
||||||
|
if (all.get(i)._account_id() == user) {
|
||||||
|
return all.get(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private final native NativeMap<NativeString> _values() /*-{ return this.values; }-*/;
|
private final native NativeMap<NativeString> _values() /*-{ return this.values; }-*/;
|
||||||
|
|
||||||
public final Set<String> values() {
|
public final Set<String> values() {
|
||||||
return Natives.keys(_values());
|
return Natives.keys(_values());
|
||||||
}
|
}
|
||||||
@@ -147,15 +163,102 @@ public class ChangeInfo extends JavaScriptObject {
|
|||||||
return 0;
|
return 0;
|
||||||
}-*/;
|
}-*/;
|
||||||
|
|
||||||
|
public final String max_value() {
|
||||||
|
return LabelValue.formatValue(value_set().last());
|
||||||
|
}
|
||||||
|
|
||||||
|
public final SortedSet<Short> value_set() {
|
||||||
|
SortedSet<Short> values = new TreeSet<Short>();
|
||||||
|
for (String v : values()) {
|
||||||
|
values.add(parseValue(v));
|
||||||
|
}
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final short parseValue(String formatted) {
|
||||||
|
if (formatted.startsWith("+")) {
|
||||||
|
formatted = formatted.substring(1);
|
||||||
|
} else if (formatted.startsWith(" ")) {
|
||||||
|
formatted = formatted.trim();
|
||||||
|
}
|
||||||
|
return Short.parseShort(formatted);
|
||||||
|
}
|
||||||
|
|
||||||
protected LabelInfo() {
|
protected LabelInfo() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ApprovalInfo extends AccountInfo {
|
public static class ApprovalInfo extends AccountInfo {
|
||||||
public final native boolean has_value() /*-{ return this.hasOwnProperty('value'); }-*/;
|
public final native boolean has_value() /*-{ return this.hasOwnProperty('value'); }-*/;
|
||||||
public final native short value() /*-{ return this.value; }-*/;
|
public final native short value() /*-{ return this.value || 0; }-*/;
|
||||||
|
|
||||||
protected ApprovalInfo() {
|
protected ApprovalInfo() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class RevisionInfo extends JavaScriptObject {
|
||||||
|
public final native int _number() /*-{ return this._number; }-*/;
|
||||||
|
public final native String name() /*-{ return this.name; }-*/;
|
||||||
|
public final native boolean draft() /*-{ return this.draft || false; }-*/;
|
||||||
|
public final native CommitInfo commit() /*-{ return this.commit; }-*/;
|
||||||
|
public final native void set_commit(CommitInfo c) /*-{ this.commit = c; }-*/;
|
||||||
|
|
||||||
|
public final native boolean has_files() /*-{ return this.hasOwnProperty('files') }-*/;
|
||||||
|
public final native NativeMap<FileInfo> files() /*-{ return this.files; }-*/;
|
||||||
|
|
||||||
|
public final native boolean has_actions() /*-{ return this.hasOwnProperty('actions') }-*/;
|
||||||
|
public final native NativeMap<ActionInfo> actions() /*-{ return this.actions; }-*/;
|
||||||
|
|
||||||
|
protected RevisionInfo () {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class CommitInfo extends JavaScriptObject {
|
||||||
|
public final native String commit() /*-{ return this.commit; }-*/;
|
||||||
|
public final native GitPerson author() /*-{ return this.author; }-*/;
|
||||||
|
public final native GitPerson committer() /*-{ return this.committer; }-*/;
|
||||||
|
public final native String subject() /*-{ return this.subject; }-*/;
|
||||||
|
public final native String message() /*-{ return this.message; }-*/;
|
||||||
|
|
||||||
|
protected CommitInfo() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class GitPerson extends JavaScriptObject {
|
||||||
|
public final native String name() /*-{ return this.name; }-*/;
|
||||||
|
public final native String email() /*-{ return this.email; }-*/;
|
||||||
|
private final native String dateRaw() /*-{ return this.date; }-*/;
|
||||||
|
|
||||||
|
public final Timestamp date() {
|
||||||
|
return JavaSqlTimestamp_JsonSerializer.parseTimestamp(dateRaw());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected GitPerson() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ActionInfo extends JavaScriptObject {
|
||||||
|
public final native String id() /*-{ return this.id; }-*/;
|
||||||
|
public final native String method() /*-{ return this.method; }-*/;
|
||||||
|
public final native String label() /*-{ return this.label; }-*/;
|
||||||
|
public final native String title() /*-{ return this.title; }-*/;
|
||||||
|
public final native boolean enabled() /*-{ return this.enabled || false; }-*/;
|
||||||
|
public final native String confirmation_message() /*-{ return this.confirmation_message; }-*/;
|
||||||
|
|
||||||
|
protected ActionInfo() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class MessageInfo extends JavaScriptObject {
|
||||||
|
public final native AccountInfo author() /*-{ return this.author; }-*/;
|
||||||
|
public final native String message() /*-{ return this.message; }-*/;
|
||||||
|
private final native String dateRaw() /*-{ return this.date; }-*/;
|
||||||
|
|
||||||
|
public final Timestamp date() {
|
||||||
|
return JavaSqlTimestamp_JsonSerializer.parseTimestamp(dateRaw());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected MessageInfo() {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ public interface ChangeMessages extends Messages {
|
|||||||
String patchTableComments(@PluralCount int count);
|
String patchTableComments(@PluralCount int count);
|
||||||
String patchTableDrafts(@PluralCount int count);
|
String patchTableDrafts(@PluralCount int count);
|
||||||
String patchTableSize_Modify(int insertions, int deletions);
|
String patchTableSize_Modify(int insertions, int deletions);
|
||||||
|
String patchTableSize_LongModify(int insertions, int deletions);
|
||||||
String patchTableSize_Lines(@PluralCount int insertions);
|
String patchTableSize_Lines(@PluralCount int insertions);
|
||||||
|
|
||||||
String removeReviewer(String fullName);
|
String removeReviewer(String fullName);
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ submitPatchSet = Submit Patch Set {0}
|
|||||||
patchTableComments = {0} comments
|
patchTableComments = {0} comments
|
||||||
patchTableDrafts = {0} drafts
|
patchTableDrafts = {0} drafts
|
||||||
patchTableSize_Modify = +{0}, -{1}
|
patchTableSize_Modify = +{0}, -{1}
|
||||||
|
patchTableSize_LongModify = {0} inserted, {1} deleted
|
||||||
patchTableSize_Lines = {0} lines
|
patchTableSize_Lines = {0} lines
|
||||||
|
|
||||||
removeReviewer = Remove reviewer {0}
|
removeReviewer = Remove reviewer {0}
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ package com.google.gerrit.client.changes;
|
|||||||
import com.google.gwt.core.client.JavaScriptObject;
|
import com.google.gwt.core.client.JavaScriptObject;
|
||||||
|
|
||||||
public class ReviewInput extends JavaScriptObject {
|
public class ReviewInput extends JavaScriptObject {
|
||||||
|
public static enum NotifyHandling {
|
||||||
|
NONE, OWNER, OWNER_REVIEWERS, ALL;
|
||||||
|
}
|
||||||
|
|
||||||
public static ReviewInput create() {
|
public static ReviewInput create() {
|
||||||
ReviewInput r = createObject().cast();
|
ReviewInput r = createObject().cast();
|
||||||
r.init();
|
r.init();
|
||||||
@@ -26,6 +30,11 @@ public class ReviewInput extends JavaScriptObject {
|
|||||||
public final native void message(String m) /*-{ if(m)this.message=m; }-*/;
|
public final native void message(String m) /*-{ if(m)this.message=m; }-*/;
|
||||||
public final native void label(String n, short v) /*-{ this.labels[n]=v; }-*/;
|
public final native void label(String n, short v) /*-{ this.labels[n]=v; }-*/;
|
||||||
|
|
||||||
|
public final void notify(NotifyHandling e) {
|
||||||
|
_notify(e.name());
|
||||||
|
}
|
||||||
|
private final native void _notify(String n) /*-{ this.notify=n; }-*/;
|
||||||
|
|
||||||
private final native void init() /*-{
|
private final native void init() /*-{
|
||||||
this.labels = {};
|
this.labels = {};
|
||||||
this.strict_labels = true;
|
this.strict_labels = true;
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ package com.google.gerrit.client.diff;
|
|||||||
import com.google.gerrit.client.Gerrit;
|
import com.google.gerrit.client.Gerrit;
|
||||||
import com.google.gerrit.client.changes.ChangeApi;
|
import com.google.gerrit.client.changes.ChangeApi;
|
||||||
import com.google.gerrit.client.changes.ChangeInfo;
|
import com.google.gerrit.client.changes.ChangeInfo;
|
||||||
import com.google.gerrit.client.changes.ChangeScreen;
|
|
||||||
import com.google.gerrit.client.changes.CommentApi;
|
import com.google.gerrit.client.changes.CommentApi;
|
||||||
import com.google.gerrit.client.changes.CommentInfo;
|
import com.google.gerrit.client.changes.CommentInfo;
|
||||||
import com.google.gerrit.client.diff.DiffInfo.Region;
|
import com.google.gerrit.client.diff.DiffInfo.Region;
|
||||||
@@ -744,7 +743,9 @@ public class CodeMirrorDemo extends Screen {
|
|||||||
private Runnable upToChange() {
|
private Runnable upToChange() {
|
||||||
return new Runnable() {
|
return new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
Gerrit.display(PageLinks.toChange(revision), new ChangeScreen(revision));
|
Gerrit.display(PageLinks.toChange2(
|
||||||
|
revision.getParentKey(),
|
||||||
|
String.valueOf(revision.get())));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user