diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/ui/list/FilterableSimpleList.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/ui/list/FilterableSimpleList.java new file mode 100644 index 00000000000..1a79ab7b9de --- /dev/null +++ b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/ui/list/FilterableSimpleList.java @@ -0,0 +1,107 @@ +/** + * Copyright (c) 2012-2017 Red Hat, Inc. All rights reserved. This program and the accompanying + * materials are made available under the terms of the Eclipse Public License v1.0 which accompanies + * this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html + * + *

Contributors: Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.ide.ui.list; + +import static com.google.gwt.event.dom.client.KeyCodes.KEY_BACKSPACE; +import static com.google.gwt.event.dom.client.KeyCodes.KEY_ESCAPE; + +import com.google.gwt.user.client.ui.FocusPanel; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * A focus panel witch contain {@link SimpleList} widget. Supports filtering items according to + * typed from keyboard symbols. + */ +public class FilterableSimpleList extends FocusPanel { + private Map filterableItems; + private SimpleList simpleList; + private StringBuilder filter; + + public interface FilterChangedHandler { + /** Is called when search filter is changed */ + void onFilterChanged(String filter); + } + + private FilterableSimpleList( + SimpleList.View view, + SimpleList.Css css, + SimpleList.ListItemRenderer itemRenderer, + SimpleList.ListEventDelegate eventDelegate, + FilterChangedHandler filterChangedHandler) { + super(); + simpleList = SimpleList.create(view, css, itemRenderer, eventDelegate); + this.getElement().setAttribute("style", "outline: 0"); + + addKeyDownHandler( + keyDownEvent -> { + int keyCode = keyDownEvent.getNativeEvent().getKeyCode(); + if (keyCode == KEY_BACKSPACE) { + filter.deleteCharAt(filter.length() - 1); + filterChangedHandler.onFilterChanged(filter.toString()); + } else if (keyCode == KEY_ESCAPE && !filter.toString().isEmpty()) { + clearFilter(); + keyDownEvent.stopPropagation(); + filterChangedHandler.onFilterChanged(""); + } else { + return; + } + doFilter(); + }); + + addKeyPressHandler( + keyPressEvent -> { + filter.append(String.valueOf(keyPressEvent.getCharCode())); + filterChangedHandler.onFilterChanged(filter.toString()); + doFilter(); + }); + + add(simpleList); + filter = new StringBuilder(); + } + + public static FilterableSimpleList create( + SimpleList.View view, + SimpleList.Css simpleListCss, + SimpleList.ListItemRenderer itemRenderer, + SimpleList.ListEventDelegate eventDelegate, + FilterChangedHandler filterChangedHandler) { + return new FilterableSimpleList<>( + view, simpleListCss, itemRenderer, eventDelegate, filterChangedHandler); + } + + /** + * Render the list with given items. + * + * @param filterableItems map with filterable value as a key and the item as a value + */ + public void render(Map filterableItems) { + this.filterableItems = filterableItems; + doFilter(); + } + + /** Reset the filter. */ + public void clearFilter() { + filter.delete(0, filter.length() + 1); + } + + /** Returns the selection model from parent {@link SimpleList} widget. */ + public HasSelection getSelectionModel() { + return simpleList.getSelectionModel(); + } + + private void doFilter() { + simpleList.render( + filterableItems + .keySet() + .stream() + .filter(name -> name.startsWith(filter.toString())) + .map(name -> filterableItems.get(name)) + .collect(Collectors.toList())); + } +} diff --git a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/ui/list/SimpleList.java b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/ui/list/SimpleList.java index 920abee265f..56ea9b1bf5e 100644 --- a/ide/commons-gwt/src/main/java/org/eclipse/che/ide/ui/list/SimpleList.java +++ b/ide/commons-gwt/src/main/java/org/eclipse/che/ide/ui/list/SimpleList.java @@ -334,7 +334,7 @@ private void maybeRemoveSelectionFromElement() { private HTML widget; - private SimpleList( + SimpleList( View view, Element container, Element itemHolder, diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/GitLocalizationConstant.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/GitLocalizationConstant.java index 681a9940006..d6b57017712 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/GitLocalizationConstant.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/GitLocalizationConstant.java @@ -360,12 +360,15 @@ public interface GitLocalizationConstant extends Messages { @Key("view.branch.delete_ask") String branchDeleteAsk(String name); - @Key("view.branch.filter.label") - String branchFilterLabel(); + @Key("view.branch.local_remote_filter.label") + String branchLocalRemoteFilterLabel(); @Key("view.branch.title") String branchTitle(); + @Key("view.branch.search_filter.label") + String branchSearchFilterLabel(); + // Commit @Key("view.commit.commit_message") String commitMessage(String revision, String time); diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/branch/BranchPresenter.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/branch/BranchPresenter.java index 8541fbf91c2..8d6276a6da7 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/branch/BranchPresenter.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/branch/BranchPresenter.java @@ -21,7 +21,6 @@ import org.eclipse.che.api.git.shared.Branch; import org.eclipse.che.api.git.shared.BranchListMode; import org.eclipse.che.api.git.shared.CheckoutRequest; -import org.eclipse.che.ide.api.app.AppContext; import org.eclipse.che.ide.api.notification.NotificationManager; import org.eclipse.che.ide.api.resources.Project; import org.eclipse.che.ide.dto.DtoFactory; @@ -54,7 +53,6 @@ public class BranchPresenter implements BranchView.ActionDelegate { private final DialogFactory dialogFactory; private final GitServiceClient service; private final GitLocalizationConstant constant; - private final AppContext appContext; private final NotificationManager notificationManager; private Branch selectedBranch; @@ -62,12 +60,11 @@ public class BranchPresenter implements BranchView.ActionDelegate { /** Create presenter. */ @Inject - public BranchPresenter( + BranchPresenter( BranchView view, DtoFactory dtoFactory, GitServiceClient service, GitLocalizationConstant constant, - AppContext appContext, NotificationManager notificationManager, GitOutputConsoleFactory gitOutputConsoleFactory, ProcessesPanelPresenter processesPanelPresenter, @@ -80,7 +77,6 @@ public BranchPresenter( this.view.setDelegate(this); this.service = service; this.constant = constant; - this.appContext = appContext; this.notificationManager = notificationManager; } @@ -91,8 +87,10 @@ public void showBranches(Project project) { } @Override - public void onCloseClicked() { + public void onClose() { view.close(); + view.setTextToSearchFilterLabel(""); + view.clearSearchFilter(); } @Override @@ -240,10 +238,15 @@ public void onBranchUnselected() { } @Override - public void onFilterValueChanged() { + public void onLocalRemoteFilterChanged() { getBranches(); } + @Override + public void onSearchFilterChanged(String filter) { + view.setTextToSearchFilterLabel(filter); + } + @Override public void onBranchSelected(@NotNull Branch branch) { selectedBranch = branch; diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/branch/BranchView.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/branch/BranchView.java index e89b42ba406..8f11c40fa4a 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/branch/BranchView.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/branch/BranchView.java @@ -22,9 +22,9 @@ */ public interface BranchView extends View { /** Needs for delegate some function into Branch view. */ - public interface ActionDelegate { - /** Performs any actions appropriate in response to the user having pressed the Close button. */ - void onCloseClicked(); + interface ActionDelegate { + /** Performs any actions appropriate in response to the user having pressed the Close action. */ + void onClose(); /** * Performs any actions appropriate in response to the user having pressed the Rename button. @@ -56,8 +56,13 @@ public interface ActionDelegate { /** Performs any action in response to the user do not have any selected branch. */ void onBranchUnselected(); - /** Performs any action in response to the user having selected branch filter. */ - void onFilterValueChanged(); + /** + * Performs any action in response to the user having selected branch filter (local/remote/all). + */ + void onLocalRemoteFilterChanged(); + + /** Is called when search filter is updated */ + void onSearchFilterChanged(String filter); } /** @@ -96,4 +101,14 @@ public interface ActionDelegate { /** Show dialog. */ void showDialogIfClosed(); + + /** + * Set new content to search filter label. + * + * @param text text to set + */ + void setTextToSearchFilterLabel(String text); + + /** Clear search filter. */ + void clearSearchFilter(); } diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/branch/BranchViewImpl.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/branch/BranchViewImpl.java index 4078b5abfb3..1b79360558c 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/branch/BranchViewImpl.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/branch/BranchViewImpl.java @@ -12,13 +12,13 @@ import com.google.gwt.core.client.GWT; import com.google.gwt.event.dom.client.ChangeEvent; -import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.safehtml.shared.SafeHtmlBuilder; 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.Label; import com.google.gwt.user.client.ui.ListBox; import com.google.gwt.user.client.ui.ScrollPanel; import com.google.gwt.user.client.ui.UIObject; @@ -29,12 +29,14 @@ import elemental.html.TableCellElement; import elemental.html.TableElement; import java.util.List; +import java.util.stream.Collectors; import javax.validation.constraints.NotNull; import org.eclipse.che.api.git.shared.Branch; +import org.eclipse.che.ide.FontAwesome; import org.eclipse.che.ide.ext.git.client.GitLocalizationConstant; import org.eclipse.che.ide.ext.git.client.GitResources; import org.eclipse.che.ide.ui.dialogs.DialogFactory; -import org.eclipse.che.ide.ui.dialogs.confirm.ConfirmCallback; +import org.eclipse.che.ide.ui.list.FilterableSimpleList; import org.eclipse.che.ide.ui.list.SimpleList; import org.eclipse.che.ide.ui.window.Window; import org.eclipse.che.ide.util.dom.Elements; @@ -44,6 +46,7 @@ * The implementation of {@link BranchView}. * * @author Andrey Plotnikov + * @author Igor Vinokur */ @Singleton public class BranchViewImpl extends Window implements BranchView { @@ -57,7 +60,9 @@ interface BranchViewImplUiBinder extends UiBinder {} Button btnCreate; Button btnCheckout; @UiField ScrollPanel branchesPanel; - @UiField ListBox filter; + @UiField ListBox localRemoteFilter; + @UiField Label searchFilterLabel; + @UiField Label searchFilterIcon; @UiField(provided = true) final GitResources res; @@ -66,10 +71,9 @@ interface BranchViewImplUiBinder extends UiBinder {} final GitLocalizationConstant locale; private final DialogFactory dialogFactory; - private SimpleList branches; + private FilterableSimpleList branchesList; private ActionDelegate delegate; - /** Create presenter. */ @Inject protected BranchViewImpl( GitResources resources, @@ -81,17 +85,16 @@ protected BranchViewImpl( this.dialogFactory = dialogFactory; this.ensureDebugId("git-branches-window"); - Widget widget = ourUiBinder.createAndBindUi(this); + setTitle(locale.branchTitle()); + setWidget(ourUiBinder.createAndBindUi(this)); + searchFilterIcon.getElement().setInnerHTML(FontAwesome.SEARCH); - this.setTitle(locale.branchTitle()); - this.setWidget(widget); - - TableElement breakPointsElement = Elements.createTableElement(); - breakPointsElement.setAttribute("style", "width: 100%"); + TableElement branchElement = Elements.createTableElement(); + branchElement.setAttribute("style", "width: 100%"); SimpleList.ListEventDelegate listBranchesDelegate = new SimpleList.ListEventDelegate() { public void onListItemClicked(Element itemElement, Branch itemData) { - branches.getSelectionModel().setSelectedItem(itemData); + branchesList.getSelectionModel().setSelectedItem(itemData); delegate.onBranchSelected(itemData); } @@ -132,90 +135,67 @@ public Element createElement() { return Elements.createTRElement(); } }; - branches = - SimpleList.create( - (SimpleList.View) breakPointsElement, + branchesList = + FilterableSimpleList.create( + (SimpleList.View) branchElement, coreRes.defaultSimpleListCss(), listBranchesRenderer, - listBranchesDelegate); - this.branchesPanel.add(branches); + listBranchesDelegate, + this::onFilterChanged); + this.branchesPanel.add(branchesList); - this.filter.addItem("All", "all"); - this.filter.addItem("Local", "local"); - this.filter.addItem("Remote", "remote"); + this.localRemoteFilter.addItem("All", "all"); + this.localRemoteFilter.addItem("Local", "local"); + this.localRemoteFilter.addItem("Remote", "remote"); createButtons(); + addHandlers(); + } + + private void onFilterChanged(String filter) { + if (branchesList.getSelectionModel().getSelectedItem() == null) { + delegate.onBranchUnselected(); + } + delegate.onSearchFilterChanged(filter); } - @UiHandler("filter") - public void onFilterChanged(ChangeEvent event) { - delegate.onFilterValueChanged(); + @UiHandler("localRemoteFilter") + public void onLocalRemoteFilterChanged(ChangeEvent event) { + delegate.onLocalRemoteFilterChanged(); + branchesList.setFocus(true); + } + + private void addHandlers() { + ClickHandler clickHandler = event -> branchesList.setFocus(true); + localRemoteFilter.addClickHandler(clickHandler); + searchFilterLabel.addClickHandler(clickHandler); + searchFilterIcon.addClickHandler(clickHandler); } private void createButtons() { btnClose = - createButton( - locale.buttonClose(), - "git-branches-close", - new ClickHandler() { - - @Override - public void onClick(ClickEvent event) { - delegate.onCloseClicked(); - } - }); + createButton(locale.buttonClose(), "git-branches-close", event -> delegate.onClose()); addButtonToFooter(btnClose); btnRename = createButton( - locale.buttonRename(), - "git-branches-rename", - new ClickHandler() { - - @Override - public void onClick(ClickEvent event) { - delegate.onRenameClicked(); - } - }); + locale.buttonRename(), "git-branches-rename", event -> delegate.onRenameClicked()); addButtonToFooter(btnRename); btnDelete = - createButton( - locale.buttonDelete(), - "git-branches-delete", - new ClickHandler() { - - @Override - public void onClick(ClickEvent event) { - onDeleteClicked(); - } - }); + createButton(locale.buttonDelete(), "git-branches-delete", event -> onDeleteClicked()); addButtonToFooter(btnDelete); btnCreate = createButton( - locale.buttonCreate(), - "git-branches-create", - new ClickHandler() { - - @Override - public void onClick(ClickEvent event) { - delegate.onCreateClicked(); - } - }); + locale.buttonCreate(), "git-branches-create", event -> delegate.onCreateClicked()); addButtonToFooter(btnCreate); btnCheckout = createButton( locale.buttonCheckout(), "git-branches-checkout", - new ClickHandler() { - - @Override - public void onClick(ClickEvent event) { - delegate.onCheckoutClicked(); - } - }); + event -> delegate.onCheckoutClicked()); addButtonToFooter(btnCheckout); } @@ -223,13 +203,9 @@ private void onDeleteClicked() { dialogFactory .createConfirmDialog( locale.branchDelete(), - locale.branchDeleteAsk(branches.getSelectionModel().getSelectedItem().getName()), - new ConfirmCallback() { - @Override - public void accepted() { - delegate.onDeleteClicked(); - } - }, + locale.branchDeleteAsk( + branchesList.getSelectionModel().getSelectedItem().getDisplayName()), + () -> delegate.onDeleteClicked(), null) .show(); } @@ -237,7 +213,7 @@ public void accepted() { @Override protected void onEnterClicked() { if (isWidgetFocused(btnClose)) { - delegate.onCloseClicked(); + delegate.onClose(); return; } @@ -261,34 +237,30 @@ protected void onEnterClicked() { } } - /** {@inheritDoc} */ @Override public void setDelegate(ActionDelegate delegate) { this.delegate = delegate; } - /** {@inheritDoc} */ @Override public void setBranches(@NotNull List branches) { - this.branches.render(branches); - if (this.branches.getSelectionModel().getSelectedItem() == null) { + branchesList.render( + branches.stream().collect(Collectors.toMap(Branch::getDisplayName, branch -> branch))); + if (branchesList.getSelectionModel().getSelectedItem() == null) { delegate.onBranchUnselected(); } } - /** {@inheritDoc} */ @Override public void setEnableDeleteButton(boolean enabled) { btnDelete.setEnabled(enabled); } - /** {@inheritDoc} */ @Override public void setEnableCheckoutButton(boolean enabled) { btnCheckout.setEnabled(enabled); } - /** {@inheritDoc} */ @Override public void setEnableRenameButton(boolean enabled) { btnRename.setEnabled(enabled); @@ -296,20 +268,34 @@ public void setEnableRenameButton(boolean enabled) { @Override public String getFilterValue() { - return filter.getSelectedValue(); + return localRemoteFilter.getSelectedValue(); } - /** {@inheritDoc} */ @Override public void close() { this.hide(); } - /** {@inheritDoc} */ @Override public void showDialogIfClosed() { if (!super.isShowing()) { this.show(btnCreate); + branchesList.setFocus(true); } } + + @Override + public void setTextToSearchFilterLabel(String filter) { + searchFilterLabel.setText(filter.isEmpty() ? locale.branchSearchFilterLabel() : filter); + } + + @Override + public void clearSearchFilter() { + branchesList.clearFilter(); + } + + @Override + public void onClose() { + delegate.onClose(); + } } diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/branch/BranchViewImpl.ui.xml b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/branch/BranchViewImpl.ui.xml index 3d73b4e1cdb..fe4e30d9fe4 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/branch/BranchViewImpl.ui.xml +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/branch/BranchViewImpl.ui.xml @@ -23,16 +23,43 @@ .alignLeft { float: left; } + + .label { + float: left; + margin-top: 2px; + } + + .filterIcon { + float: left; + margin-left: 5px; + margin-right: 5px; + margin-top: -2px; + font-size: 16px; + } + + .filterPanel { + float: left; + border: solid 1px rgba(0, 0, 0, 0.2); + border-radius: 6px; + margin-left: 5px; + } - + - - - + + + + + + + - + diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/branchlist/BranchListPresenter.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/branchlist/BranchListPresenter.java index fc28cbb2144..daabfbd1418 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/branchlist/BranchListPresenter.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/branchlist/BranchListPresenter.java @@ -98,8 +98,10 @@ public void showBranches(Project project, Resource selectedItem) { } @Override - public void onCloseClicked() { + public void onClose() { view.close(); + view.updateSearchFilterLabel(""); + view.clearSearchFilter(); } @Override @@ -154,6 +156,11 @@ public void onBranchUnselected() { view.setEnableCompareButton(false); } + @Override + public void onSearchFilterChanged(String filter) { + view.updateSearchFilterLabel(filter); + } + @Override public void onBranchSelected(@NotNull Branch branch) { selectedBranch = branch; diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/branchlist/BranchListView.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/branchlist/BranchListView.java index 1b0027d9f16..e1cb23fd460 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/branchlist/BranchListView.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/branchlist/BranchListView.java @@ -23,8 +23,8 @@ public interface BranchListView extends View { /** Needs for delegate some function into list of branches view. */ interface ActionDelegate { - /** Performs any actions appropriate in response to the user having pressed the Close button. */ - void onCloseClicked(); + /** Performs any actions appropriate in response to the user having pressed the Close action. */ + void onClose(); /** * Performs any actions appropriate in response to the user having pressed the Compare button. @@ -40,6 +40,9 @@ interface ActionDelegate { /** Performs any action in response to the user do not have any selected branch. */ void onBranchUnselected(); + + /** Is called when search filter is changed. */ + void onSearchFilterChanged(String filter); } /** @@ -67,4 +70,14 @@ interface ActionDelegate { /** Show dialog. */ void showDialog(); + + /** + * Set new content to search filter label. + * + * @param filter updated filter + */ + void updateSearchFilterLabel(String filter); + + /** Clear search filter. */ + void clearSearchFilter(); } diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/branchlist/BranchListViewImpl.java b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/branchlist/BranchListViewImpl.java index 566ca4ff54d..48d16f99189 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/branchlist/BranchListViewImpl.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/branchlist/BranchListViewImpl.java @@ -11,12 +11,11 @@ package org.eclipse.che.ide.ext.git.client.compare.branchlist; import com.google.gwt.core.client.GWT; -import com.google.gwt.event.dom.client.ClickEvent; -import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.safehtml.shared.SafeHtmlBuilder; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.ScrollPanel; import com.google.gwt.user.client.ui.UIObject; import com.google.gwt.user.client.ui.Widget; @@ -26,10 +25,13 @@ import elemental.html.TableCellElement; import elemental.html.TableElement; import java.util.List; +import java.util.stream.Collectors; import javax.validation.constraints.NotNull; import org.eclipse.che.api.git.shared.Branch; +import org.eclipse.che.ide.FontAwesome; import org.eclipse.che.ide.ext.git.client.GitLocalizationConstant; import org.eclipse.che.ide.ext.git.client.GitResources; +import org.eclipse.che.ide.ui.list.FilterableSimpleList; import org.eclipse.che.ide.ui.list.SimpleList; import org.eclipse.che.ide.ui.window.Window; import org.eclipse.che.ide.util.dom.Elements; @@ -49,13 +51,17 @@ interface BranchViewImplUiBinder extends UiBinder {} Button btnClose; Button btnCompare; @UiField ScrollPanel branchesPanel; + @UiField Label searchFilterLabel; + @UiField Label searchFilterIcon; @UiField(provided = true) final GitResources res; + @UiField(provided = true) + GitLocalizationConstant locale; + private ActionDelegate delegate; - private final GitLocalizationConstant locale; - private final SimpleList branches; + private final FilterableSimpleList branchesList; @Inject protected BranchListViewImpl( @@ -66,17 +72,16 @@ protected BranchListViewImpl( this.locale = locale; this.ensureDebugId("git-compare-branch-window"); - Widget widget = uiBinder.createAndBindUi(this); - - this.setTitle(locale.compareWithBranchTitle()); - this.setWidget(widget); + setTitle(locale.compareWithBranchTitle()); + setWidget(uiBinder.createAndBindUi(this)); + searchFilterIcon.getElement().setInnerHTML(FontAwesome.SEARCH); - TableElement tableElement = Elements.createTableElement(); - tableElement.setAttribute("style", "width: 100%"); + TableElement branchElement = Elements.createTableElement(); + branchElement.setAttribute("style", "width: 100%"); SimpleList.ListEventDelegate listBranchesDelegate = new SimpleList.ListEventDelegate() { public void onListItemClicked(Element itemElement, Branch itemData) { - branches.getSelectionModel().setSelectedItem(itemData); + branchesList.getSelectionModel().setSelectedItem(itemData); delegate.onBranchSelected(itemData); } @@ -119,75 +124,82 @@ public Element createElement() { return Elements.createTRElement(); } }; - branches = - SimpleList.create( - (SimpleList.View) tableElement, + branchesList = + FilterableSimpleList.create( + (SimpleList.View) branchElement, coreRes.defaultSimpleListCss(), listBranchesRenderer, - listBranchesDelegate); - this.branchesPanel.add(branches); + listBranchesDelegate, + this::onFilterChanged); + branchesPanel.add(branchesList); + searchFilterLabel.addClickHandler(event -> branchesList.setFocus(true)); createButtons(); } - /** {@inheritDoc} */ + private void onFilterChanged(String filter) { + if (branchesList.getSelectionModel().getSelectedItem() == null) { + delegate.onBranchUnselected(); + } + delegate.onSearchFilterChanged(filter); + } + @Override public void setDelegate(ActionDelegate delegate) { this.delegate = delegate; } - /** {@inheritDoc} */ @Override public void setBranches(@NotNull List branches) { - this.branches.render(branches); - if (this.branches.getSelectionModel().getSelectedItem() == null) { + branchesList.render( + branches.stream().collect(Collectors.toMap(Branch::getDisplayName, branch -> branch))); + if (branchesList.getSelectionModel().getSelectedItem() == null) { delegate.onBranchUnselected(); } } - /** {@inheritDoc} */ @Override public void setEnableCompareButton(boolean enabled) { btnCompare.setEnabled(enabled); } - /** {@inheritDoc} */ @Override public void close() { this.hide(); } - /** {@inheritDoc} */ @Override public void showDialog() { this.show(); + branchesList.setFocus(true); + } + + @Override + public void updateSearchFilterLabel(String filter) { + searchFilterLabel.setText(filter.isEmpty() ? locale.branchSearchFilterLabel() : filter); + } + + @Override + public void clearSearchFilter() { + branchesList.clearFilter(); + searchFilterLabel.setText(locale.branchSearchFilterLabel()); + } + + @Override + public void onClose() { + delegate.onClose(); } private void createButtons() { btnClose = - createButton( - locale.buttonClose(), - "git-compare-branch-close", - new ClickHandler() { - - @Override - public void onClick(ClickEvent event) { - delegate.onCloseClicked(); - } - }); + createButton(locale.buttonClose(), "git-compare-branch-close", event -> delegate.onClose()); addButtonToFooter(btnClose); btnCompare = createButton( locale.buttonCompare(), "git-compare-branch-compare", - new ClickHandler() { - - @Override - public void onClick(ClickEvent event) { - delegate.onCompareClicked(); - } - }); + event -> delegate.onCompareClicked()); addButtonToFooter(btnCompare); } } diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/branchlist/BranchListViewImpl.ui.xml b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/branchlist/BranchListViewImpl.ui.xml index 832dc8ed889..c0f6633a83a 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/branchlist/BranchListViewImpl.ui.xml +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/java/org/eclipse/che/ide/ext/git/client/compare/branchlist/BranchListViewImpl.ui.xml @@ -13,15 +13,44 @@ + .emptyBorder { margin: 6px; } + + .filterLabel { + float: left; + margin-top: 2px; + } + + .filterIcon { + float: left; + margin-left: 5px; + margin-right: 5px; + margin-top: -2px; + font-size: 16px; + } + + .filterPanel { + height: 20px; + border: solid 1px rgba(0, 0, 0, 0.2); + border-radius: 6px; + } - + + + + + + + - + - \ No newline at end of file + diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/main/resources/org/eclipse/che/ide/ext/git/client/GitLocalizationConstant.properties b/plugins/plugin-git/che-plugin-git-ext-git/src/main/resources/org/eclipse/che/ide/ext/git/client/GitLocalizationConstant.properties index b965c1d3827..7bc89acd84c 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/main/resources/org/eclipse/che/ide/ext/git/client/GitLocalizationConstant.properties +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/main/resources/org/eclipse/che/ide/ext/git/client/GitLocalizationConstant.properties @@ -131,8 +131,9 @@ view.branch.title_rename=Enter branch name view.branch.type_rename=Name: view.branch.delete=Delete branch view.branch.delete_ask=Are you sure you want to delete branch {0}? -view.branch.filter.label=Show branches: +view.branch.local_remote_filter.label=Show branches: view.branch.title=Branches +view.branch.search_filter.label=Type from keyboard to filter branches #Reset view.reset.files.title=Select files to reset view.reset.commit.title=Reset to commit diff --git a/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/branch/BranchPresenterTest.java b/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/branch/BranchPresenterTest.java index d3caf9b74f0..668dc217823 100644 --- a/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/branch/BranchPresenterTest.java +++ b/plugins/plugin-git/che-plugin-git-ext-git/src/test/java/org/eclipse/che/ide/ext/git/client/branch/BranchPresenterTest.java @@ -57,10 +57,10 @@ public class BranchPresenterTest extends BaseTest { @Captor private ArgumentCaptor inputCallbackCaptor; @Captor private ArgumentCaptor confirmCallbackCaptor; - public static final String BRANCH_NAME = "branchName"; - public static final String REMOTE_BRANCH_NAME = "origin/branchName"; - public static final boolean IS_REMOTE = true; - public static final boolean IS_ACTIVE = true; + private static final String BRANCH_NAME = "branchName"; + private static final String REMOTE_BRANCH_NAME = "origin/branchName"; + private static final boolean IS_REMOTE = true; + private static final boolean IS_ACTIVE = true; @Mock private BranchView view; @Mock private Branch selectedBranch; @Mock private DialogFactory dialogFactory; @@ -79,7 +79,6 @@ public void disarm() { dtoFactory, service, constant, - appContext, notificationManager, gitOutputConsoleFactory, processesPanelPresenter, @@ -164,7 +163,7 @@ public void shouldShowRemoteBranchesWheBranchesFilterIsSetToRemote() throws Exce @Test public void testOnCloseClicked() throws Exception { - presenter.onCloseClicked(); + presenter.onClose(); verify(view).close(); } diff --git a/selenium/che-selenium-test/src/main/java/org/eclipse/che/selenium/pageobject/git/Git.java b/selenium/che-selenium-test/src/main/java/org/eclipse/che/selenium/pageobject/git/Git.java index bec9a43fa52..58da290a36f 100644 --- a/selenium/che-selenium-test/src/main/java/org/eclipse/che/selenium/pageobject/git/Git.java +++ b/selenium/che-selenium-test/src/main/java/org/eclipse/che/selenium/pageobject/git/Git.java @@ -156,6 +156,25 @@ public void waitBranchInTheListWithCoState(String nameOfTheBranch) { loader.waitOnClosed(); } + /** + * wait for the branch search filter label to be with given text. + * + * @param text text to check + */ + public void waitBranchSearchFilerWithText(String text) { + gitBranchesForm.waitBranchesForm(); + gitBranchesForm.waitSearchFilerWithText(text); + } + + /** + * Type text to the branch search filter. + * + * @param text typed text + */ + public void typeToBranchSearchFilter(String text) { + gitBranchesForm.typeSearchFilter(text); + } + /** click on Close button and wait while form will be closed */ public void closeBranchesForm() { gitBranchesForm.clickCloseBtn(); diff --git a/selenium/che-selenium-test/src/main/java/org/eclipse/che/selenium/pageobject/git/GitBranches.java b/selenium/che-selenium-test/src/main/java/org/eclipse/che/selenium/pageobject/git/GitBranches.java index cda9f2c7402..653b49c804f 100644 --- a/selenium/che-selenium-test/src/main/java/org/eclipse/che/selenium/pageobject/git/GitBranches.java +++ b/selenium/che-selenium-test/src/main/java/org/eclipse/che/selenium/pageobject/git/GitBranches.java @@ -10,6 +10,8 @@ */ package org.eclipse.che.selenium.pageobject.git; +import static org.eclipse.che.selenium.core.constant.TestTimeoutsConstants.REDRAW_UI_ELEMENTS_TIMEOUT_SEC; + import com.google.inject.Inject; import com.google.inject.Singleton; import org.eclipse.che.selenium.core.SeleniumWebDriver; @@ -46,6 +48,7 @@ private interface Locators { String CLOSE_BTN_ID = "git-branches-close"; String DELBRANCH_FORM = "//div[text()='Delete branch']/ancestor::div[3]"; // TODO CREATE ID String DELBRANCH_BUTN_OK = "ask-dialog-ok"; + String SEARCH_FILTER_LABEL_ID = "gwt-debug-git-branches-search_filter"; } @FindBy(id = Locators.MAIN_FORM_ID) @@ -72,6 +75,9 @@ private interface Locators { @FindBy(id = Locators.DELBRANCH_BUTN_OK) WebElement buttonOK; + @FindBy(id = Locators.SEARCH_FILTER_LABEL_ID) + WebElement searchFilterLabel; + /** wait appearance of the IDE branches form */ public void waitBranchesForm() { new WebDriverWait(seleniumWebDriver, 15).until(ExpectedConditions.visibilityOf(mainForm)); @@ -247,4 +253,23 @@ public void clickCloseBtn() { public void clickRenameBtn() { renameBtn.click(); } + + /** + * wait for the search filter label to be with given text. + * + * @param text text to check + */ + public void waitSearchFilerWithText(String text) { + new WebDriverWait(seleniumWebDriver, REDRAW_UI_ELEMENTS_TIMEOUT_SEC) + .until(ExpectedConditions.textToBePresentInElement(searchFilterLabel, text)); + } + + /** + * Type text to the branch search filter. + * + * @param text typed text + */ + public void typeSearchFilter(String text) { + seleniumWebDriver.getKeyboard().sendKeys(text); + } } diff --git a/selenium/che-selenium-test/src/test/java/org/eclipse/che/selenium/git/CheckoutBranchTest.java b/selenium/che-selenium-test/src/test/java/org/eclipse/che/selenium/git/BranchTest.java similarity index 95% rename from selenium/che-selenium-test/src/test/java/org/eclipse/che/selenium/git/CheckoutBranchTest.java rename to selenium/che-selenium-test/src/test/java/org/eclipse/che/selenium/git/BranchTest.java index 6713f19be50..eba5fefde65 100644 --- a/selenium/che-selenium-test/src/test/java/org/eclipse/che/selenium/git/CheckoutBranchTest.java +++ b/selenium/che-selenium-test/src/test/java/org/eclipse/che/selenium/git/BranchTest.java @@ -35,8 +35,8 @@ import org.testng.annotations.Test; /** @author Aleksandr Shmaraev */ -public class CheckoutBranchTest { - private static final String PROJECT_NAME = NameGenerator.generate("CheckoutBranch_", 4); +public class BranchTest { + private static final String PROJECT_NAME = NameGenerator.generate("Branch_", 4); private static final String APP_JAVA_PATH = "/src/main/java/org/eclipse/qa/examples/AppController.java"; private static final String HELLO_JAVA_PATH = "/src/main/java/org/eclipse/qa/examples/Hello"; @@ -253,6 +253,21 @@ public void checkoutBranchTest() throws Exception { checkShwithConflict(); } + @Test(priority = 1) + public void filterBranchesTest() { + menu.runCommand(TestMenuCommandsConstants.Git.GIT, TestMenuCommandsConstants.Git.BRANCHES); + String defaultFilter = "Type from keyboard to filter branches"; + git.waitBranchSearchFilerWithText(defaultFilter); + git.typeToBranchSearchFilter("newbranch"); + git.waitBranchSearchFilerWithText("newbranch"); + git.waitBranchInTheList("newbranch"); + git.waitDisappearBranchName("master"); + git.typeToBranchSearchFilter(Keys.ESCAPE.toString()); + git.waitBranchSearchFilerWithText(defaultFilter); + git.waitBranchInTheList("master"); + git.waitBranchInTheList("newbranch"); + } + private void createBranch() throws Exception { menu.runCommand(TestMenuCommandsConstants.Git.GIT, TestMenuCommandsConstants.Git.BRANCHES); git.waitBranchInTheList(MASTER_BRANCH); diff --git a/selenium/che-selenium-test/src/test/resources/suites/CheSuite.xml b/selenium/che-selenium-test/src/test/resources/suites/CheSuite.xml index c954a59cfa9..c03381ff8db 100644 --- a/selenium/che-selenium-test/src/test/resources/suites/CheSuite.xml +++ b/selenium/che-selenium-test/src/test/resources/suites/CheSuite.xml @@ -191,7 +191,7 @@ - +