diff --git a/src/main/java/org/jboss/tools/intellij/openshift/actions/project/ChangeActiveProjectAction.java b/src/main/java/org/jboss/tools/intellij/openshift/actions/project/ChangeActiveProjectAction.java index a0814bc31..84228497d 100644 --- a/src/main/java/org/jboss/tools/intellij/openshift/actions/project/ChangeActiveProjectAction.java +++ b/src/main/java/org/jboss/tools/intellij/openshift/actions/project/ChangeActiveProjectAction.java @@ -73,11 +73,11 @@ private void doActionPerformed(final ApplicationsRootNode rootNode, final Point throw new RuntimeException(e); } }, SwingUtils.EXECUTOR_BACKGROUND) - .handleAsync((ClusterProjects, error) -> { + .handleAsync((clusterProjects, error) -> { if (error != null) { return null; } - ChangeActiveProjectDialog dialog = openActiveProjectDialog(ClusterProjects.isOpenShift, ClusterProjects.current, ClusterProjects.all, location, project); + ChangeActiveProjectDialog dialog = openActiveProjectDialog(clusterProjects.isOpenShift, clusterProjects.current, clusterProjects.all, location, project); if (dialog.isOK()) { return new ChangeActiveProjectOperation(dialog.getActiveProject(), odo); } else if (dialog.isCreateNewProject()) { diff --git a/src/main/java/org/jboss/tools/intellij/openshift/actions/project/CreateProjectAction.java b/src/main/java/org/jboss/tools/intellij/openshift/actions/project/CreateProjectAction.java index a28b33235..844e69327 100644 --- a/src/main/java/org/jboss/tools/intellij/openshift/actions/project/CreateProjectAction.java +++ b/src/main/java/org/jboss/tools/intellij/openshift/actions/project/CreateProjectAction.java @@ -19,11 +19,17 @@ import org.jboss.tools.intellij.openshift.actions.ActionUtils; import org.jboss.tools.intellij.openshift.actions.NotificationUtils; import org.jboss.tools.intellij.openshift.actions.cluster.LoggedInClusterAction; +import org.jboss.tools.intellij.openshift.telemetry.TelemetryService; import org.jboss.tools.intellij.openshift.tree.application.ApplicationsRootNode; +import org.jboss.tools.intellij.openshift.ui.SwingUtils; +import org.jboss.tools.intellij.openshift.ui.project.CreateNewProjectDialog; import org.jboss.tools.intellij.openshift.utils.odo.Odo; import org.jetbrains.annotations.NotNull; +import java.awt.Point; import java.io.IOException; +import java.util.List; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import static org.jboss.tools.intellij.openshift.actions.ActionUtils.runWithProgress; @@ -40,35 +46,69 @@ public static void execute(ApplicationsRootNode rootNode) { return; } CreateProjectAction action = ActionUtils.createAction(CreateProjectAction.class.getName()); - action.doActionPerformed(rootNode, odo, rootNode.getProject()); + action.doActionPerformed(rootNode, null, odo, rootNode.getProject()); } @Override public void actionPerformedOnSelectedObject(AnActionEvent anActionEvent, Object selected, @NotNull Odo odo) { ApplicationsRootNode clusterNode = (ApplicationsRootNode) selected; - doActionPerformed(clusterNode, odo, getEventProject(anActionEvent)); + Point location = ActionUtils.getLocation(anActionEvent); + doActionPerformed(clusterNode, location, odo, getEventProject(anActionEvent)); } - private void doActionPerformed(ApplicationsRootNode clusterNode, Odo odo, Project project) { - String projectName = Messages.showInputDialog("Project name", "New Project", Messages.getQuestionIcon()); - if ((projectName == null) || projectName.trim().isEmpty()) { - sendTelemetryResults(TelemetryResult.ABORTED); - return; - } - runWithProgress((ProgressIndicator progress) -> { + private void doActionPerformed(final ApplicationsRootNode clusterNode, final Point location, final Odo odo, Project project) { + runWithProgress((ProgressIndicator progress) -> + CompletableFuture + .supplyAsync(() -> { + try { + return odo.getNamespaces(); + } catch (IOException e) { + NotificationUtils.notifyError("Create New Project", "Could not get projects: " + e.getMessage()); + sendTelemetryError(e.getMessage()); + throw new RuntimeException(e); + } + }, SwingUtils.EXECUTOR_BACKGROUND) + .handleAsync((allProjects, error) -> { + if (error != null) { + return null; + } + CreateNewProjectDialog dialog = openCreateProjectDialog(allProjects, location, project); + if (dialog.isOK()) { + return dialog.getNewProject(); + } else { + sendTelemetryResults(TelemetryService.TelemetryResult.ABORTED); + return null; + } + } + , SwingUtils.EXECUTOR_UI) + .whenCompleteAsync((newProject, error) -> { + if (error != null + || newProject == null) { + return; + } + createProject(newProject, odo); + }, SwingUtils.EXECUTOR_BACKGROUND), + "Create Active Project...", + project); + } + + private void createProject(String newProject, Odo odo) { try { - Notification notif = NotificationUtils.notifyInformation("Create Project", "Creating project " + projectName); - odo.createProject(projectName); + Notification notif = NotificationUtils.notifyInformation("Create Project", "Creating project " + newProject); + odo.createProject(newProject); notif.expire(); - NotificationUtils.notifyInformation("Create Project", "Project " + projectName + " successfully created"); - clusterNode.getStructure().fireModified(clusterNode); + NotificationUtils.notifyInformation("Create Project", "Project " + newProject + " successfully created"); sendTelemetryResults(TelemetryResult.SUCCESS); } catch (IOException | CompletionException e) { sendTelemetryError(e); UIHelper.executeInUI(() -> Messages.showErrorDialog("Error: " + e.getLocalizedMessage(), "Create Project")); } - }, - "Create Project...", - project); } + + private CreateNewProjectDialog openCreateProjectDialog(List allProjects, Point location, Project project) { + CreateNewProjectDialog dialog = new CreateNewProjectDialog(project, allProjects, location); + dialog.show(); + return dialog; + } + } diff --git a/src/main/java/org/jboss/tools/intellij/openshift/ui/BaseDialog.java b/src/main/java/org/jboss/tools/intellij/openshift/ui/BaseDialog.java new file mode 100644 index 000000000..11fa567ad --- /dev/null +++ b/src/main/java/org/jboss/tools/intellij/openshift/ui/BaseDialog.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2024 Red Hat, Inc. + * Distributed under license by Red Hat, Inc. All rights reserved. + * This program is made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + ******************************************************************************/ +package org.jboss.tools.intellij.openshift.ui; + +import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.CommonShortcuts; +import com.intellij.openapi.actionSystem.IdeActions; +import com.intellij.openapi.project.DumbAwareAction; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.ui.PopupBorder; +import org.jetbrains.annotations.Nullable; + +import javax.swing.JRootPane; +import javax.swing.RootPaneContainer; +import java.awt.Point; +import java.awt.Window; + +import static org.jboss.tools.intellij.openshift.ui.SwingUtils.locationOrMouseLocation; + +abstract public class BaseDialog extends DialogWrapper { + + private final Point location; + + public BaseDialog(@Nullable Project project, Point location) { + super(project, false); + this.location = location; + init(); + } + + @Override + protected void init() { + super.init(); + Window dialogWindow = getPeer().getWindow(); + JRootPane rootPane = ((RootPaneContainer) dialogWindow).getRootPane(); + registerShortcuts(rootPane); + setBorders(rootPane); + setLocation(locationOrMouseLocation(location)); + } + + private void registerShortcuts(JRootPane rootPane) { + AnAction escape = ActionManager.getInstance().getAction(IdeActions.ACTION_EDITOR_ESCAPE); + DumbAwareAction.create(e -> closeImmediately()) + .registerCustomShortcutSet( + escape == null ? CommonShortcuts.ESCAPE : escape.getShortcutSet(), + rootPane, + myDisposable); + } + + private void setBorders(JRootPane rootPane) { + rootPane.setBorder(PopupBorder.Factory.create(true, true)); + rootPane.setWindowDecorationStyle(JRootPane.NONE); + } + + protected void closeImmediately() { + if (isVisible()) { + doCancelAction(); + } + } +} diff --git a/src/main/java/org/jboss/tools/intellij/openshift/ui/SwingUtils.java b/src/main/java/org/jboss/tools/intellij/openshift/ui/SwingUtils.java index 769623ca2..55a1de004 100644 --- a/src/main/java/org/jboss/tools/intellij/openshift/ui/SwingUtils.java +++ b/src/main/java/org/jboss/tools/intellij/openshift/ui/SwingUtils.java @@ -38,6 +38,8 @@ import java.awt.Component; import java.awt.Dimension; import java.awt.Font; +import java.awt.MouseInfo; +import java.awt.Point; import java.util.concurrent.Executor; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -140,4 +142,11 @@ public static void setMovable(JRootPane rootPane, JComponent... movableComponent component -> component.addMouseListener(windowMoveListener)); } + public static Point locationOrMouseLocation(Point location) { + if (location == null) { + location = MouseInfo.getPointerInfo().getLocation(); + } + return location; + } + } diff --git a/src/main/java/org/jboss/tools/intellij/openshift/ui/project/ChangeActiveProjectDialog.java b/src/main/java/org/jboss/tools/intellij/openshift/ui/project/ChangeActiveProjectDialog.java index 7290f9f16..16deea844 100644 --- a/src/main/java/org/jboss/tools/intellij/openshift/ui/project/ChangeActiveProjectDialog.java +++ b/src/main/java/org/jboss/tools/intellij/openshift/ui/project/ChangeActiveProjectDialog.java @@ -10,23 +10,17 @@ ******************************************************************************/ package org.jboss.tools.intellij.openshift.ui.project; -import com.intellij.openapi.actionSystem.ActionManager; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.CommonShortcuts; -import com.intellij.openapi.actionSystem.IdeActions; -import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.ComponentValidator; -import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.ValidationInfo; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.ui.PopupBorder; import com.intellij.ui.TextFieldWithAutoCompletion; import com.intellij.ui.TextFieldWithAutoCompletionListProvider; import com.intellij.ui.components.JBLabel; import com.intellij.util.textCompletion.TextFieldWithCompletion; import com.intellij.util.ui.JBUI; import net.miginfocom.swing.MigLayout; +import org.jboss.tools.intellij.openshift.ui.BaseDialog; import org.jboss.tools.intellij.openshift.ui.SwingUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -34,26 +28,21 @@ import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; -import javax.swing.JRootPane; -import javax.swing.RootPaneContainer; import javax.swing.SwingConstants; -import java.awt.MouseInfo; import java.awt.Point; -import java.awt.Window; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.util.Collection; import java.util.function.Supplier; -public class ChangeActiveProjectDialog extends DialogWrapper { +public class ChangeActiveProjectDialog extends BaseDialog { private static final String WIDTH = "300"; private final Project project; private final String kind; private final String currentProject; private final Collection allProjects; - private final Point location; private TextFieldWithCompletion activeProjectTextField; private String activeProject; @@ -66,48 +55,21 @@ public ChangeActiveProjectDialog( String currentProject, Collection allProjects, Point location) { - super(project, false); + super(project, location); this.project = project; this.kind = kind; this.currentProject = currentProject; this.allProjects = allProjects; - this.location = location; init(); } @Override protected void init() { super.init(); - Window dialogWindow = getPeer().getWindow(); - JRootPane rootPane = ((RootPaneContainer) dialogWindow).getRootPane(); - registerShortcuts(rootPane); setOKButtonText("Change"); - setBorders(rootPane); - setLocation(location); setTitle("Change Active " + kind); } - @Override - public void setLocation(Point location) { - if (location == null) { - location = MouseInfo.getPointerInfo().getLocation(); - } - super.setLocation(location); - } - - private void registerShortcuts(JRootPane rootPane) { - AnAction escape = ActionManager.getInstance().getAction(IdeActions.ACTION_EDITOR_ESCAPE); - DumbAwareAction.create(e -> closeImmediately()) - .registerCustomShortcutSet(escape == null ? - CommonShortcuts.ESCAPE - : escape.getShortcutSet(), rootPane, myDisposable); - } - - private void setBorders(JRootPane rootPane) { - rootPane.setBorder(PopupBorder.Factory.create(true, true)); - rootPane.setWindowDecorationStyle(JRootPane.NONE); - } - @Override protected @Nullable JComponent createCenterPanel() { JComponent panel = new JPanel(new MigLayout( @@ -156,12 +118,6 @@ private TextFieldWithAutoCompletionListProvider onLookup(Collection allProjects; + private JBTextField newProjectTextField; + + private String newProject; + + public CreateNewProjectDialog(@Nullable Project project, Collection allProjects, Point location) { + super(project, location); + this.allProjects = allProjects; + init(); + } + + @Override + protected void init() { + super.init(); + setOKButtonText("Create"); + setTitle("Create New Project"); + } + + @Override + protected @Nullable JComponent createCenterPanel() { + JComponent panel = new JPanel(new MigLayout( + "flowx, ins 0, gap 0, fillx, filly, hidemode 3", + "[left]10[" + WIDTH +",fill]")); + JLabel newActiveProjectLabel = new JBLabel("New project:", SwingConstants.LEFT); + newActiveProjectLabel.setBorder(JBUI.Borders.empty(10, 0)); + panel.add(newActiveProjectLabel, "left, bottom"); + this.newProjectTextField = new JBTextField(); + newProjectTextField.selectAll(); + panel.add(newProjectTextField, "pushx, growx, wrap"); + ComponentValidator activeProjectValidator = new ComponentValidator(myDisposable) + .withValidator(new ActiveProjectValidator()) + .installOn(newProjectTextField) + .andRegisterOnDocumentListener(newProjectTextField); + activeProjectValidator.revalidate(); + return panel; + } + + @Override + protected void doOKAction() { + super.doOKAction(); + this.newProject = newProjectTextField.getText(); + } + + public String getNewProject() { + return newProject; + } + + private class ActiveProjectValidator implements Supplier { + + @Override + public ValidationInfo get() { + String activeProject = newProjectTextField.getText(); + ValidationInfo validation = getValidationInfo(activeProject); + // update OK button + setOKActionEnabled(validation.okEnabled); + return validation; + } + + private ValidationInfo getValidationInfo(String newProject) { + ValidationInfo validation = new ValidationInfo("").withOKEnabled(); + if (StringUtil.isEmptyOrSpaces(newProject)) { + validation = new ValidationInfo("Provide project name").forComponent(newProjectTextField).asWarning(); + } else if (allProjects.contains(newProject)) { + validation = new ValidationInfo("Already exists, choose new name").forComponent(newProjectTextField).asWarning(); + } + return validation; + } + } +}