CHE-673. Correct handling buttons of Commands dialog when Enter is clicked

Signed-off-by: Roman Nikitenko <rnikitenko@codenvy.com>
6.19.x
Roman Nikitenko 2016-03-11 13:20:09 +02:00
parent de2422fb2c
commit 4d6379d3de
4 changed files with 313 additions and 39 deletions

View File

@ -64,7 +64,6 @@ public class EditCommandsPresenter implements EditCommandsView.ActionDelegate {
private final EditCommandsView view;
private final WorkspaceServiceClient workspaceServiceClient;
private final CommandManager commandManager;
private final String workspaceId;
private final DtoFactory dtoFactory;
private final CommandTypeRegistry commandTypeRegistry;
private final DialogFactory dialogFactory;
@ -72,14 +71,17 @@ public class EditCommandsPresenter implements EditCommandsView.ActionDelegate {
private final CoreLocalizationConstant coreLocale;
private final Provider<SelectCommandComboBoxReady> selectCommandActionProvider;
private final Set<ConfigurationChangedListener> configurationChangedListeners;
private final AppContext appContext;
/** Set of the existing command names. */
private final Set<String> commandNames;
private CommandConfigurationPage<CommandConfiguration> editedPage;
/** Command that being edited. */
private CommandConfiguration editedCommand;
/** Name of the edited command before editing. */
private String editedCommandOriginName;
private String editedCommandOriginPreviewUrl;
String editedCommandOriginName;
String editedCommandOriginPreviewUrl;
String workspaceId;
CommandProcessingCallback commandProcessingCallback;
@Inject
protected EditCommandsPresenter(EditCommandsView view,
@ -95,7 +97,6 @@ public class EditCommandsPresenter implements EditCommandsView.ActionDelegate {
this.view = view;
this.workspaceServiceClient = workspaceServiceClient;
this.commandManager = commandManager;
this.workspaceId = appContext.getWorkspace().getId();
this.dtoFactory = dtoFactory;
this.commandTypeRegistry = commandTypeRegistry;
this.dialogFactory = dialogFactory;
@ -103,7 +104,7 @@ public class EditCommandsPresenter implements EditCommandsView.ActionDelegate {
this.coreLocale = coreLocale;
this.selectCommandActionProvider = selectCommandActionProvider;
this.view.setDelegate(this);
this.appContext = appContext;
configurationChangedListeners = new HashSet<>();
commandNames = new HashSet<>();
}
@ -134,6 +135,7 @@ public class EditCommandsPresenter implements EditCommandsView.ActionDelegate {
updateCommand(selectedConfiguration).then(new Operation<UsersWorkspaceDto>() {
@Override
public void apply(UsersWorkspaceDto arg) throws OperationException {
commandProcessingCallback = getCommandProcessingCallback();
fetchCommands();
fireConfigurationUpdated(selectedConfiguration);
}
@ -172,6 +174,7 @@ public class EditCommandsPresenter implements EditCommandsView.ActionDelegate {
@Override
public void onCancelClicked() {
commandProcessingCallback = getCommandProcessingCallback();
fetchCommands();
}
@ -293,6 +296,7 @@ public class EditCommandsPresenter implements EditCommandsView.ActionDelegate {
@Override
public void apply(UsersWorkspaceDto arg) throws OperationException {
view.selectNextItem();
commandProcessingCallback = getCommandProcessingCallback();
fetchCommands();
fireConfigurationRemoved(selectedConfiguration);
}
@ -324,6 +328,20 @@ public class EditCommandsPresenter implements EditCommandsView.ActionDelegate {
view.close();
}
@Override
public void onEnterClicked() {
if (view.isCancelButtonInFocus()) {
onCancelClicked();
return;
}
if (view.isCloseButtonInFocus()) {
onCloseClicked();
return;
}
onSaveClicked();
}
private void reset() {
editedCommand = null;
editedCommandOriginName = null;
@ -436,6 +454,7 @@ public class EditCommandsPresenter implements EditCommandsView.ActionDelegate {
/** Show dialog. */
public void show() {
workspaceId = appContext.getWorkspaceId();
fetchCommands();
view.show();
}
@ -497,6 +516,11 @@ public class EditCommandsPresenter implements EditCommandsView.ActionDelegate {
}
view.setData(categories);
view.setFilterState(!commandConfigurations.isEmpty());
if (commandProcessingCallback != null) {
commandProcessingCallback.onCompleted();
commandProcessingCallback = null;
}
}
}).catchError(new Operation<PromiseError>() {
@Override
@ -533,6 +557,15 @@ public class EditCommandsPresenter implements EditCommandsView.ActionDelegate {
}
}
private CommandProcessingCallback getCommandProcessingCallback() {
return new CommandProcessingCallback() {
@Override
public void onCompleted() {
view.setCloseButtonInFocus();
}
};
}
public void addConfigurationsChangedListener(ConfigurationChangedListener listener) {
configurationChangedListeners.add(listener);
}
@ -549,4 +582,9 @@ public class EditCommandsPresenter implements EditCommandsView.ActionDelegate {
void onConfigurationsUpdated(CommandConfiguration command);
}
interface CommandProcessingCallback {
/** Called when handling of command is completed successfully. */
void onCompleted();
}
}

View File

@ -17,6 +17,7 @@ import org.eclipse.che.ide.extension.machine.client.command.CommandConfiguration
import org.eclipse.che.ide.extension.machine.client.command.CommandType;
import org.eclipse.che.commons.annotation.Nullable;
import java.util.List;
import java.util.Map;
@ -67,7 +68,7 @@ public interface EditCommandsView extends View<EditCommandsView.ActionDelegate>
/** Sets enabled state of the 'Apply' button. */
void setSaveButtonState(boolean enabled);
/** Sets enabled state of the filter input field. */
void setFilterState(boolean enabled);
@ -82,6 +83,15 @@ public interface EditCommandsView extends View<EditCommandsView.ActionDelegate>
@Nullable
CommandConfiguration getSelectedConfiguration();
/** Sets the focus on the 'Close' button. */
void setCloseButtonInFocus();
/** Returns {@code true} if cancel button is in the focus and {@code false} - otherwise. */
boolean isCancelButtonInFocus();
/** Returns {@code true} if close button is in the focus and {@code false} - otherwise. */
boolean isCloseButtonInFocus();
/** Action handler for the view actions/controls. */
interface ActionDelegate {
@ -106,6 +116,9 @@ public interface EditCommandsView extends View<EditCommandsView.ActionDelegate>
/** Called when 'Execute' button is clicked. */
void onExecuteClicked();
/** Performs any actions appropriate in response to the user having clicked the Enter key. */
void onEnterClicked();
/**
* Called when some command configuration is selected.
*

View File

@ -49,6 +49,7 @@ import org.eclipse.che.ide.api.icon.IconRegistry;
import org.eclipse.che.ide.extension.machine.client.MachineLocalizationConstant;
import org.eclipse.che.ide.extension.machine.client.command.CommandConfiguration;
import org.eclipse.che.ide.extension.machine.client.command.CommandType;
import org.eclipse.che.ide.ui.WidgetFocusTracker;
import org.eclipse.che.ide.ui.list.CategoriesList;
import org.eclipse.che.ide.ui.list.Category;
import org.eclipse.che.ide.ui.list.CategoryRenderer;
@ -73,10 +74,12 @@ public class EditCommandsViewImpl extends Window implements EditCommandsView {
private final EditCommandResources commandResources;
private final IconRegistry iconRegistry;
private final WidgetFocusTracker widgetFocusTracker;
private final CoreLocalizationConstant coreLocale;
private final Button cancelButton;
private final Button saveButton;
private final Label hintLabel;
private Button cancelButton;
private Button saveButton;
private Button closeButton;
private final CategoryRenderer<CommandConfiguration> projectImporterRenderer =
new CategoryRenderer<CommandConfiguration>() {
@ -136,11 +139,13 @@ public class EditCommandsViewImpl extends Window implements EditCommandsView {
EditCommandResources commandResources,
MachineLocalizationConstant machineLocale,
CoreLocalizationConstant coreLocale,
IconRegistry iconRegistry) {
IconRegistry iconRegistry,
WidgetFocusTracker widgetFocusTracker) {
this.commandResources = commandResources;
this.machineLocale = machineLocale;
this.coreLocale = coreLocale;
this.iconRegistry = iconRegistry;
this.widgetFocusTracker = widgetFocusTracker;
selectConfiguration = null;
categories = new HashMap<>();
@ -178,24 +183,7 @@ public class EditCommandsViewImpl extends Window implements EditCommandsView {
previewUrlPanel.setVisible(false);
contentPanel.clear();
saveButton = createButton(coreLocale.save(), "window-edit-configurations-save", new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
delegate.onSaveClicked();
}
});
saveButton.addStyleName(this.resources.windowCss().primaryButton());
overFooter.add(saveButton);
cancelButton = createButton(coreLocale.cancel(), "window-edit-configurations-cancel", new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
delegate.onCancelClicked();
}
});
overFooter.add(cancelButton);
createFooterButton();
createButtons();
resetFilter();
getWidget().getElement().getStyle().setPadding(0, Style.Unit.PX);
@ -357,14 +345,31 @@ public class EditCommandsViewImpl extends Window implements EditCommandsView {
renderCategoriesList(categories);
}
private void createFooterButton() {
final Button closeButton = createButton(coreLocale.close(), "window-edit-configurations-close",
new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
delegate.onCloseClicked();
}
});
private void createButtons() {
saveButton = createButton(coreLocale.save(), "window-edit-configurations-save", new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
delegate.onSaveClicked();
}
});
saveButton.addStyleName(this.resources.windowCss().primaryButton());
overFooter.add(saveButton);
cancelButton = createButton(coreLocale.cancel(), "window-edit-configurations-cancel", new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
delegate.onCancelClicked();
}
});
overFooter.add(cancelButton);
closeButton = createButton(coreLocale.close(), "window-edit-configurations-close",
new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
delegate.onCloseClicked();
}
});
closeButton.addDomHandler(new BlurHandler() {
@Override
public void onBlur(BlurEvent blurEvent) {
@ -398,11 +403,13 @@ public class EditCommandsViewImpl extends Window implements EditCommandsView {
super.show(focusPanel);
configurationName.setText("");
configurationPreviewUrl.setText("");
trackFocusForWidgets();
}
@Override
public void close() {
this.hide();
unTrackFocusForWidgets();
}
@Override
@ -472,6 +479,11 @@ public class EditCommandsViewImpl extends Window implements EditCommandsView {
return selectConfiguration;
}
@Override
public void setCloseButtonInFocus() {
closeButton.setFocus(true);
}
@UiHandler("configurationName")
public void onNameKeyUp(KeyUpEvent event) {
delegate.onNameChanged();
@ -492,16 +504,35 @@ public class EditCommandsViewImpl extends Window implements EditCommandsView {
@Override
protected void onEnterClicked() {
if (saveButton.isEnabled()) {
delegate.onSaveClicked();
}
delegate.onEnterClicked();
}
@Override
protected void onClose() {
setSelectedConfiguration(selectConfiguration);
unTrackFocusForWidgets();
}
@Override
public boolean isCancelButtonInFocus() {
return widgetFocusTracker.isWidgetFocused(cancelButton);
}
@Override
public boolean isCloseButtonInFocus() {
return widgetFocusTracker.isWidgetFocused(closeButton);
}
private void trackFocusForWidgets() {
widgetFocusTracker.subscribe(cancelButton);
widgetFocusTracker.subscribe(closeButton);
}
private void unTrackFocusForWidgets() {
widgetFocusTracker.unSubscribe(cancelButton);
widgetFocusTracker.unSubscribe(closeButton);
}
interface EditCommandsViewImplUiBinder extends UiBinder<Widget, EditCommandsViewImpl> {
}
}
}

View File

@ -0,0 +1,192 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* 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:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.ide.extension.machine.client.command.edit;
import org.eclipse.che.api.machine.shared.dto.CommandDto;
import org.eclipse.che.api.promises.client.Function;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.Promise;
import org.eclipse.che.api.workspace.gwt.client.WorkspaceServiceClient;
import org.eclipse.che.api.workspace.shared.dto.UsersWorkspaceDto;
import org.eclipse.che.ide.CoreLocalizationConstant;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.dto.DtoFactory;
import org.eclipse.che.ide.extension.machine.client.MachineLocalizationConstant;
import org.eclipse.che.ide.extension.machine.client.command.CommandConfiguration;
import org.eclipse.che.ide.extension.machine.client.command.CommandManager;
import org.eclipse.che.ide.extension.machine.client.command.CommandType;
import org.eclipse.che.ide.extension.machine.client.command.CommandTypeRegistry;
import org.eclipse.che.ide.ui.dialogs.DialogFactory;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import java.util.ArrayList;
import java.util.List;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyMap;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/** @author Roman Nikitenko */
@RunWith(MockitoJUnitRunner.class)
public class EditCommandsPresenterTest {
private static String WORKSPACE_ID = "workspaceId";
private static String COMMAND_NAME = "commandName";
@Mock
private EditCommandsView view;
@Mock
private WorkspaceServiceClient workspaceServiceClient;
@Mock
private CommandManager commandManager;
@Mock
private DtoFactory dtoFactory;
@Mock
private CommandTypeRegistry commandTypeRegistry;
@Mock
private AppContext appContext;
@Mock
private DialogFactory dialogFactory;
@Mock
private MachineLocalizationConstant machineLocale;
@Mock
private CoreLocalizationConstant coreLocale;
@Mock
private UsersWorkspaceDto workspace;
@Mock
private Promise<List<CommandDto>> commandsPromise;
@Mock
private Promise<UsersWorkspaceDto> workspacePromise;
@Mock
private Promise<List<CommandConfiguration>> commandConfigurationPromise;
@Captor
private ArgumentCaptor<Function<List<CommandDto>, List<CommandConfiguration>>> commandsCaptor;
@Captor
private ArgumentCaptor<Operation<List<CommandConfiguration>>> commandConfigurationCaptor;
@Captor
private ArgumentCaptor<Operation<UsersWorkspaceDto>> workspaceCaptor;
@InjectMocks
private EditCommandsPresenter presenter;
@Before
public void setUp() {
presenter.editedCommandOriginName = COMMAND_NAME;
presenter.workspaceId = WORKSPACE_ID;
when(appContext.getWorkspace()).thenReturn(workspace);
when(workspace.getId()).thenReturn(WORKSPACE_ID);
when(workspaceServiceClient.getCommands(anyString())).thenReturn(commandsPromise);
when(commandsPromise.then((Function<List<CommandDto>, List<CommandConfiguration>>)anyObject()))
.thenReturn(commandConfigurationPromise);
when(commandConfigurationPromise.then((Operation<List<CommandConfiguration>>)anyObject())).thenReturn(commandConfigurationPromise);
when(workspaceServiceClient.updateCommand(anyString(), anyObject())).thenReturn(workspacePromise);
}
@Test
public void onEnterClickedWhenCancelButtonInFocus() throws Exception {
when(view.isCancelButtonInFocus()).thenReturn(true);
CommandDto command = mock(CommandDto.class);
CommandConfiguration commandConfiguration = mock(CommandConfiguration.class);
List<CommandDto> commands = new ArrayList<>(1);
List<CommandConfiguration> confiqurations = new ArrayList<>(1);
commands.add(command);
confiqurations.add(commandConfiguration);
presenter.onEnterClicked();
verify(view).setCancelButtonState(false);
verify(view).setSaveButtonState(false);
verify(workspaceServiceClient).getCommands(anyString());
verify(commandsPromise).then(commandsCaptor.capture());
commandsCaptor.getValue().apply(commands);
verify(commandConfigurationPromise).then(commandConfigurationCaptor.capture());
commandConfigurationCaptor.getValue().apply(confiqurations);
verify(view).setData(anyObject());
verify(view).setFilterState(anyBoolean());
verify(view).setCloseButtonInFocus();
verify(view, never()).close();
verify(workspaceServiceClient, never()).updateCommand(anyString(), anyObject());
verify(workspaceServiceClient, never()).deleteCommand(anyString(), anyString());
}
@Test
public void onEnterClickedWhenCloseButtonInFocus() throws Exception {
when(view.isCloseButtonInFocus()).thenReturn(true);
presenter.onEnterClicked();
verify(view).close();
verify(workspaceServiceClient, never()).getCommands(anyString());
verify(workspaceServiceClient, never()).updateCommand(anyString(), anyObject());
verify(workspaceServiceClient, never()).deleteCommand(anyString(), anyString());
}
@Test
public void onEnterClickedWhenSaveButtonInFocus() throws Exception {
when(view.isCancelButtonInFocus()).thenReturn(false);
when(view.isCloseButtonInFocus()).thenReturn(false);
CommandDto command = mock(CommandDto.class);
CommandConfiguration commandConfiguration = mock(CommandConfiguration.class);
List<CommandDto> commands = new ArrayList<>(1);
List<CommandConfiguration> confiqurations = new ArrayList<>(1);
commands.add(command);
confiqurations.add(commandConfiguration);
when(dtoFactory.createDto(CommandDto.class)).thenReturn(command);
when(command.withName(anyString())).thenReturn(command);
when(command.withCommandLine(anyString())).thenReturn(command);
when(command.withType(anyString())).thenReturn(command);
when(command.withAttributes(anyMap())).thenReturn(command);
when(view.getSelectedConfiguration()).thenReturn(commandConfiguration);
when(commandConfiguration.getType()).thenReturn(mock(CommandType.class));
when(commandConfiguration.getName()).thenReturn(COMMAND_NAME);
presenter.onEnterClicked();
verify(dtoFactory).createDto(CommandDto.class);
verify(workspaceServiceClient).updateCommand(eq(WORKSPACE_ID), eq(command));
verify(workspacePromise).then(workspaceCaptor.capture());
workspaceCaptor.getValue().apply(workspace);
verify(view).setCancelButtonState(false);
verify(view).setSaveButtonState(false);
verify(workspaceServiceClient).getCommands(anyString());
verify(commandsPromise).then(commandsCaptor.capture());
commandsCaptor.getValue().apply(commands);
verify(commandConfigurationPromise).then(commandConfigurationCaptor.capture());
commandConfigurationCaptor.getValue().apply(confiqurations);
verify(view).setData(anyObject());
verify(view).setFilterState(anyBoolean());
verify(view).setCloseButtonInFocus();
verify(view, never()).close();
}
}