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

Commit b76864c

Browse files
authored
feat: validate new project name (#237) (#680)
* feat: validate new project name (#237) Signed-off-by: Andre Dietisheim <[email protected]> * feat: ctx menu & dialog shows "namespace"/"project" depending on cluster type (#237, #701) Signed-off-by: Andre Dietisheim <[email protected]> Signed-off-by: Stephane Bouchet <[email protected]> * namespace/project in 'Change Project' action and dialog (#701) Signed-off-by: Andre Dietisheim <[email protected]> Signed-off-by: Stephane Bouchet <[email protected]> --------- Signed-off-by: Andre Dietisheim <[email protected]> Signed-off-by: Stephane Bouchet <[email protected]>
1 parent 59e700e commit b76864c

File tree

13 files changed

+392
-106
lines changed

13 files changed

+392
-106
lines changed

src/main/java/org/jboss/tools/intellij/openshift/actions/OdoAction.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public void actionPerformed(AnActionEvent anActionEvent, TreePath path, Object s
4545
this.actionPerformedOnSelectedObject(anActionEvent, getElement(selected), odo);
4646
}
4747

48-
private Odo getOdo(AnActionEvent anActionEvent) {
48+
protected Odo getOdo(AnActionEvent anActionEvent) {
4949
try {
5050
return ActionUtils.getApplicationRootNode(anActionEvent).getOdo().getNow(null);
5151
} catch(Exception e) {

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

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,19 @@ public static void execute(ParentableNode<?> node) {
5656
action.doActionPerformed(rootNode, location, odo, project);
5757
}
5858

59+
@Override
60+
public void update(AnActionEvent e) {
61+
super.update(e);
62+
if (e.getPresentation().isVisible()) {
63+
Odo odo = getOdo(e);
64+
if (odo == null) {
65+
return;
66+
}
67+
// overrides label given in plugin.xml
68+
e.getPresentation().setText("Change " + odo.getNamespaceKind());
69+
}
70+
}
71+
5972
@Override
6073
public void actionPerformedOnSelectedObject(AnActionEvent anActionEvent, Object selected, @NotNull Odo odo) {
6174
Project project = getEventProject(anActionEvent);
@@ -71,16 +84,18 @@ private void doActionPerformed(final ApplicationsRootNode rootNode, final Point
7184
try {
7285
return new ClusterProjects(odo.isOpenShift(), odo.getCurrentNamespace(), odo.getNamespaces());
7386
} catch (IOException e) {
74-
NotificationUtils.notifyError("Change Active Project", "Could not get projects: " + e.getMessage());
87+
NotificationUtils.notifyError(
88+
"Change Active " + odo.getNamespaceKind(),
89+
"Could not get " + odo.getNamespaceKind().toLowerCase() + ": " + e.getMessage());
7590
sendTelemetryError(e.getMessage());
7691
throw new RuntimeException(e);
7792
}
7893
}, SwingUtils.EXECUTOR_BACKGROUND)
79-
.handleAsync((ClusterProjects, error) -> {
94+
.handleAsync((clusterProjects, error) -> {
8095
if (error != null) {
8196
return null;
8297
}
83-
ChangeActiveProjectDialog dialog = openActiveProjectDialog(ClusterProjects.isOpenShift, ClusterProjects.current, ClusterProjects.all, location, project);
98+
ChangeActiveProjectDialog dialog = openActiveProjectDialog(clusterProjects.current, clusterProjects.all, location, odo, project);
8499
if (dialog.isOK()) {
85100
return new ChangeActiveProjectOperation(dialog.getActiveProject(), odo);
86101
} else if (dialog.isCreateNewProject()) {
@@ -103,9 +118,8 @@ private void doActionPerformed(final ApplicationsRootNode rootNode, final Point
103118
project);
104119
}
105120

106-
private ChangeActiveProjectDialog openActiveProjectDialog(boolean isOpenShift, String currentProject, List<String> allProjects, Point location, Project project) {
107-
String kind = isOpenShift ? "Project" : "Namespace";
108-
ChangeActiveProjectDialog dialog = new ChangeActiveProjectDialog(project, kind, currentProject, allProjects, location);
121+
private ChangeActiveProjectDialog openActiveProjectDialog(String currentProject, List<String> allProjects, Point location, Odo odo, Project project) {
122+
ChangeActiveProjectDialog dialog = new ChangeActiveProjectDialog(project, odo.getNamespaceKind(), currentProject, allProjects, location);
109123
dialog.show();
110124
return dialog;
111125
}
@@ -146,12 +160,17 @@ private ChangeActiveProjectOperation(String activeProject, Odo odo) {
146160

147161
@Override
148162
public void run() {
163+
String kind = odo.getNamespaceKind();
149164
try {
150165
odo.setProject(activeProject);
151-
NotificationUtils.notifyInformation("Change active project", "Active project set to '" + activeProject + "'");
166+
NotificationUtils.notifyInformation(
167+
"Change active " + kind,
168+
"Active " + kind.toLowerCase() + " set to '" + activeProject + "'");
152169
sendTelemetryResults(TelemetryService.TelemetryResult.SUCCESS);
153170
} catch (IOException e) {
154-
NotificationUtils.notifyError("Change active project", "Could not set active project: " + e.getMessage());
171+
NotificationUtils.notifyError(
172+
"Change active " + kind.toLowerCase(),
173+
"Could not set active " + kind.toLowerCase() + ": " + e.getMessage());
155174
throw new RuntimeException(e);
156175
}
157176
}

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

Lines changed: 104 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,56 +19,135 @@
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;
28+
import org.slf4j.Logger;
29+
import org.slf4j.LoggerFactory;
2530

31+
import java.awt.Point;
2632
import java.io.IOException;
33+
import java.util.List;
34+
import java.util.concurrent.CompletableFuture;
2735
import java.util.concurrent.CompletionException;
2836

2937
import static org.jboss.tools.intellij.openshift.actions.ActionUtils.runWithProgress;
38+
import static org.jboss.tools.intellij.openshift.actions.NodeUtils.getRoot;
3039
import static org.jboss.tools.intellij.openshift.telemetry.TelemetryService.TelemetryResult;
3140

3241
public class CreateProjectAction extends LoggedInClusterAction {
3342

34-
@Override
35-
public String getTelemetryActionName() { return "create project"; }
43+
private static final Logger LOGGER = LoggerFactory.getLogger(CreateProjectAction.class);
3644

3745
public static void execute(ApplicationsRootNode rootNode) {
3846
Odo odo = rootNode.getOdo().getNow(null);
3947
if (odo == null) {
4048
return;
4149
}
4250
CreateProjectAction action = ActionUtils.createAction(CreateProjectAction.class.getName());
43-
action.doActionPerformed(rootNode, odo, rootNode.getProject());
51+
action.doActionPerformed(null, odo, rootNode.getProject());
52+
}
53+
54+
@Override
55+
public void update(AnActionEvent e) {
56+
super.update(e);
57+
if (e.getPresentation().isVisible()) {
58+
Odo odo = getOdo(e);
59+
if (odo == null) {
60+
return;
61+
}
62+
// overrides label given in plugin.xml
63+
e.getPresentation().setText("New " + odo.getNamespaceKind());
64+
}
65+
}
66+
67+
@Override
68+
public String getTelemetryActionName() {
69+
return "create project";
4470
}
4571

4672
@Override
4773
public void actionPerformedOnSelectedObject(AnActionEvent anActionEvent, Object selected, @NotNull Odo odo) {
48-
ApplicationsRootNode clusterNode = (ApplicationsRootNode) selected;
49-
doActionPerformed(clusterNode, odo, getEventProject(anActionEvent));
74+
Point location = ActionUtils.getLocation(anActionEvent);
75+
doActionPerformed(location, odo, getEventProject(anActionEvent));
5076
}
5177

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;
78+
private void doActionPerformed(final Point location, @NotNull final Odo odo, Project project) {
79+
String kind = odo.getNamespaceKind();
80+
runWithProgress((ProgressIndicator progress) ->
81+
CompletableFuture
82+
.supplyAsync(() -> {
83+
try {
84+
return odo.getNamespaces();
85+
} catch (IOException e) {
86+
NotificationUtils.notifyError("Create New " + kind, "Could not get " + kind.toLowerCase() + "s: " + e.getMessage());
87+
sendTelemetryError(e.getMessage());
88+
throw new CompletionException(e);
89+
}
90+
}, SwingUtils.EXECUTOR_BACKGROUND)
91+
.handleAsync((allProjects, error) -> {
92+
if (error != null) {
93+
return null;
94+
}
95+
CreateNewProjectDialog dialog = openCreateProjectDialog(allProjects, kind, location, project);
96+
if (dialog.isOK()) {
97+
return dialog.getNewProject();
98+
} else {
99+
sendTelemetryResults(TelemetryService.TelemetryResult.ABORTED);
100+
return null;
101+
}
102+
}
103+
, SwingUtils.EXECUTOR_UI)
104+
.whenCompleteAsync((newProject, error) -> {
105+
if (error != null
106+
|| newProject == null) {
107+
return;
108+
}
109+
createProject(newProject, odo);
110+
}, SwingUtils.EXECUTOR_BACKGROUND),
111+
"Create Active " + kind + "...",
112+
project);
113+
}
114+
115+
private void createProject(String newProject, @NotNull Odo odo) {
116+
String kind = odo.getNamespaceKind();
117+
Notification notification = NotificationUtils.notifyInformation("Create " + kind, "Creating " + kind.toLowerCase() + " newProject");
118+
try {
119+
odo.createProject(newProject);
120+
notification.expire();
121+
NotificationUtils.notifyInformation("Create " + kind, kind + newProject + " successfully created");
122+
sendTelemetryResults(TelemetryResult.SUCCESS);
123+
} catch (IOException | CompletionException e) {
124+
notification.expire();
125+
sendTelemetryError(e);
126+
UIHelper.executeInUI(() -> Messages.showErrorDialog("Error: " + e.getLocalizedMessage(), "Create " + kind));
57127
}
58-
runWithProgress((ProgressIndicator progress) -> {
59-
try {
60-
Notification notif = NotificationUtils.notifyInformation("Create Project", "Creating project " + projectName);
61-
odo.createProject(projectName);
62-
notif.expire();
63-
NotificationUtils.notifyInformation("Create Project", "Project " + projectName + " successfully created");
64-
clusterNode.getStructure().fireModified(clusterNode);
65-
sendTelemetryResults(TelemetryResult.SUCCESS);
66-
} catch (IOException | CompletionException e) {
67-
sendTelemetryError(e);
68-
UIHelper.executeInUI(() -> Messages.showErrorDialog("Error: " + e.getLocalizedMessage(), "Create Project"));
69-
}
70-
},
71-
"Create Project...",
72-
project);
128+
}
129+
130+
protected CreateNewProjectDialog openCreateProjectDialog(List<String> allProjects, String kind, Point location, Project project) {
131+
CreateNewProjectDialog dialog = new CreateNewProjectDialog(project, allProjects, kind, location);
132+
dialog.show();
133+
return dialog;
134+
}
135+
136+
@Override
137+
public boolean isVisible(Object selected) {
138+
return isRoot(selected)
139+
&& isLoggedIn(selected);
140+
}
141+
142+
private boolean isLoggedIn(Object node) {
143+
ApplicationsRootNode root = getRoot(node);
144+
if (root == null) {
145+
return false;
146+
}
147+
return root.isLogged();
148+
}
149+
150+
private boolean isRoot(Object node) {
151+
return node instanceof ApplicationsRootNode;
73152
}
74153
}

src/main/java/org/jboss/tools/intellij/openshift/tree/application/ApplicationRootNodeOdo.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ public boolean namespaceExists(String name) {
7373
return delegate.namespaceExists(name);
7474
}
7575

76+
@Override
77+
public String getNamespaceKind() {
78+
return delegate.getNamespaceKind();
79+
}
80+
7681
@Override
7782
public void start(String project, String context, String component, ComponentFeature feature,
7883
Consumer<Boolean> callback, Consumer<Boolean> processTerminatedCallback) throws IOException {

src/main/java/org/jboss/tools/intellij/openshift/tree/application/ChangeActiveProjectLinkNode.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,26 @@
1212

1313
import com.redhat.devtools.intellij.common.tree.LinkElement;
1414
import org.jboss.tools.intellij.openshift.actions.project.ChangeActiveProjectAction;
15+
import org.jboss.tools.intellij.openshift.utils.odo.Odo;
1516

1617
public class ChangeActiveProjectLinkNode extends MessageNode<NamespaceNode> implements LinkElement {
18+
1719
protected ChangeActiveProjectLinkNode(ApplicationsRootNode root, NamespaceNode parent) {
18-
super(root, parent, "Missing project, <a>choose or create a different one</a>");
20+
super(root, parent, getLabel(root));
1921
}
2022

2123
@Override
2224
public void execute() {
2325
ChangeActiveProjectAction.execute(getParent());
2426
}
27+
28+
private static String getLabel(ApplicationsRootNode root) {
29+
Odo odo = root.getOdo().getNow(null);
30+
String label = "Missing %s, <a>choose or create a different one</a>";
31+
if (odo == null) {
32+
return String.format(label, "project/namespace");
33+
} else {
34+
return String.format(label, odo.getNamespaceKind().toLowerCase());
35+
}
36+
}
2537
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
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;
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.DialogWrapper;
20+
import com.intellij.ui.PopupBorder;
21+
import org.jetbrains.annotations.Nullable;
22+
23+
import javax.swing.JRootPane;
24+
import javax.swing.RootPaneContainer;
25+
import java.awt.Point;
26+
import java.awt.Window;
27+
28+
import static org.jboss.tools.intellij.openshift.ui.SwingUtils.locationOrMouseLocation;
29+
30+
public abstract class BaseDialog extends DialogWrapper {
31+
32+
private final Point location;
33+
34+
protected BaseDialog(@Nullable Project project, Point location) {
35+
super(project, false);
36+
this.location = location;
37+
}
38+
39+
/**
40+
* Set the borders, location etc.
41+
* Has to be called from the extending subclass.
42+
*/
43+
@Override
44+
protected void init() {
45+
super.init();
46+
Window dialogWindow = getPeer().getWindow();
47+
JRootPane rootPane = ((RootPaneContainer) dialogWindow).getRootPane();
48+
registerShortcuts(rootPane);
49+
setBorders(rootPane);
50+
setLocation(locationOrMouseLocation(location));
51+
}
52+
53+
private void registerShortcuts(JRootPane rootPane) {
54+
AnAction escape = ActionManager.getInstance().getAction(IdeActions.ACTION_EDITOR_ESCAPE);
55+
DumbAwareAction.create(e -> closeImmediately())
56+
.registerCustomShortcutSet(
57+
escape == null ? CommonShortcuts.ESCAPE : escape.getShortcutSet(),
58+
rootPane,
59+
myDisposable);
60+
}
61+
62+
private void setBorders(JRootPane rootPane) {
63+
rootPane.setBorder(PopupBorder.Factory.create(true, true));
64+
rootPane.setWindowDecorationStyle(JRootPane.NONE);
65+
}
66+
67+
protected void closeImmediately() {
68+
if (isVisible()) {
69+
doCancelAction();
70+
}
71+
}
72+
}

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
}

0 commit comments

Comments
 (0)