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:
parent
0058c0a049
commit
097b957915
@ -54,6 +54,14 @@ public class PageLinks {
|
||||
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) {
|
||||
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.ProjectListScreen;
|
||||
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.ChangeScreen;
|
||||
import com.google.gerrit.client.changes.CustomDashboardScreen;
|
||||
@ -190,6 +191,9 @@ public class Dispatcher {
|
||||
} else if (matchPrefix("/c/", token)) {
|
||||
change(token);
|
||||
|
||||
} else if (matchPrefix("/c2/", token)) {
|
||||
change2(token);
|
||||
|
||||
} else if (matchExact(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) {
|
||||
String token = toPublish(ps);
|
||||
new AsyncSplit(token) {
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
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.ParameterizedString;
|
||||
import com.google.gerrit.reviewdb.client.Branch;
|
||||
@ -45,19 +46,26 @@ public class GitwebLink {
|
||||
return !ps.isDraft() || type.getLinkDrafts();
|
||||
}
|
||||
|
||||
public boolean canLink(RevisionInfo revision) {
|
||||
return revision.draft() || type.getLinkDrafts();
|
||||
}
|
||||
|
||||
public String 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());
|
||||
|
||||
final Map<String, String> p = new HashMap<String, String>();
|
||||
p.put("project", encode(project.get()));
|
||||
p.put("commit", encode(ps.getRevision().get()));
|
||||
Map<String, String> p = new HashMap<String, String>();
|
||||
p.put("project", encode(project));
|
||||
p.put("commit", encode(commit));
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
private static RestApi change(int id) {
|
||||
public static RestApi change(int id) {
|
||||
// TODO Switch to triplet project~branch~id format in URI.
|
||||
return new RestApi("/changes/").id(String.valueOf(id));
|
||||
}
|
||||
|
@ -22,6 +22,8 @@ public interface ChangeConstants extends Constants {
|
||||
String statusLongMerged();
|
||||
String statusLongAbandoned();
|
||||
String statusLongDraft();
|
||||
String readyToSubmit();
|
||||
String mergeConflict();
|
||||
|
||||
String myDashboardTitle();
|
||||
String unknownDashboardTitle();
|
||||
@ -53,7 +55,9 @@ public interface ChangeConstants extends Constants {
|
||||
String expandCollapseDependencies();
|
||||
String previousPatchSet();
|
||||
String nextPatchSet();
|
||||
String keyReload();
|
||||
String keyPublishComments();
|
||||
String keyEditTopic();
|
||||
|
||||
String patchTableColumnName();
|
||||
String patchTableColumnComments();
|
||||
@ -63,6 +67,7 @@ public interface ChangeConstants extends Constants {
|
||||
String patchTableDiffUnified();
|
||||
String patchTableDownloadPreImage();
|
||||
String patchTableDownloadPostImage();
|
||||
String patchTableBinary();
|
||||
String commitMessage();
|
||||
String fileCommentHeader();
|
||||
|
||||
|
@ -3,6 +3,8 @@ statusLongSubmitted = Submitted, Merge Pending
|
||||
statusLongMerged = Merged
|
||||
statusLongAbandoned = Abandoned
|
||||
statusLongDraft = Draft
|
||||
readyToSubmit = Ready to Submit
|
||||
mergeConflict = Merge Conflict
|
||||
|
||||
starredHeading = Starred Changes
|
||||
watchedHeading = Open Changes of Watched Projects
|
||||
@ -33,7 +35,9 @@ upToChangeList = Up to change list
|
||||
expandCollapseDependencies = Expands / Collapses dependencies section
|
||||
previousPatchSet = Previous patch set
|
||||
nextPatchSet = Next patch set
|
||||
keyReload = Reload change
|
||||
keyPublishComments = Review and publish comments
|
||||
keyEditTopic = Edit change topic
|
||||
|
||||
patchTableColumnName = File Path
|
||||
patchTableColumnComments = Comments
|
||||
@ -43,6 +47,7 @@ patchTableDiffSideBySide = Side-by-Side
|
||||
patchTableDiffUnified = Unified
|
||||
patchTableDownloadPreImage = old
|
||||
patchTableDownloadPostImage = new
|
||||
patchTableBinary = Binary
|
||||
commitMessage = Commit Message
|
||||
fileCommentHeader = File Comment:
|
||||
|
||||
|
@ -15,9 +15,11 @@
|
||||
package com.google.gerrit.client.changes;
|
||||
|
||||
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.NativeString;
|
||||
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.reviewdb.client.Change;
|
||||
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.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
public class ChangeInfo extends JavaScriptObject {
|
||||
public final void init() {
|
||||
if (labels0() != null) {
|
||||
labels0().copyKeysIntoChildren("_name");
|
||||
if (all_labels() != null) {
|
||||
all_labels().copyKeysIntoChildren("_name");
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,7 +73,7 @@ public class ChangeInfo extends JavaScriptObject {
|
||||
}
|
||||
|
||||
public final Set<String> labels() {
|
||||
return labels0().keySet();
|
||||
return all_labels().keySet();
|
||||
}
|
||||
|
||||
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 reviewed() /*-{ return this.reviewed ? true : false; }-*/;
|
||||
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 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()
|
||||
/*-{ return this.hasOwnProperty('permitted_labels') }-*/;
|
||||
private final native NativeMap<JavaScriptObject> _permitted_labels()
|
||||
public final native NativeMap<JsArrayString> 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)
|
||||
/*-{ return this.permitted_labels[n]; }-*/;
|
||||
|
||||
public final native JsArray<AccountInfo> 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 boolean _more_changes()
|
||||
/*-{ 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 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; }-*/;
|
||||
|
||||
public final Set<String> values() {
|
||||
return Natives.keys(_values());
|
||||
}
|
||||
@ -147,15 +163,102 @@ public class ChangeInfo extends JavaScriptObject {
|
||||
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() {
|
||||
}
|
||||
}
|
||||
|
||||
public static class ApprovalInfo extends AccountInfo {
|
||||
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() {
|
||||
}
|
||||
}
|
||||
|
||||
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 patchTableDrafts(@PluralCount int count);
|
||||
String patchTableSize_Modify(int insertions, int deletions);
|
||||
String patchTableSize_LongModify(int insertions, int deletions);
|
||||
String patchTableSize_Lines(@PluralCount int insertions);
|
||||
|
||||
String removeReviewer(String fullName);
|
||||
|
@ -17,6 +17,7 @@ submitPatchSet = Submit Patch Set {0}
|
||||
patchTableComments = {0} comments
|
||||
patchTableDrafts = {0} drafts
|
||||
patchTableSize_Modify = +{0}, -{1}
|
||||
patchTableSize_LongModify = {0} inserted, {1} deleted
|
||||
patchTableSize_Lines = {0} lines
|
||||
|
||||
removeReviewer = Remove reviewer {0}
|
||||
|
@ -17,6 +17,10 @@ package com.google.gerrit.client.changes;
|
||||
import com.google.gwt.core.client.JavaScriptObject;
|
||||
|
||||
public class ReviewInput extends JavaScriptObject {
|
||||
public static enum NotifyHandling {
|
||||
NONE, OWNER, OWNER_REVIEWERS, ALL;
|
||||
}
|
||||
|
||||
public static ReviewInput create() {
|
||||
ReviewInput r = createObject().cast();
|
||||
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 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() /*-{
|
||||
this.labels = {};
|
||||
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.changes.ChangeApi;
|
||||
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.CommentInfo;
|
||||
import com.google.gerrit.client.diff.DiffInfo.Region;
|
||||
@ -744,7 +743,9 @@ public class CodeMirrorDemo extends Screen {
|
||||
private Runnable upToChange() {
|
||||
return new Runnable() {
|
||||
public void run() {
|
||||
Gerrit.display(PageLinks.toChange(revision), new ChangeScreen(revision));
|
||||
Gerrit.display(PageLinks.toChange2(
|
||||
revision.getParentKey(),
|
||||
String.valueOf(revision.get())));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user