Skip to content
This repository was archived by the owner on Apr 23, 2025. It is now read-only.

Commit d3022bd

Browse files
committed
feat: validate new project name (#237)
Signed-off-by: Andre Dietisheim <[email protected]>
1 parent 590ff1d commit d3022bd

File tree

5 files changed

+221
-23
lines changed

5 files changed

+221
-23
lines changed

src/main/java/org/jboss/tools/intellij/openshift/actions/project/ChangeActiveProjectAction.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,11 @@ private void doActionPerformed(final ApplicationsRootNode rootNode, final Point
7373
throw new RuntimeException(e);
7474
}
7575
}, SwingUtils.EXECUTOR_BACKGROUND)
76-
.handleAsync((ClusterProjects, error) -> {
76+
.handleAsync((clusterProjects, error) -> {
7777
if (error != null) {
7878
return null;
7979
}
80-
ChangeActiveProjectDialog dialog = openActiveProjectDialog(ClusterProjects.isOpenShift, ClusterProjects.current, ClusterProjects.all, location, project);
80+
ChangeActiveProjectDialog dialog = openActiveProjectDialog(clusterProjects.isOpenShift, clusterProjects.current, clusterProjects.all, location, project);
8181
if (dialog.isOK()) {
8282
return new ChangeActiveProjectOperation(dialog.getActiveProject(), odo);
8383
} else if (dialog.isCreateNewProject()) {

src/main/java/org/jboss/tools/intellij/openshift/actions/project/CreateProjectAction.java

Lines changed: 56 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,17 @@
1919
import org.jboss.tools.intellij.openshift.actions.ActionUtils;
2020
import org.jboss.tools.intellij.openshift.actions.NotificationUtils;
2121
import org.jboss.tools.intellij.openshift.actions.cluster.LoggedInClusterAction;
22+
import org.jboss.tools.intellij.openshift.telemetry.TelemetryService;
2223
import org.jboss.tools.intellij.openshift.tree.application.ApplicationsRootNode;
24+
import org.jboss.tools.intellij.openshift.ui.SwingUtils;
25+
import org.jboss.tools.intellij.openshift.ui.project.CreateNewProjectDialog;
2326
import org.jboss.tools.intellij.openshift.utils.odo.Odo;
2427
import org.jetbrains.annotations.NotNull;
2528

29+
import java.awt.Point;
2630
import java.io.IOException;
31+
import java.util.List;
32+
import java.util.concurrent.CompletableFuture;
2733
import java.util.concurrent.CompletionException;
2834

2935
import static org.jboss.tools.intellij.openshift.actions.ActionUtils.runWithProgress;
@@ -40,35 +46,69 @@ public static void execute(ApplicationsRootNode rootNode) {
4046
return;
4147
}
4248
CreateProjectAction action = ActionUtils.createAction(CreateProjectAction.class.getName());
43-
action.doActionPerformed(rootNode, odo, rootNode.getProject());
49+
action.doActionPerformed(rootNode, null, odo, rootNode.getProject());
4450
}
4551

4652
@Override
4753
public void actionPerformedOnSelectedObject(AnActionEvent anActionEvent, Object selected, @NotNull Odo odo) {
4854
ApplicationsRootNode clusterNode = (ApplicationsRootNode) selected;
49-
doActionPerformed(clusterNode, odo, getEventProject(anActionEvent));
55+
Point location = ActionUtils.getLocation(anActionEvent);
56+
doActionPerformed(clusterNode, location, odo, getEventProject(anActionEvent));
5057
}
5158

52-
private void doActionPerformed(ApplicationsRootNode clusterNode, Odo odo, Project project) {
53-
String projectName = Messages.showInputDialog("Project name", "New Project", Messages.getQuestionIcon());
54-
if ((projectName == null) || projectName.trim().isEmpty()) {
55-
sendTelemetryResults(TelemetryResult.ABORTED);
56-
return;
57-
}
58-
runWithProgress((ProgressIndicator progress) -> {
59+
private void doActionPerformed(final ApplicationsRootNode clusterNode, final Point location, final Odo odo, Project project) {
60+
runWithProgress((ProgressIndicator progress) ->
61+
CompletableFuture
62+
.supplyAsync(() -> {
63+
try {
64+
return odo.getNamespaces();
65+
} catch (IOException e) {
66+
NotificationUtils.notifyError("Create New Project", "Could not get projects: " + e.getMessage());
67+
sendTelemetryError(e.getMessage());
68+
throw new RuntimeException(e);
69+
}
70+
}, SwingUtils.EXECUTOR_BACKGROUND)
71+
.handleAsync((allProjects, error) -> {
72+
if (error != null) {
73+
return null;
74+
}
75+
CreateNewProjectDialog dialog = openCreateProjectDialog(allProjects, location, project);
76+
if (dialog.isOK()) {
77+
return dialog.getNewProject();
78+
} else {
79+
sendTelemetryResults(TelemetryService.TelemetryResult.ABORTED);
80+
return null;
81+
}
82+
}
83+
, SwingUtils.EXECUTOR_UI)
84+
.whenCompleteAsync((newProject, error) -> {
85+
if (error != null
86+
|| newProject == null) {
87+
return;
88+
}
89+
createProject(newProject, odo);
90+
}, SwingUtils.EXECUTOR_BACKGROUND),
91+
"Create Active Project...",
92+
project);
93+
}
94+
95+
private void createProject(String newProject, Odo odo) {
5996
try {
60-
Notification notif = NotificationUtils.notifyInformation("Create Project", "Creating project " + projectName);
61-
odo.createProject(projectName);
97+
Notification notif = NotificationUtils.notifyInformation("Create Project", "Creating project " + newProject);
98+
odo.createProject(newProject);
6299
notif.expire();
63-
NotificationUtils.notifyInformation("Create Project", "Project " + projectName + " successfully created");
64-
clusterNode.getStructure().fireModified(clusterNode);
100+
NotificationUtils.notifyInformation("Create Project", "Project " + newProject + " successfully created");
65101
sendTelemetryResults(TelemetryResult.SUCCESS);
66102
} catch (IOException | CompletionException e) {
67103
sendTelemetryError(e);
68104
UIHelper.executeInUI(() -> Messages.showErrorDialog("Error: " + e.getLocalizedMessage(), "Create Project"));
69105
}
70-
},
71-
"Create Project...",
72-
project);
73106
}
107+
108+
private CreateNewProjectDialog openCreateProjectDialog(List<String> allProjects, Point location, Project project) {
109+
CreateNewProjectDialog dialog = new CreateNewProjectDialog(project, allProjects, location);
110+
dialog.show();
111+
return dialog;
112+
}
113+
74114
}

src/main/java/org/jboss/tools/intellij/openshift/ui/SwingUtils.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
import java.awt.Component;
3939
import java.awt.Dimension;
4040
import java.awt.Font;
41+
import java.awt.MouseInfo;
42+
import java.awt.Point;
4143
import java.util.concurrent.Executor;
4244
import java.util.regex.Matcher;
4345
import java.util.regex.Pattern;
@@ -140,4 +142,11 @@ public static void setMovable(JRootPane rootPane, JComponent... movableComponent
140142
component -> component.addMouseListener(windowMoveListener));
141143
}
142144

145+
public static Point locationOrMouseLocation(Point location) {
146+
if (location == null) {
147+
location = MouseInfo.getPointerInfo().getLocation();
148+
}
149+
return location;
150+
}
151+
143152
}

src/main/java/org/jboss/tools/intellij/openshift/ui/project/ChangeActiveProjectDialog.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
import javax.swing.JRootPane;
3838
import javax.swing.RootPaneContainer;
3939
import javax.swing.SwingConstants;
40-
import java.awt.MouseInfo;
4140
import java.awt.Point;
4241
import java.awt.Window;
4342
import java.awt.event.MouseAdapter;
@@ -46,6 +45,8 @@
4645
import java.util.Collection;
4746
import java.util.function.Supplier;
4847

48+
import static org.jboss.tools.intellij.openshift.ui.SwingUtils.locationOrMouseLocation;
49+
4950
public class ChangeActiveProjectDialog extends DialogWrapper {
5051

5152
private static final String WIDTH = "300";
@@ -89,10 +90,7 @@ protected void init() {
8990

9091
@Override
9192
public void setLocation(Point location) {
92-
if (location == null) {
93-
location = MouseInfo.getPointerInfo().getLocation();
94-
}
95-
super.setLocation(location);
93+
super.setLocation(locationOrMouseLocation(location));
9694
}
9795

9896
private void registerShortcuts(JRootPane rootPane) {
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2024 Red Hat, Inc.
3+
* Distributed under license by Red Hat, Inc. All rights reserved.
4+
* This program is made available under the terms of the
5+
* Eclipse Public License v2.0 which accompanies this distribution,
6+
* and is available at http://www.eclipse.org/legal/epl-v20.html
7+
*
8+
* Contributors:
9+
* Red Hat, Inc. - initial API and implementation
10+
******************************************************************************/
11+
package org.jboss.tools.intellij.openshift.ui.project;
12+
13+
import com.intellij.openapi.actionSystem.ActionManager;
14+
import com.intellij.openapi.actionSystem.AnAction;
15+
import com.intellij.openapi.actionSystem.CommonShortcuts;
16+
import com.intellij.openapi.actionSystem.IdeActions;
17+
import com.intellij.openapi.project.DumbAwareAction;
18+
import com.intellij.openapi.project.Project;
19+
import com.intellij.openapi.ui.ComponentValidator;
20+
import com.intellij.openapi.ui.DialogWrapper;
21+
import com.intellij.openapi.ui.ValidationInfo;
22+
import com.intellij.openapi.util.text.StringUtil;
23+
import com.intellij.ui.PopupBorder;
24+
import com.intellij.ui.components.JBLabel;
25+
import com.intellij.ui.components.JBTextField;
26+
import com.intellij.util.ui.JBUI;
27+
import net.miginfocom.swing.MigLayout;
28+
import org.jetbrains.annotations.Nullable;
29+
30+
import javax.swing.JComponent;
31+
import javax.swing.JLabel;
32+
import javax.swing.JPanel;
33+
import javax.swing.JRootPane;
34+
import javax.swing.RootPaneContainer;
35+
import javax.swing.SwingConstants;
36+
import java.awt.Point;
37+
import java.awt.Window;
38+
import java.util.Collection;
39+
import java.util.function.Supplier;
40+
41+
import static org.jboss.tools.intellij.openshift.ui.SwingUtils.locationOrMouseLocation;
42+
43+
public class CreateNewProjectDialog extends DialogWrapper {
44+
45+
private static final String WIDTH = "300";
46+
private final Collection<String> allProjects;
47+
private final Point location;
48+
private final Project project;
49+
private JBTextField newProjectTextField;
50+
51+
private String newProject;
52+
53+
public CreateNewProjectDialog(
54+
@Nullable Project project,
55+
Collection<String> allProjects,
56+
Point location) {
57+
super(project, false);
58+
this.project = project;
59+
this.allProjects = allProjects;
60+
this.location = location;
61+
init();
62+
}
63+
64+
@Override
65+
protected void init() {
66+
super.init();
67+
Window dialogWindow = getPeer().getWindow();
68+
JRootPane rootPane = ((RootPaneContainer) dialogWindow).getRootPane();
69+
registerShortcuts(rootPane);
70+
setOKButtonText("Create");
71+
setBorders(rootPane);
72+
setLocation(location);
73+
setTitle("Create New Project");
74+
}
75+
76+
@Override
77+
public void setLocation(Point location) {
78+
super.setLocation(locationOrMouseLocation(location));
79+
}
80+
81+
private void registerShortcuts(JRootPane rootPane) {
82+
AnAction escape = ActionManager.getInstance().getAction(IdeActions.ACTION_EDITOR_ESCAPE);
83+
DumbAwareAction.create(e -> closeImmediately())
84+
.registerCustomShortcutSet(
85+
escape == null ? CommonShortcuts.ESCAPE : escape.getShortcutSet(),
86+
rootPane,
87+
myDisposable);
88+
}
89+
90+
private void setBorders(JRootPane rootPane) {
91+
rootPane.setBorder(PopupBorder.Factory.create(true, true));
92+
rootPane.setWindowDecorationStyle(JRootPane.NONE);
93+
}
94+
95+
@Override
96+
protected @Nullable JComponent createCenterPanel() {
97+
JComponent panel = new JPanel(new MigLayout(
98+
"flowx, ins 0, gap 0, fillx, filly, hidemode 3",
99+
"[left]10[" + WIDTH +",fill]"));
100+
JLabel newActiveProjectLabel = new JBLabel("New project:", SwingConstants.LEFT);
101+
newActiveProjectLabel.setBorder(JBUI.Borders.empty(10, 0));
102+
panel.add(newActiveProjectLabel, "left, bottom");
103+
this.newProjectTextField = new JBTextField();
104+
newProjectTextField.selectAll();
105+
panel.add(newProjectTextField, "pushx, growx, wrap");
106+
ComponentValidator activeProjectValidator = new ComponentValidator(myDisposable)
107+
.withValidator(new ActiveProjectValidator())
108+
.installOn(newProjectTextField)
109+
.andRegisterOnDocumentListener(newProjectTextField);
110+
activeProjectValidator.revalidate();
111+
return panel;
112+
}
113+
114+
private void closeImmediately() {
115+
if (isVisible()) {
116+
doCancelAction();
117+
}
118+
}
119+
120+
@Override
121+
protected void doOKAction() {
122+
super.doOKAction();
123+
this.newProject = newProjectTextField.getText();
124+
}
125+
126+
public String getNewProject() {
127+
return newProject;
128+
}
129+
130+
private class ActiveProjectValidator implements Supplier<ValidationInfo> {
131+
132+
@Override
133+
public ValidationInfo get() {
134+
String activeProject = newProjectTextField.getText();
135+
ValidationInfo validation = getValidationInfo(activeProject);
136+
// update OK button
137+
setOKActionEnabled(validation.okEnabled);
138+
return validation;
139+
}
140+
141+
private ValidationInfo getValidationInfo(String newProject) {
142+
ValidationInfo validation = new ValidationInfo("").withOKEnabled();
143+
if (StringUtil.isEmptyOrSpaces(newProject)) {
144+
validation = new ValidationInfo("Provide project name").forComponent(newProjectTextField).asWarning();
145+
} else if (allProjects.contains(newProject)) {
146+
validation = new ValidationInfo("Already exists, choose new name").forComponent(newProjectTextField).asWarning();
147+
}
148+
return validation;
149+
}
150+
}
151+
}

0 commit comments

Comments
 (0)