blob: 47bedd706f723fc2c749519929d84dc1f9aa254f [file] [log] [blame]
// Copyright (C) 2014 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.googlesource.gerrit.plugins.reviewers.client;
import static com.googlesource.gerrit.plugins.reviewers.client.AccountCapabilities.MODIFY_REVIEWERS_CONFIG;
import com.google.gerrit.client.rpc.NativeMap;
import com.google.gerrit.client.rpc.Natives;
import com.google.gerrit.plugin.client.rpc.RestApi;
import com.google.gerrit.plugin.client.screen.Screen;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.http.client.URL;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.SuggestBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwtexpui.globalkey.client.NpTextBox;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
public class ReviewersScreen extends HorizontalPanel {
private static final String REMOVE_BUTTON_IMG = "plugins/reviewers/static/remove_reviewer.png";
static class Factory implements Screen.EntryPoint {
@Override
public void onLoad(Screen screen) {
screen.setPageTitle("Reviewers");
screen.show(new ReviewersScreen(URL.decodeQueryString(screen.getToken(1))));
}
}
private boolean isOwner;
private boolean hasModifyReviewersConfigCapability;
private String projectName;
private Set<ReviewerEntry> rEntries;
ReviewersScreen(String projectName) {
setStyleName("reviewers-panel");
this.projectName = projectName;
this.rEntries = new HashSet<>();
new RestApi("access/")
.addParameter("project", projectName)
.get(
new AsyncCallback<NativeMap<ProjectAccessInfo>>() {
@Override
public void onSuccess(NativeMap<ProjectAccessInfo> result) {
isOwner = result.get(projectName).isOwner();
if (isOwner) {
display();
} else {
// TODO(davido): Find a way to run above and below requests in parallel
AccountCapabilities.queryPluginCapability(
new AsyncCallback<AccountCapabilities>() {
@Override
public void onSuccess(AccountCapabilities result) {
hasModifyReviewersConfigCapability =
result.canPerform(MODIFY_REVIEWERS_CONFIG);
display();
}
@Override
public void onFailure(Throwable caught) {}
});
}
}
@Override
public void onFailure(Throwable caught) {}
});
}
void display() {
new RestApi("projects")
.id(projectName)
.view("reviewers")
.get(
new AsyncCallback<JsArray<ReviewerFilterSection>>() {
@Override
public void onSuccess(JsArray<ReviewerFilterSection> result) {
display(result);
}
@Override
public void onFailure(Throwable caught) {}
});
}
void display(JsArray<ReviewerFilterSection> sections) {
add(createEntriesPanel(sections));
add(createInputPanel());
}
Panel createEntriesPanel(JsArray<ReviewerFilterSection> sections) {
Panel p = new VerticalPanel();
for (ReviewerFilterSection section : Natives.asList(sections)) {
Label filter = new Label(section.filter());
filter.addStyleName("reviewers-filterLabel");
p.add(filter);
for (String reviewer : Natives.asList(section.reviewers())) {
ReviewerEntry rEntry = new ReviewerEntry(section.filter(), reviewer);
rEntries.add(rEntry);
p.add(createOneEntry(rEntry));
}
}
return p;
}
Panel createOneEntry(final ReviewerEntry e) {
Label l = new Label(e.reviewer);
l.setStyleName("reviewers-reviewerLabel");
Image img = new Image(REMOVE_BUTTON_IMG);
Button removeButton = Button.wrap(img.getElement());
removeButton.setStyleName("reviewers-removeButton");
removeButton.setTitle("remove reviewer");
removeButton.addClickHandler(
new ClickHandler() {
@Override
public void onClick(final ClickEvent event) {
doSave(Action.REMOVE, e);
}
});
removeButton.setVisible(isModifiable());
HorizontalPanel p = new HorizontalPanel();
p.add(l);
p.add(removeButton);
return p;
}
Panel createInputPanel() {
Grid inputGrid = new Grid(2, 2);
final NpTextBox filterBox = new NpTextBox();
filterBox.getElement().setPropertyString("placeholder", "filter");
inputGrid.setText(0, 0, "Filter: ");
inputGrid.setWidget(0, 1, filterBox);
// TODO(davido): Remove hard coded start suggest char 3
final ReviewerSuggestOracle oracle = new ReviewerSuggestOracle(3, projectName);
final SuggestBox reviewerBox = new SuggestBox(oracle, new NpTextBox());
reviewerBox.getElement().setPropertyString("placeholder", "reviewer");
inputGrid.setText(1, 0, "Reviewer: ");
inputGrid.setWidget(1, 1, reviewerBox);
Button addButton = new Button("Add");
addButton.setStyleName("reviewers-addButton");
addButton.addClickHandler(
new ClickHandler() {
@Override
public void onClick(final ClickEvent event) {
ReviewerEntry e = new ReviewerEntry(filterBox.getValue(), reviewerBox.getValue());
if (!rEntries.contains(e) && !e.filter.isEmpty() && !e.reviewer.isEmpty()) {
doSave(Action.ADD, e);
}
filterBox.setText("");
reviewerBox.setText("");
}
});
filterBox.setEnabled(isModifiable());
reviewerBox.setEnabled(isModifiable());
addButton.setEnabled(isModifiable());
Panel p = new VerticalPanel();
p.setStyleName("reviewers-inputPanel");
p.add(inputGrid);
p.add(addButton);
return p;
}
boolean isModifiable() {
return isOwner || hasModifyReviewersConfigCapability;
}
void doSave(Action action, ReviewerEntry entry) {
ChangeReviewersInput in = ChangeReviewersInput.create();
in.setAction(action);
in.setFilter(entry.filter);
in.setReviewer(entry.reviewer);
reset();
new RestApi("projects")
.id(projectName)
.view("reviewers")
.put(
in,
new AsyncCallback<JsArray<ReviewerFilterSection>>() {
@Override
public void onSuccess(JsArray<ReviewerFilterSection> result) {
display(result);
}
@Override
public void onFailure(Throwable caught) {}
});
}
void reset() {
clear();
rEntries = new HashSet<>();
}
static class ReviewerEntry {
private String filter;
private String reviewer;
ReviewerEntry(String filter, String reviewer) {
this.filter = filter;
this.reviewer = reviewer;
}
@Override
public int hashCode() {
return Objects.hash(filter, reviewer);
}
@Override
public boolean equals(Object o) {
if (o == null || !(o instanceof ReviewerEntry)) {
return false;
}
ReviewerEntry other = (ReviewerEntry) o;
if (!this.filter.equals(other.filter) || !this.reviewer.equals(other.reviewer)) {
return false;
}
return true;
}
}
}