Skip to content

Commit c239834

Browse files
committed
app: home: Add delete button for clusters
Signed-off-by: Vincent T <[email protected]>
1 parent d24fc9f commit c239834

File tree

2 files changed

+64
-24
lines changed

2 files changed

+64
-24
lines changed

frontend/src/components/App/Home/index.tsx

+45-22
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ function ContextMenu({ cluster }: { cluster: Cluster }) {
3333
const menuId = useId('context-menu');
3434
const [openConfirmDialog, setOpenConfirmDialog] = React.useState(false);
3535

36-
function removeCluster(cluster: Cluster) {
37-
deleteCluster(cluster.name || '')
36+
function removeCluster(cluster: Cluster, isDynamic: boolean = false) {
37+
deleteCluster(cluster.name || '', isDynamic)
3838
.then(config => {
3939
dispatch(setConfig(config));
4040
})
@@ -92,7 +92,7 @@ function ContextMenu({ cluster }: { cluster: Cluster }) {
9292
>
9393
<ListItemText>{t('translation|Settings')}</ListItemText>
9494
</MenuItem>
95-
{helpers.isElectron() && cluster.meta_data?.source === 'dynamic_cluster' && (
95+
{helpers.isElectron() && (
9696
<MenuItem
9797
onClick={() => {
9898
setOpenConfirmDialog(true);
@@ -104,6 +104,26 @@ function ContextMenu({ cluster }: { cluster: Cluster }) {
104104
)}
105105
</Menu>
106106

107+
<ConfirmDialog
108+
open={openConfirmDialog}
109+
handleClose={() => setOpenConfirmDialog(false)}
110+
onConfirm={() => {
111+
setOpenConfirmDialog(false);
112+
// to do: create a function that removes the cluster and also edits the kubeconfig
113+
if (cluster.meta_data?.source === 'dynamic_cluster') {
114+
removeCluster(cluster, true);
115+
} else removeCluster(cluster);
116+
}}
117+
title={t('translation|Delete Cluster')}
118+
description={t(
119+
'translation|Are you sure you want to remove the cluster "{{ clusterName }}"? from "{{ clusterOrigin }}"',
120+
{
121+
clusterName: cluster.name,
122+
clusterOrigin: getOrigin(cluster),
123+
}
124+
)}
125+
/>
126+
107127
<ConfirmDialog
108128
open={openConfirmDialog}
109129
handleClose={() => setOpenConfirmDialog(false)}
@@ -113,9 +133,10 @@ function ContextMenu({ cluster }: { cluster: Cluster }) {
113133
}}
114134
title={t('translation|Delete Cluster')}
115135
description={t(
116-
'translation|Are you sure you want to remove the cluster "{{ clusterName }}"?',
136+
'translation|Are you sure you want to remove the cluster "{{ clusterName }}"? from "{{ clusterOrigin }}"',
117137
{
118138
clusterName: cluster.name,
139+
clusterOrigin: getOrigin(cluster),
119140
}
120141
)}
121142
/>
@@ -162,6 +183,26 @@ function ClusterStatus({ error }: { error?: ApiError | null }) {
162183
);
163184
}
164185

186+
/**
187+
* Gets the origin of a cluster.
188+
*
189+
* @param cluster
190+
* @returns A description of where the cluster is picked up from: dynamic, in-cluster, or from a kubeconfig file.
191+
*/
192+
function getOrigin(cluster: Cluster): string {
193+
const { t } = useTranslation(['translation']);
194+
195+
if (cluster.meta_data?.source === 'kubeconfig') {
196+
const kubeconfigPath = process.env.KUBECONFIG ?? '~/.kube/config';
197+
return `Kubeconfig: ${kubeconfigPath}`;
198+
} else if (cluster.meta_data?.source === 'dynamic_cluster') {
199+
return t('translation|Plugin');
200+
} else if (cluster.meta_data?.source === 'in_cluster') {
201+
return t('translation|In-cluster');
202+
}
203+
return 'Unknown';
204+
}
205+
165206
export default function Home() {
166207
const history = useHistory();
167208
const clusters = useClustersConf() || {};
@@ -239,24 +280,6 @@ function HomeComponent(props: HomeComponentProps) {
239280
.sort();
240281
}
241282

242-
/**
243-
* Gets the origin of a cluster.
244-
*
245-
* @param cluster
246-
* @returns A description of where the cluster is picked up from: dynamic, in-cluster, or from a kubeconfig file.
247-
*/
248-
function getOrigin(cluster: Cluster): string {
249-
if (cluster.meta_data?.source === 'kubeconfig') {
250-
const kubeconfigPath = process.env.KUBECONFIG ?? '~/.kube/config';
251-
return `Kubeconfig: ${kubeconfigPath}`;
252-
} else if (cluster.meta_data?.source === 'dynamic_cluster') {
253-
return t('translation|Plugin');
254-
} else if (cluster.meta_data?.source === 'in_cluster') {
255-
return t('translation|In-cluster');
256-
}
257-
return 'Unknown';
258-
}
259-
260283
const memoizedComponent = React.useMemo(
261284
() => (
262285
<PageGrid>

frontend/src/lib/k8s/api/v1/clusterApi.ts

+19-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { exec } from 'child_process';
2+
import { promisify } from 'util';
13
import helpers, { getHeadlampAPIHeaders } from '../../../../helpers';
24
import { ConfigState } from '../../../../redux/configSlice';
35
import store from '../../../../redux/stores/store';
@@ -10,6 +12,8 @@ import { getCluster, getClusterGroup } from '../../../util';
1012
import { ClusterRequest, clusterRequest, post, request } from './clusterRequests';
1113
import { JSON_HEADERS } from './constants';
1214

15+
const execAsync = promisify(exec);
16+
1317
/**
1418
* Test authentication for the given cluster.
1519
* Will throw an error if the user is not authenticated.
@@ -78,14 +82,27 @@ export async function setCluster(clusterReq: ClusterRequest) {
7882
// @todo: needs documenting.
7983

8084
export async function deleteCluster(
81-
cluster: string
85+
cluster: string,
86+
isDynamic: boolean
8287
): Promise<{ clusters: ConfigState['clusters'] }> {
83-
if (cluster) {
88+
if (cluster && isDynamic) {
8489
const kubeconfig = await findKubeconfigByClusterName(cluster);
8590
if (kubeconfig !== null) {
8691
await deleteClusterKubeconfig(cluster);
8792
window.location.reload();
8893
return { clusters: {} };
94+
} else if (cluster && !isDynamic) {
95+
// Delete cluster from kubeconfig for non-dynamic clusters
96+
try {
97+
await execAsync(`kubectl config unset clusters.${cluster}`);
98+
await execAsync(`kubectl config unset contexts.${cluster}`);
99+
await execAsync(`kubectl config unset users.${cluster}`);
100+
window.location.reload();
101+
return { clusters: {} };
102+
} catch (error) {
103+
console.error('Failed to delete non-dynamic cluster:', error);
104+
throw error;
105+
}
89106
}
90107
}
91108

0 commit comments

Comments
 (0)