Skip to content

Commit 282e741

Browse files
committed
allow user to set ns/project with ctx menu (#521)
Signed-off-by: Andre Dietisheim <[email protected]>
1 parent 9fe217c commit 282e741

File tree

11 files changed

+429
-122
lines changed

11 files changed

+429
-122
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2023 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 com.redhat.devtools.intellij.kubernetes.actions
12+
13+
import com.intellij.openapi.actionSystem.AnActionEvent
14+
import com.intellij.openapi.application.runInEdt
15+
import com.intellij.openapi.diagnostic.logger
16+
import com.intellij.openapi.project.Project
17+
import com.redhat.devtools.intellij.common.actions.StructureTreeAction
18+
import com.redhat.devtools.intellij.kubernetes.dialogs.ResourceNameDialog
19+
import com.redhat.devtools.intellij.kubernetes.model.IResourceModel
20+
import com.redhat.devtools.intellij.kubernetes.model.Notification
21+
import com.redhat.devtools.intellij.kubernetes.model.context.IActiveContext.ResourcesIn
22+
import com.redhat.devtools.intellij.kubernetes.model.resource.kubernetes.NamespacesOperator
23+
import com.redhat.devtools.intellij.kubernetes.model.util.ResourceException
24+
import com.redhat.devtools.intellij.kubernetes.model.util.toMessage
25+
import com.redhat.devtools.intellij.kubernetes.telemetry.TelemetryService
26+
import com.redhat.devtools.intellij.kubernetes.tree.KubernetesStructure.NamespacesFolder
27+
import java.awt.Point
28+
import java.awt.event.MouseEvent
29+
import java.util.concurrent.CompletableFuture.runAsync
30+
import javax.swing.tree.TreePath
31+
32+
class SetCurrentNamespaceAction : StructureTreeAction(false) {
33+
34+
override fun actionPerformed(event: AnActionEvent?, path: TreePath?, selectedNode: Any?) {
35+
val project = event?.project ?: return
36+
val model = getResourceModel() ?: return
37+
38+
openNameDialog(project, model, (event.inputEvent as? MouseEvent)?.locationOnScreen)
39+
}
40+
41+
private fun openNameDialog(project: Project, model: IResourceModel, location: Point?) {
42+
runAsync {
43+
val projects = loadNamespaces(model)
44+
runInEdt {
45+
val dialog = ResourceNameDialog(project, "Namespace", projects, onOk(model), location)
46+
dialog.showAndGet()
47+
}
48+
}
49+
}
50+
51+
private fun loadNamespaces(model: IResourceModel) = try {
52+
model.getCurrentContext()?.getAllResources(NamespacesOperator.KIND, ResourcesIn.NO_NAMESPACE)
53+
} catch (e: ResourceException) {
54+
logger<SetCurrentNamespaceAction>().warn(
55+
"Could not get all namespaces.", e
56+
)
57+
null
58+
} ?: emptyList()
59+
60+
private fun onOk(model: IResourceModel): (projectName: String) -> Unit {
61+
return { name ->
62+
run("Setting current namespace $name...", true) {
63+
val telemetry = TelemetryService.instance
64+
.action(TelemetryService.NAME_PREFIX_NAMESPACE + "switch_by_name")
65+
try {
66+
model.setCurrentNamespace(name)
67+
telemetry.success().send()
68+
} catch (e: Exception) {
69+
Notification().error("Could not set current namespace $name", toMessage(e))
70+
logger<SetCurrentNamespaceAction>().warn(
71+
"Could not set current namespace ${name}.", e
72+
)
73+
telemetry.error(e).send()
74+
}
75+
}
76+
}
77+
}
78+
79+
override fun isVisible(selected: Any?): Boolean {
80+
return selected?.getElement<NamespacesFolder>() != null
81+
}
82+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2023 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 com.redhat.devtools.intellij.kubernetes.actions
12+
13+
import com.intellij.openapi.actionSystem.AnActionEvent
14+
import com.intellij.openapi.application.runInEdt
15+
import com.intellij.openapi.diagnostic.logger
16+
import com.intellij.openapi.project.Project
17+
import com.redhat.devtools.intellij.common.actions.StructureTreeAction
18+
import com.redhat.devtools.intellij.kubernetes.dialogs.ResourceNameDialog
19+
import com.redhat.devtools.intellij.kubernetes.model.IResourceModel
20+
import com.redhat.devtools.intellij.kubernetes.model.Notification
21+
import com.redhat.devtools.intellij.kubernetes.model.context.IActiveContext.ResourcesIn
22+
import com.redhat.devtools.intellij.kubernetes.model.resource.openshift.ProjectsOperator
23+
import com.redhat.devtools.intellij.kubernetes.model.util.ResourceException
24+
import com.redhat.devtools.intellij.kubernetes.model.util.toMessage
25+
import com.redhat.devtools.intellij.kubernetes.telemetry.TelemetryService
26+
import com.redhat.devtools.intellij.kubernetes.tree.OpenShiftStructure.ProjectsFolder
27+
import java.awt.Point
28+
import java.awt.event.MouseEvent
29+
import javax.swing.tree.TreePath
30+
import org.jetbrains.concurrency.runAsync
31+
32+
class SetCurrentProjectAction : StructureTreeAction(false) {
33+
34+
override fun actionPerformed(event: AnActionEvent?, path: TreePath?, selectedNode: Any?) {
35+
val project = event?.project ?: return
36+
val model = getResourceModel() ?: return
37+
38+
openNameDialog(project, model, (event.inputEvent as? MouseEvent)?.locationOnScreen)
39+
}
40+
41+
private fun openNameDialog(project: Project, model: IResourceModel, location: Point?) {
42+
runAsync {
43+
val projects = loadProjects(model)
44+
runInEdt {
45+
val dialog = ResourceNameDialog(project, "Project", projects, onOk(model), location)
46+
dialog.showAndGet()
47+
}
48+
}
49+
}
50+
51+
private fun loadProjects(model: IResourceModel) = try {
52+
model.getCurrentContext()?.getAllResources(ProjectsOperator.KIND, ResourcesIn.NO_NAMESPACE)
53+
} catch (e: ResourceException) {
54+
logger<SetCurrentProjectAction>().warn(
55+
"Could not get all projects.", e
56+
)
57+
null
58+
} ?: emptyList()
59+
60+
private fun onOk(model: IResourceModel): (projectName: String) -> Unit {
61+
return { name ->
62+
run("Setting current project $name...", true) {
63+
val telemetry = TelemetryService.instance
64+
.action(TelemetryService.NAME_PREFIX_NAMESPACE + "switch_by_name")
65+
try {
66+
model.setCurrentNamespace(name)
67+
telemetry.success().send()
68+
} catch (e: Exception) {
69+
Notification().error("Could not set current project $name", toMessage(e))
70+
logger<SetCurrentProjectAction>().warn(
71+
"Could not set current project ${name}.", e
72+
)
73+
telemetry.error(e).send()
74+
}
75+
}
76+
}
77+
}
78+
79+
override fun isVisible(selected: Any?): Boolean {
80+
return selected?.getElement<ProjectsFolder>() != null
81+
}
82+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2023 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 com.redhat.devtools.intellij.kubernetes.dialogs
12+
13+
import com.intellij.openapi.project.Project
14+
import com.intellij.openapi.ui.DialogWrapper
15+
import com.intellij.openapi.ui.ValidationInfo
16+
import com.intellij.ui.TextFieldWithAutoCompletion
17+
import com.intellij.ui.TextFieldWithAutoCompletionListProvider
18+
import com.intellij.ui.components.JBLabel
19+
import com.intellij.util.ui.JBUI
20+
import io.fabric8.kubernetes.api.model.HasMetadata
21+
import java.awt.BorderLayout
22+
import java.awt.Point
23+
import javax.swing.Box
24+
import javax.swing.BoxLayout
25+
import javax.swing.JComponent
26+
import javax.swing.JPanel
27+
import javax.swing.SwingConstants
28+
29+
class ResourceNameDialog<NAMESPACE: HasMetadata>(
30+
project: Project,
31+
private val kind: String,
32+
existingNamespaces: Collection<NAMESPACE>,
33+
private val onOk: (name: String) -> Unit,
34+
private val location: Point?
35+
) : DialogWrapper(project, false) {
36+
37+
companion object {
38+
private const val HEIGHT = 40
39+
private const val WIDTH = 300
40+
}
41+
42+
private val nameTextField = TextFieldWithAutoCompletion(
43+
project,
44+
onLookup(existingNamespaces),
45+
false,
46+
null
47+
)
48+
49+
private fun onLookup(projects: Collection<NAMESPACE>): TextFieldWithAutoCompletionListProvider<NAMESPACE> {
50+
return object : TextFieldWithAutoCompletionListProvider<NAMESPACE>(projects) {
51+
override fun getLookupString(item: NAMESPACE): String {
52+
return item.metadata.name
53+
}
54+
}
55+
}
56+
57+
override fun createCenterPanel(): JComponent {
58+
return JPanel(BorderLayout()).apply {
59+
layout = BoxLayout(this, BoxLayout.Y_AXIS)
60+
val label = JBLabel("Current $kind:", SwingConstants.LEFT)
61+
label.border = JBUI.Borders.empty(0, 0, 10, 0)
62+
add(label)
63+
add(nameTextField)
64+
add(Box.createVerticalBox())
65+
}
66+
}
67+
68+
override fun init() {
69+
title = "Set Current $kind"
70+
setResizable(false)
71+
setOKButtonText("Set")
72+
isModal = false
73+
setSize(WIDTH, HEIGHT)
74+
if (location != null) {
75+
setLocation(location.x, location.y)
76+
}
77+
super.init()
78+
}
79+
80+
override fun getPreferredFocusedComponent(): JComponent {
81+
return nameTextField
82+
}
83+
84+
override fun show() {
85+
init()
86+
super.show()
87+
}
88+
89+
override fun doValidate(): ValidationInfo? {
90+
return if (nameTextField.text.isEmpty()) {
91+
ValidationInfo("Name musn't be empty", nameTextField)
92+
} else {
93+
null
94+
}
95+
}
96+
97+
override fun doOKAction() {
98+
super.doOKAction()
99+
onOk.invoke(nameTextField.text)
100+
}
101+
}

0 commit comments

Comments
 (0)