From d49fcd8f3eb111a72dbed1892b120c558d8ec60e Mon Sep 17 00:00:00 2001 From: Ali <83188384+testA113@users.noreply.github.com> Date: Wed, 14 May 2025 16:31:42 +1200 Subject: [PATCH] feat(helm): make the atomic flag optional [r8s-314] (#733) --- api/http/handler/helm/helm_install.go | 2 ++ .../ChartActions/UpgradeHelmModal.tsx | 18 +++++++++++++++++- .../HelmEventsDatatable.test.tsx | 4 +++- .../ReleaseDetails/HelmEventsDatatable.tsx | 3 ++- .../ResourcesTable/ResourcesTable.test.tsx | 16 ++++++++++++---- .../ResourcesTable/ResourcesTable.tsx | 2 +- .../ResourcesTable/columns/resourceType.tsx | 14 ++++++++++++++ .../ResourcesTable/columns/status.tsx | 18 +++++++++++++++++- .../queries/useUpdateHelmReleaseMutation.ts | 1 + pkg/libhelm/options/install_options.go | 1 + pkg/libhelm/sdk/upgrade.go | 2 +- 11 files changed, 71 insertions(+), 10 deletions(-) diff --git a/api/http/handler/helm/helm_install.go b/api/http/handler/helm/helm_install.go index cd4985770..83ae0db51 100644 --- a/api/http/handler/helm/helm_install.go +++ b/api/http/handler/helm/helm_install.go @@ -27,6 +27,7 @@ type installChartPayload struct { Repo string `json:"repo"` Values string `json:"values"` Version string `json:"version"` + Atomic bool `json:"atomic"` } var errChartNameInvalid = errors.New("invalid chart name. " + @@ -105,6 +106,7 @@ func (handler *Handler) installChart(r *http.Request, p installChartPayload) (*r Version: p.Version, Namespace: p.Namespace, Repo: p.Repo, + Atomic: p.Atomic, KubernetesClusterAccess: clusterAccess, } diff --git a/app/react/kubernetes/helm/HelmApplicationView/ChartActions/UpgradeHelmModal.tsx b/app/react/kubernetes/helm/HelmApplicationView/ChartActions/UpgradeHelmModal.tsx index bb71f28c5..8dba31e38 100644 --- a/app/react/kubernetes/helm/HelmApplicationView/ChartActions/UpgradeHelmModal.tsx +++ b/app/react/kubernetes/helm/HelmApplicationView/ChartActions/UpgradeHelmModal.tsx @@ -11,6 +11,7 @@ import { Input } from '@@/form-components/Input'; import { CodeEditor } from '@@/CodeEditor'; import { FormControl } from '@@/form-components/FormControl'; import { WidgetTitle } from '@@/Widget'; +import { Checkbox } from '@@/form-components/Checkbox'; import { UpdateHelmReleasePayload } from '../queries/useUpdateHelmReleaseMutation'; import { ChartVersion } from '../queries/useHelmRepositories'; @@ -37,7 +38,7 @@ export function UpgradeHelmModal({ values, versions, onSubmit }: Props) { versionOptions[0]?.value; const [version, setVersion] = useState(defaultVersion); const [userValues, setUserValues] = useState(values.values || ''); - + const [atomic, setAtomic] = useState(false); return ( onSubmit()} @@ -88,6 +89,20 @@ export function UpgradeHelmModal({ values, versions, onSubmit }: Props) { data-cy="helm-namespace-input" /> + + setAtomic(e.target.checked)} + /> + { await waitFor(() => { expect( - screen.getByText('Events reflect the latest revision only.') + screen.getByText( + 'Only events for resources currently in the cluster will be displayed.' + ) ).toBeInTheDocument(); }); diff --git a/app/react/kubernetes/helm/HelmApplicationView/ReleaseDetails/HelmEventsDatatable.tsx b/app/react/kubernetes/helm/HelmApplicationView/ReleaseDetails/HelmEventsDatatable.tsx index d02423d82..ced859f54 100644 --- a/app/react/kubernetes/helm/HelmApplicationView/ReleaseDetails/HelmEventsDatatable.tsx +++ b/app/react/kubernetes/helm/HelmApplicationView/ReleaseDetails/HelmEventsDatatable.tsx @@ -42,7 +42,8 @@ export function HelmEventsDatatable({ dataset={eventsQuery.data || []} title={ - Events reflect the latest revision only. + Only events for resources currently in the cluster will be + displayed. } titleIcon={null} diff --git a/app/react/kubernetes/helm/HelmApplicationView/ReleaseDetails/ResourcesTable/ResourcesTable.test.tsx b/app/react/kubernetes/helm/HelmApplicationView/ReleaseDetails/ResourcesTable/ResourcesTable.test.tsx index 113776344..1bae99912 100644 --- a/app/react/kubernetes/helm/HelmApplicationView/ReleaseDetails/ResourcesTable/ResourcesTable.test.tsx +++ b/app/react/kubernetes/helm/HelmApplicationView/ReleaseDetails/ResourcesTable/ResourcesTable.test.tsx @@ -167,9 +167,13 @@ describe('ResourcesTable', () => { ); // Check that success badge is rendered - const successBadge = screen.getByText('MinimumReplicasAvailable'); + const successBadge = screen.getByText( + (content, element) => + content.includes('MinimumReplicasAvailable') && + element !== null && + element.className.includes('bg-success') + ); expect(successBadge).toBeInTheDocument(); - expect(successBadge.className).toContain('bg-success'); }); it('should show error badges for failed resources', () => { @@ -177,8 +181,12 @@ describe('ResourcesTable', () => { expect(screen.getByText('probe-failure-nginx-bad')).toBeInTheDocument(); // Check for the unhealthy status badge and make sure it has the error styling - const errorBadge = screen.getByText('InsufficientPods'); + const errorBadge = screen.getByText( + (content, element) => + content.includes('InsufficientPods') && + element !== null && + element.className.includes('bg-error') + ); expect(errorBadge).toBeInTheDocument(); - expect(errorBadge.className).toContain('bg-error'); }); }); diff --git a/app/react/kubernetes/helm/HelmApplicationView/ReleaseDetails/ResourcesTable/ResourcesTable.tsx b/app/react/kubernetes/helm/HelmApplicationView/ReleaseDetails/ResourcesTable/ResourcesTable.tsx index 8469e38fe..1757535ba 100644 --- a/app/react/kubernetes/helm/HelmApplicationView/ReleaseDetails/ResourcesTable/ResourcesTable.tsx +++ b/app/react/kubernetes/helm/HelmApplicationView/ReleaseDetails/ResourcesTable/ResourcesTable.tsx @@ -59,7 +59,7 @@ export function ResourcesTable() { emptyContentLabel="No resources found" title={ - Resources reflect the latest revision only. + Only resources currently in the cluster will be displayed. } disableSelect diff --git a/app/react/kubernetes/helm/HelmApplicationView/ReleaseDetails/ResourcesTable/columns/resourceType.tsx b/app/react/kubernetes/helm/HelmApplicationView/ReleaseDetails/ResourcesTable/columns/resourceType.tsx index e1df5ffbb..aec7783d1 100644 --- a/app/react/kubernetes/helm/HelmApplicationView/ReleaseDetails/ResourcesTable/columns/resourceType.tsx +++ b/app/react/kubernetes/helm/HelmApplicationView/ReleaseDetails/ResourcesTable/columns/resourceType.tsx @@ -1,6 +1,20 @@ +import { Row } from '@tanstack/react-table'; + +import { filterHOC } from '@@/datatables/Filter'; + +import { ResourceRow } from '../types'; + import { columnHelper } from './helper'; export const resourceType = columnHelper.accessor((row) => row.resourceType, { header: 'Resource type', id: 'resourceType', + meta: { + filter: filterHOC('Filter by resource type'), + }, + enableColumnFilter: true, + filterFn: (row: Row, _: string, filterValue: string[]) => + filterValue.length === 0 || + (!!row.original.resourceType && + filterValue.includes(row.original.resourceType)), }); diff --git a/app/react/kubernetes/helm/HelmApplicationView/ReleaseDetails/ResourcesTable/columns/status.tsx b/app/react/kubernetes/helm/HelmApplicationView/ReleaseDetails/ResourcesTable/columns/status.tsx index cded59796..1e7bbb8f2 100644 --- a/app/react/kubernetes/helm/HelmApplicationView/ReleaseDetails/ResourcesTable/columns/status.tsx +++ b/app/react/kubernetes/helm/HelmApplicationView/ReleaseDetails/ResourcesTable/columns/status.tsx @@ -1,6 +1,7 @@ -import { CellContext } from '@tanstack/react-table'; +import { CellContext, Row } from '@tanstack/react-table'; import { StatusBadge } from '@@/StatusBadge'; +import { filterHOC } from '@@/datatables/Filter'; import { ResourceRow } from '../types'; @@ -10,6 +11,21 @@ export const status = columnHelper.accessor((row) => row.status.label, { header: 'Status', id: 'status', cell: Cell, + meta: { + filter: filterHOC( + 'Filter by status', + // don't include empty values in the filter options + (rows: Row[]) => + Array.from( + new Set(rows.map((row) => row.original.status.label).filter(Boolean)) + ) + ), + }, + enableColumnFilter: true, + filterFn: (row: Row, _: string, filterValue: string[]) => + filterValue.length === 0 || + (!!row.original.status.label && + filterValue.includes(row.original.status.label)), }); function Cell({ row }: CellContext) { diff --git a/app/react/kubernetes/helm/HelmApplicationView/queries/useUpdateHelmReleaseMutation.ts b/app/react/kubernetes/helm/HelmApplicationView/queries/useUpdateHelmReleaseMutation.ts index 00e9f8131..4c60faafb 100644 --- a/app/react/kubernetes/helm/HelmApplicationView/queries/useUpdateHelmReleaseMutation.ts +++ b/app/react/kubernetes/helm/HelmApplicationView/queries/useUpdateHelmReleaseMutation.ts @@ -14,6 +14,7 @@ export interface UpdateHelmReleasePayload { name: string; chart: string; version?: string; + atomic?: boolean; } export function useUpdateHelmReleaseMutation(environmentId: EnvironmentId) { const queryClient = useQueryClient(); diff --git a/pkg/libhelm/options/install_options.go b/pkg/libhelm/options/install_options.go index 0028c6c0c..807862683 100644 --- a/pkg/libhelm/options/install_options.go +++ b/pkg/libhelm/options/install_options.go @@ -11,6 +11,7 @@ type InstallOptions struct { Wait bool ValuesFile string PostRenderer string + Atomic bool Timeout time.Duration KubernetesClusterAccess *KubernetesClusterAccess diff --git a/pkg/libhelm/sdk/upgrade.go b/pkg/libhelm/sdk/upgrade.go index cf5124370..b47a439a9 100644 --- a/pkg/libhelm/sdk/upgrade.go +++ b/pkg/libhelm/sdk/upgrade.go @@ -133,7 +133,7 @@ func (hspm *HelmSDKPackageManager) Upgrade(upgradeOpts options.InstallOptions) ( func initUpgradeClient(actionConfig *action.Configuration, upgradeOpts options.InstallOptions) (*action.Upgrade, error) { upgradeClient := action.NewUpgrade(actionConfig) upgradeClient.DependencyUpdate = true - upgradeClient.Atomic = true + upgradeClient.Atomic = upgradeOpts.Atomic upgradeClient.ChartPathOptions.RepoURL = upgradeOpts.Repo upgradeClient.Wait = upgradeOpts.Wait