| // 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; |
| } |
| } |
| } |