From bbe94f55b64a1784098cfc58cec9d3aae3a0ac98 Mon Sep 17 00:00:00 2001 From: Ali <83188384+testA113@users.noreply.github.com> Date: Tue, 22 Apr 2025 09:52:52 +1200 Subject: [PATCH] feat(helm): uninstall helm app from details view [r8s-285] (#648) --- .../queries/useDeleteApplicationsMutation.ts | 22 +++------ .../ChartActions/ChartActions.tsx | 30 ++++++++++++ .../ChartActions/UninstallButton.tsx | 47 +++++++++++++++++++ .../HelmApplicationView.tsx | 13 ++++- .../queries/useUninstallHelmAppMutation.ts | 39 +++++++++++++++ 5 files changed, 133 insertions(+), 18 deletions(-) create mode 100644 app/react/kubernetes/helm/HelmApplicationView/ChartActions/ChartActions.tsx create mode 100644 app/react/kubernetes/helm/HelmApplicationView/ChartActions/UninstallButton.tsx create mode 100644 app/react/kubernetes/helm/HelmApplicationView/queries/useUninstallHelmAppMutation.ts diff --git a/app/react/kubernetes/applications/queries/useDeleteApplicationsMutation.ts b/app/react/kubernetes/applications/queries/useDeleteApplicationsMutation.ts index 047cf1a44..fcaf9df8f 100644 --- a/app/react/kubernetes/applications/queries/useDeleteApplicationsMutation.ts +++ b/app/react/kubernetes/applications/queries/useDeleteApplicationsMutation.ts @@ -7,6 +7,7 @@ import { getAllSettledItems } from '@/portainer/helpers/promise-utils'; import { withGlobalError } from '@/react-tools/react-query'; import { notifyError, notifySuccess } from '@/portainer/services/notifications'; import { pluralize } from '@/portainer/helpers/strings'; +import { uninstallHelmApplication } from '@/react/kubernetes/helm/HelmApplicationView/queries/useUninstallHelmAppMutation'; import { parseKubernetesAxiosError } from '../../axiosError'; import { ApplicationRowData } from '../ListView/ApplicationsDatatable/types'; @@ -225,7 +226,11 @@ async function deleteApplication( await deletePodApplication(application, stacks, environmentId); break; case 'Helm': - await uninstallHelmApplication(application, environmentId); + await uninstallHelmApplication( + environmentId, + application.Name, + application.ResourcePool + ); break; default: throw new Error( @@ -266,21 +271,6 @@ async function deletePodApplication( } } -async function uninstallHelmApplication( - application: ApplicationRowData, - environmentId: EnvironmentId -) { - try { - await axios.delete( - `/endpoints/${environmentId}/kubernetes/helm/${application.Name}`, - { params: { namespace: application.ResourcePool } } - ); - } catch (error) { - // parseAxiosError, because it's a regular portainer api error - throw parseAxiosError(error, 'Unable to remove application'); - } -} - async function deleteHorizontalPodAutoscaler( hpa: HorizontalPodAutoscaler, environmentId: EnvironmentId diff --git a/app/react/kubernetes/helm/HelmApplicationView/ChartActions/ChartActions.tsx b/app/react/kubernetes/helm/HelmApplicationView/ChartActions/ChartActions.tsx new file mode 100644 index 000000000..c67984952 --- /dev/null +++ b/app/react/kubernetes/helm/HelmApplicationView/ChartActions/ChartActions.tsx @@ -0,0 +1,30 @@ +import { EnvironmentId } from '@/react/portainer/environments/types'; +import { useAuthorizations } from '@/react/hooks/useUser'; + +import { UninstallButton } from './UninstallButton'; + +export function ChartActions({ + environmentId, + releaseName, + namespace, +}: { + environmentId: EnvironmentId; + releaseName: string; + namespace?: string; +}) { + const { authorized } = useAuthorizations('K8sApplicationsW'); + + if (!authorized) { + return null; + } + + return ( +
+ +
+ ); +} diff --git a/app/react/kubernetes/helm/HelmApplicationView/ChartActions/UninstallButton.tsx b/app/react/kubernetes/helm/HelmApplicationView/ChartActions/UninstallButton.tsx new file mode 100644 index 000000000..fc2c6d5c2 --- /dev/null +++ b/app/react/kubernetes/helm/HelmApplicationView/ChartActions/UninstallButton.tsx @@ -0,0 +1,47 @@ +import { useRouter } from '@uirouter/react'; + +import { EnvironmentId } from '@/react/portainer/environments/types'; +import { notifySuccess } from '@/portainer/services/notifications'; + +import { DeleteButton } from '@@/buttons/DeleteButton'; + +import { useUninstallHelmAppMutation } from '../queries/useUninstallHelmAppMutation'; + +export function UninstallButton({ + environmentId, + releaseName, + namespace, +}: { + environmentId: EnvironmentId; + releaseName: string; + namespace?: string; +}) { + const uninstallHelmAppMutation = useUninstallHelmAppMutation(environmentId); + const router = useRouter(); + + return ( + + Uninstall + + ); + + function handleUninstall() { + uninstallHelmAppMutation.mutate( + { releaseName, namespace }, + { + onSuccess: () => { + router.stateService.go('kubernetes.applications', { + endpointId: environmentId, + }); + notifySuccess('Success', 'Helm chart uninstalled successfully'); + }, + } + ); + } +} diff --git a/app/react/kubernetes/helm/HelmApplicationView/HelmApplicationView.tsx b/app/react/kubernetes/helm/HelmApplicationView/HelmApplicationView.tsx index 2fc5fb601..6aec1d50a 100644 --- a/app/react/kubernetes/helm/HelmApplicationView/HelmApplicationView.tsx +++ b/app/react/kubernetes/helm/HelmApplicationView/HelmApplicationView.tsx @@ -12,6 +12,7 @@ import { Alert } from '@@/Alert'; import { HelmSummary } from './HelmSummary'; import { ReleaseTabs } from './ReleaseDetails/ReleaseTabs'; import { useHelmRelease } from './queries/useHelmRelease'; +import { ChartActions } from './ChartActions/ChartActions'; export function HelmApplicationView() { const environmentId = useEnvironmentId(); @@ -32,8 +33,16 @@ export function HelmApplicationView() {
- {name && } - + {name && ( + + + + )} + uninstallHelmApplication(environmentId, releaseName, namespace), + ...withInvalidate(queryClient, [ + applicationsQueryKeys.applications(environmentId), + ]), + ...withGlobalError('Unable to uninstall helm application'), + }); +} + +export async function uninstallHelmApplication( + environmentId: EnvironmentId, + releaseName: string, + namespace?: string +) { + try { + await axios.delete( + `/endpoints/${environmentId}/kubernetes/helm/${releaseName}`, + { params: { namespace } } + ); + } catch (error) { + // parseAxiosError, because it's a regular portainer api error + throw parseAxiosError(error, 'Unable to remove application'); + } +}