mirror of
https://github.com/portainer/portainer.git
synced 2025-07-19 13:29:41 +02:00
feat(helm): helm actions [r8s-259] (#715)
Co-authored-by: James Player <james.player@portainer.io> Co-authored-by: Cara Ryan <cara.ryan@portainer.io> Co-authored-by: stevensbkang <skan070@gmail.com>
This commit is contained in:
parent
dfa32b6755
commit
4ee349bd6b
117 changed files with 4161 additions and 696 deletions
|
@ -1,31 +1,53 @@
|
|||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
|
||||
import { HelmRelease } from '../../types';
|
||||
|
||||
import { RollbackButton } from './RollbackButton';
|
||||
import { UninstallButton } from './UninstallButton';
|
||||
import { UpgradeButton } from './UpgradeButton';
|
||||
|
||||
type Props = {
|
||||
environmentId: EnvironmentId;
|
||||
releaseName: string;
|
||||
namespace: string;
|
||||
latestRevision?: number;
|
||||
earlistRevision?: number;
|
||||
selectedRevision?: number;
|
||||
release?: HelmRelease;
|
||||
updateRelease: (release: HelmRelease) => void;
|
||||
};
|
||||
|
||||
export function ChartActions({
|
||||
environmentId,
|
||||
releaseName,
|
||||
namespace,
|
||||
currentRevision,
|
||||
}: {
|
||||
environmentId: EnvironmentId;
|
||||
releaseName: string;
|
||||
namespace?: string;
|
||||
currentRevision?: number;
|
||||
}) {
|
||||
const hasPreviousRevision = currentRevision && currentRevision >= 2;
|
||||
latestRevision,
|
||||
earlistRevision,
|
||||
selectedRevision,
|
||||
release,
|
||||
updateRelease,
|
||||
}: Props) {
|
||||
const showRollbackButton =
|
||||
latestRevision && earlistRevision && latestRevision > earlistRevision;
|
||||
|
||||
return (
|
||||
<div className="inline-flex gap-x-2">
|
||||
<div className="inline-flex gap-2 flex-wrap">
|
||||
<UpgradeButton
|
||||
environmentId={environmentId}
|
||||
releaseName={releaseName}
|
||||
namespace={namespace}
|
||||
release={release}
|
||||
updateRelease={updateRelease}
|
||||
/>
|
||||
<UninstallButton
|
||||
environmentId={environmentId}
|
||||
releaseName={releaseName}
|
||||
namespace={namespace}
|
||||
/>
|
||||
{hasPreviousRevision && (
|
||||
{showRollbackButton && (
|
||||
<RollbackButton
|
||||
latestRevision={currentRevision}
|
||||
latestRevision={latestRevision}
|
||||
selectedRevision={selectedRevision}
|
||||
environmentId={environmentId}
|
||||
releaseName={releaseName}
|
||||
namespace={namespace}
|
||||
|
|
|
@ -6,6 +6,7 @@ import { vi, type Mock } from 'vitest';
|
|||
import { server } from '@/setup-tests/server';
|
||||
import { notifySuccess } from '@/portainer/services/notifications';
|
||||
import { withTestQueryProvider } from '@/react/test-utils/withTestQuery';
|
||||
import { withTestRouter } from '@/react/test-utils/withRouter';
|
||||
|
||||
import { confirm } from '@@/modals/confirm';
|
||||
|
||||
|
@ -25,13 +26,18 @@ vi.mock('@/portainer/services/notifications', () => ({
|
|||
function renderButton(props = {}) {
|
||||
const defaultProps = {
|
||||
latestRevision: 3, // So we're rolling back to revision 2
|
||||
selectedRevision: 3, // This simulates the selectedRevision from URL params
|
||||
environmentId: 1,
|
||||
releaseName: 'test-release',
|
||||
namespace: 'default',
|
||||
...props,
|
||||
};
|
||||
|
||||
const Wrapped = withTestQueryProvider(RollbackButton);
|
||||
const Wrapped = withTestQueryProvider(
|
||||
withTestRouter(RollbackButton, {
|
||||
route: '/?revision=3',
|
||||
})
|
||||
);
|
||||
return render(<Wrapped {...defaultProps} />);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { RotateCcw } from 'lucide-react';
|
||||
import { useRouter } from '@uirouter/react';
|
||||
|
||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
import { notifySuccess } from '@/portainer/services/notifications';
|
||||
|
@ -12,6 +13,7 @@ import { useHelmRollbackMutation } from '../queries/useHelmRollbackMutation';
|
|||
|
||||
type Props = {
|
||||
latestRevision: number;
|
||||
selectedRevision?: number;
|
||||
environmentId: EnvironmentId;
|
||||
releaseName: string;
|
||||
namespace?: string;
|
||||
|
@ -19,13 +21,16 @@ type Props = {
|
|||
|
||||
export function RollbackButton({
|
||||
latestRevision,
|
||||
selectedRevision,
|
||||
environmentId,
|
||||
releaseName,
|
||||
namespace,
|
||||
}: Props) {
|
||||
// the selectedRevision can be a prop when selecting a revision is implemented
|
||||
const selectedRevision = latestRevision ? latestRevision - 1 : undefined;
|
||||
|
||||
// when the latest revision is selected, rollback to the previous revision
|
||||
// otherwise, rollback to the selected revision
|
||||
const rollbackRevision =
|
||||
selectedRevision === latestRevision ? latestRevision - 1 : selectedRevision;
|
||||
const router = useRouter();
|
||||
const rollbackMutation = useHelmRollbackMutation(environmentId);
|
||||
|
||||
return (
|
||||
|
@ -38,7 +43,7 @@ export function RollbackButton({
|
|||
color="default"
|
||||
size="medium"
|
||||
>
|
||||
Rollback to #{selectedRevision}
|
||||
Rollback to #{rollbackRevision}
|
||||
</LoadingButton>
|
||||
);
|
||||
|
||||
|
@ -47,7 +52,7 @@ export function RollbackButton({
|
|||
title: 'Are you sure?',
|
||||
modalType: ModalType.Warn,
|
||||
confirmButton: buildConfirmButton('Rollback'),
|
||||
message: `Rolling back will restore the application to revision #${selectedRevision}, which will cause service interruption. Do you wish to continue?`,
|
||||
message: `Rolling back will restore the application to revision #${rollbackRevision}, which could cause service interruption. Do you wish to continue?`,
|
||||
});
|
||||
if (!confirmed) {
|
||||
return;
|
||||
|
@ -56,14 +61,20 @@ export function RollbackButton({
|
|||
rollbackMutation.mutate(
|
||||
{
|
||||
releaseName,
|
||||
params: { namespace, revision: selectedRevision },
|
||||
params: { namespace, revision: rollbackRevision },
|
||||
},
|
||||
{
|
||||
onSuccess: () => {
|
||||
notifySuccess(
|
||||
'Success',
|
||||
`Application rolled back to revision #${selectedRevision} successfully.`
|
||||
`Application rolled back to revision #${rollbackRevision} successfully.`
|
||||
);
|
||||
// set the revision url param to undefined to refresh the page at the latest revision
|
||||
router.stateService.go('kubernetes.helm', {
|
||||
namespace,
|
||||
name: releaseName,
|
||||
revision: undefined,
|
||||
});
|
||||
},
|
||||
}
|
||||
);
|
||||
|
|
|
@ -0,0 +1,182 @@
|
|||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { vi } from 'vitest';
|
||||
|
||||
import { withTestQueryProvider } from '@/react/test-utils/withTestQuery';
|
||||
import { withTestRouter } from '@/react/test-utils/withRouter';
|
||||
|
||||
import {
|
||||
useHelmRepoVersions,
|
||||
ChartVersion,
|
||||
} from '../queries/useHelmRepositories';
|
||||
import { HelmRelease } from '../../types';
|
||||
|
||||
import { openUpgradeHelmModal } from './UpgradeHelmModal';
|
||||
import { UpgradeButton } from './UpgradeButton';
|
||||
|
||||
// Mock the upgrade modal function
|
||||
vi.mock('./UpgradeHelmModal', () => ({
|
||||
openUpgradeHelmModal: vi.fn(() => Promise.resolve(undefined)),
|
||||
}));
|
||||
|
||||
// Mock the notifications service
|
||||
vi.mock('@/portainer/services/notifications', () => ({
|
||||
notifySuccess: vi.fn(),
|
||||
}));
|
||||
|
||||
// Mock the useHelmRepoVersions and useHelmRepositories hooks
|
||||
vi.mock('../queries/useHelmRepositories', () => ({
|
||||
useHelmRepoVersions: vi.fn(() => ({
|
||||
data: [
|
||||
{ Version: '1.0.0', Repo: 'stable' },
|
||||
{ Version: '1.1.0', Repo: 'stable' },
|
||||
],
|
||||
isInitialLoading: false,
|
||||
isError: false,
|
||||
})),
|
||||
useHelmRepositories: vi.fn(() => ({
|
||||
data: ['repo1', 'repo2'],
|
||||
isInitialLoading: false,
|
||||
isError: false,
|
||||
})),
|
||||
}));
|
||||
|
||||
function renderButton(props = {}) {
|
||||
const defaultProps = {
|
||||
environmentId: 1,
|
||||
releaseName: 'test-release',
|
||||
namespace: 'default',
|
||||
release: {
|
||||
name: 'test-release',
|
||||
chart: {
|
||||
metadata: {
|
||||
name: 'test-chart',
|
||||
version: '1.0.0',
|
||||
},
|
||||
},
|
||||
values: {
|
||||
userSuppliedValues: '{}',
|
||||
},
|
||||
manifest: '',
|
||||
} as HelmRelease,
|
||||
updateRelease: vi.fn(),
|
||||
...props,
|
||||
};
|
||||
|
||||
const Wrapped = withTestQueryProvider(withTestRouter(UpgradeButton));
|
||||
return render(<Wrapped {...defaultProps} />);
|
||||
}
|
||||
|
||||
describe('UpgradeButton', () => {
|
||||
test('should display the upgrade button', () => {
|
||||
renderButton();
|
||||
|
||||
const button = screen.getByRole('button', { name: /Upgrade/i });
|
||||
expect(button).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('should be disabled when no versions are available', () => {
|
||||
const data: ChartVersion[] = [];
|
||||
vi.mocked(useHelmRepoVersions).mockReturnValue({
|
||||
data,
|
||||
isInitialLoading: false,
|
||||
isError: false,
|
||||
});
|
||||
|
||||
renderButton();
|
||||
|
||||
const button = screen.getByRole('button', { name: /Upgrade/i });
|
||||
expect(button).toBeDisabled();
|
||||
});
|
||||
|
||||
test('should show loading state when checking for versions', () => {
|
||||
vi.mocked(useHelmRepoVersions).mockReturnValue({
|
||||
data: [],
|
||||
isInitialLoading: true,
|
||||
isError: false,
|
||||
});
|
||||
|
||||
renderButton();
|
||||
|
||||
expect(
|
||||
screen.getByText('Checking for new versions...')
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('should show "No versions available" when no versions are found', () => {
|
||||
const data: ChartVersion[] = [];
|
||||
vi.mocked(useHelmRepoVersions).mockReturnValue({
|
||||
data,
|
||||
isInitialLoading: false,
|
||||
isError: false,
|
||||
});
|
||||
|
||||
renderButton();
|
||||
|
||||
expect(screen.getByText('No versions available')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('should open upgrade modal when clicked', async () => {
|
||||
const user = userEvent.setup();
|
||||
const mockRelease = {
|
||||
name: 'test-release',
|
||||
chart: {
|
||||
metadata: {
|
||||
name: 'test-chart',
|
||||
version: '1.0.0',
|
||||
},
|
||||
},
|
||||
values: {
|
||||
userSuppliedValues: '{}',
|
||||
},
|
||||
manifest: '',
|
||||
} as HelmRelease;
|
||||
|
||||
vi.mocked(useHelmRepoVersions).mockReturnValue({
|
||||
data: [
|
||||
{ Version: '1.0.0', Repo: 'stable' },
|
||||
{ Version: '1.1.0', Repo: 'stable' },
|
||||
],
|
||||
isInitialLoading: false,
|
||||
isError: false,
|
||||
});
|
||||
|
||||
renderButton({ release: mockRelease });
|
||||
|
||||
const button = screen.getByRole('button', { name: /Upgrade/i });
|
||||
await user.click(button);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(openUpgradeHelmModal).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
name: 'test-release',
|
||||
chart: 'test-chart',
|
||||
namespace: 'default',
|
||||
values: '{}',
|
||||
version: '1.0.0',
|
||||
}),
|
||||
expect.arrayContaining([
|
||||
{ Version: '1.0.0', Repo: 'stable' },
|
||||
{ Version: '1.1.0', Repo: 'stable' },
|
||||
])
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test('should not execute the upgrade if modal is cancelled', async () => {
|
||||
const mockUpdateRelease = vi.fn();
|
||||
vi.mocked(openUpgradeHelmModal).mockResolvedValueOnce(undefined);
|
||||
|
||||
const user = userEvent.setup();
|
||||
renderButton({ updateRelease: mockUpdateRelease });
|
||||
|
||||
const button = screen.getByRole('button', { name: /Upgrade/i });
|
||||
await user.click(button);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(openUpgradeHelmModal).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
expect(mockUpdateRelease).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,167 @@
|
|||
import { ArrowUp } from 'lucide-react';
|
||||
import { useRouter } from '@uirouter/react';
|
||||
|
||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
import { notifySuccess } from '@/portainer/services/notifications';
|
||||
import { semverCompare } from '@/react/common/semver-utils';
|
||||
|
||||
import { LoadingButton } from '@@/buttons';
|
||||
import { InlineLoader } from '@@/InlineLoader';
|
||||
import { Tooltip } from '@@/Tip/Tooltip';
|
||||
import { Link } from '@@/Link';
|
||||
|
||||
import { HelmRelease } from '../../types';
|
||||
import {
|
||||
useUpdateHelmReleaseMutation,
|
||||
UpdateHelmReleasePayload,
|
||||
} from '../queries/useUpdateHelmReleaseMutation';
|
||||
import {
|
||||
ChartVersion,
|
||||
useHelmRepoVersions,
|
||||
useHelmRepositories,
|
||||
} from '../queries/useHelmRepositories';
|
||||
import { useHelmRelease } from '../queries/useHelmRelease';
|
||||
|
||||
import { openUpgradeHelmModal } from './UpgradeHelmModal';
|
||||
|
||||
export function UpgradeButton({
|
||||
environmentId,
|
||||
releaseName,
|
||||
namespace,
|
||||
release,
|
||||
updateRelease,
|
||||
}: {
|
||||
environmentId: EnvironmentId;
|
||||
releaseName: string;
|
||||
namespace: string;
|
||||
release?: HelmRelease;
|
||||
updateRelease: (release: HelmRelease) => void;
|
||||
}) {
|
||||
const router = useRouter();
|
||||
const updateHelmReleaseMutation = useUpdateHelmReleaseMutation(environmentId);
|
||||
|
||||
const repositoriesQuery = useHelmRepositories();
|
||||
const helmRepoVersionsQuery = useHelmRepoVersions(
|
||||
release?.chart.metadata?.name || '',
|
||||
60 * 60 * 1000, // 1 hour
|
||||
repositoriesQuery.data
|
||||
);
|
||||
const versions = helmRepoVersionsQuery.data;
|
||||
|
||||
// Combined loading state
|
||||
const isInitialLoading =
|
||||
repositoriesQuery.isInitialLoading ||
|
||||
helmRepoVersionsQuery.isInitialLoading;
|
||||
const isError = repositoriesQuery.isError || helmRepoVersionsQuery.isError;
|
||||
|
||||
const latestVersion = useHelmRelease(environmentId, releaseName, namespace, {
|
||||
select: (data) => data.chart.metadata?.version,
|
||||
});
|
||||
const latestVersionAvailable = versions[0]?.Version ?? '';
|
||||
const isNewVersionAvailable =
|
||||
latestVersion?.data &&
|
||||
semverCompare(latestVersionAvailable, latestVersion?.data) === 1;
|
||||
|
||||
const editableHelmRelease: UpdateHelmReleasePayload = {
|
||||
name: releaseName,
|
||||
namespace: namespace || '',
|
||||
values: release?.values?.userSuppliedValues,
|
||||
chart: release?.chart.metadata?.name || '',
|
||||
version: release?.chart.metadata?.version,
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<LoadingButton
|
||||
color="secondary"
|
||||
data-cy="k8sApp-upgradeHelmChartButton"
|
||||
onClick={() => openUpgradeForm(versions, release)}
|
||||
disabled={
|
||||
versions.length === 0 ||
|
||||
isInitialLoading ||
|
||||
isError ||
|
||||
release?.info?.status?.startsWith('pending')
|
||||
}
|
||||
loadingText="Upgrading..."
|
||||
isLoading={updateHelmReleaseMutation.isLoading}
|
||||
icon={ArrowUp}
|
||||
size="medium"
|
||||
>
|
||||
Upgrade
|
||||
</LoadingButton>
|
||||
{versions.length === 0 && isInitialLoading && (
|
||||
<InlineLoader
|
||||
size="xs"
|
||||
className="absolute -bottom-5 left-0 right-0 whitespace-nowrap"
|
||||
>
|
||||
Checking for new versions...
|
||||
</InlineLoader>
|
||||
)}
|
||||
{versions.length === 0 && !isInitialLoading && !isError && (
|
||||
<span className="absolute flex items-center -bottom-5 left-0 right-0 text-xs text-muted text-center whitespace-nowrap">
|
||||
No versions available
|
||||
<Tooltip
|
||||
message={
|
||||
<div>
|
||||
Portainer is unable to find any versions for this chart in the
|
||||
repositories saved. Try adding a new repository which contains
|
||||
the chart in the{' '}
|
||||
<Link
|
||||
to="portainer.account"
|
||||
params={{ '#': 'helm-repositories' }}
|
||||
data-cy="user-settings-link"
|
||||
>
|
||||
Helm repositories settings
|
||||
</Link>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</span>
|
||||
)}
|
||||
{isNewVersionAvailable && (
|
||||
<span className="absolute -bottom-5 left-0 right-0 text-xs text-muted text-center whitespace-nowrap">
|
||||
New version available ({latestVersionAvailable})
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
async function openUpgradeForm(
|
||||
versions: ChartVersion[],
|
||||
release?: HelmRelease
|
||||
) {
|
||||
const result = await openUpgradeHelmModal(editableHelmRelease, versions);
|
||||
|
||||
if (result) {
|
||||
handleUpgrade(result, release);
|
||||
}
|
||||
}
|
||||
|
||||
function handleUpgrade(
|
||||
payload: UpdateHelmReleasePayload,
|
||||
release?: HelmRelease
|
||||
) {
|
||||
if (release?.info) {
|
||||
const updatedRelease = {
|
||||
...release,
|
||||
info: {
|
||||
...release.info,
|
||||
status: 'pending-upgrade',
|
||||
description: 'Preparing upgrade',
|
||||
},
|
||||
};
|
||||
updateRelease(updatedRelease);
|
||||
}
|
||||
updateHelmReleaseMutation.mutate(payload, {
|
||||
onSuccess: () => {
|
||||
notifySuccess('Success', 'Helm chart upgraded successfully');
|
||||
// set the revision url param to undefined to refresh the page at the latest revision
|
||||
router.stateService.go('kubernetes.helm', {
|
||||
namespace,
|
||||
name: releaseName,
|
||||
revision: undefined,
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
import { useState } from 'react';
|
||||
import { ArrowUp } from 'lucide-react';
|
||||
|
||||
import { withReactQuery } from '@/react-tools/withReactQuery';
|
||||
import { withCurrentUser } from '@/react-tools/withCurrentUser';
|
||||
|
||||
import { Modal, OnSubmit, openModal } from '@@/modals';
|
||||
import { Button } from '@@/buttons';
|
||||
import { Option, PortainerSelect } from '@@/form-components/PortainerSelect';
|
||||
import { Input } from '@@/form-components/Input';
|
||||
import { CodeEditor } from '@@/CodeEditor';
|
||||
import { FormControl } from '@@/form-components/FormControl';
|
||||
import { WidgetTitle } from '@@/Widget';
|
||||
|
||||
import { UpdateHelmReleasePayload } from '../queries/useUpdateHelmReleaseMutation';
|
||||
import { ChartVersion } from '../queries/useHelmRepositories';
|
||||
|
||||
interface Props {
|
||||
onSubmit: OnSubmit<UpdateHelmReleasePayload>;
|
||||
values: UpdateHelmReleasePayload;
|
||||
versions: ChartVersion[];
|
||||
}
|
||||
|
||||
export function UpgradeHelmModal({ values, versions, onSubmit }: Props) {
|
||||
const versionOptions: Option<ChartVersion>[] = versions.map((version) => {
|
||||
const isCurrentVersion = version.Version === values.version;
|
||||
const label = `${version.Repo}@${version.Version}${
|
||||
isCurrentVersion ? ' (current)' : ''
|
||||
}`;
|
||||
return {
|
||||
label,
|
||||
value: version,
|
||||
};
|
||||
});
|
||||
const defaultVersion =
|
||||
versionOptions.find((v) => v.value.Version === values.version)?.value ||
|
||||
versionOptions[0]?.value;
|
||||
const [version, setVersion] = useState<ChartVersion>(defaultVersion);
|
||||
const [userValues, setUserValues] = useState<string>(values.values || '');
|
||||
|
||||
return (
|
||||
<Modal
|
||||
onDismiss={() => onSubmit()}
|
||||
size="lg"
|
||||
className="flex flex-col h-[80vh] px-0"
|
||||
aria-label="upgrade-helm"
|
||||
>
|
||||
<Modal.Header
|
||||
title={<WidgetTitle className="px-5" title="Upgrade" icon={ArrowUp} />}
|
||||
/>
|
||||
<div className="flex-1 overflow-y-auto px-5">
|
||||
<Modal.Body>
|
||||
<FormControl label="Version" inputId="version-input" size="vertical">
|
||||
<PortainerSelect<ChartVersion>
|
||||
value={version}
|
||||
options={versionOptions}
|
||||
onChange={(version) => {
|
||||
if (version) {
|
||||
setVersion(version);
|
||||
}
|
||||
}}
|
||||
data-cy="helm-version-input"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl
|
||||
label="Release name"
|
||||
inputId="release-name-input"
|
||||
size="vertical"
|
||||
>
|
||||
<Input
|
||||
id="release-name-input"
|
||||
value={values.name}
|
||||
readOnly
|
||||
disabled
|
||||
data-cy="helm-release-name-input"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl
|
||||
label="Namespace"
|
||||
inputId="namespace-input"
|
||||
size="vertical"
|
||||
>
|
||||
<Input
|
||||
id="namespace-input"
|
||||
value={values.namespace}
|
||||
readOnly
|
||||
disabled
|
||||
data-cy="helm-namespace-input"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl
|
||||
label="User-defined values"
|
||||
inputId="user-values-editor"
|
||||
size="vertical"
|
||||
>
|
||||
<CodeEditor
|
||||
id="user-values-editor"
|
||||
value={userValues}
|
||||
onChange={(value) => setUserValues(value)}
|
||||
height="50vh"
|
||||
type="yaml"
|
||||
data-cy="helm-user-values-editor"
|
||||
placeholder="Define or paste the content of your values yaml file here"
|
||||
/>
|
||||
</FormControl>
|
||||
</Modal.Body>
|
||||
</div>
|
||||
<div className="px-5 border-solid border-0 border-t border-gray-5 th-dark:border-gray-7 th-highcontrast:border-white">
|
||||
<Modal.Footer>
|
||||
<Button
|
||||
onClick={() => onSubmit()}
|
||||
color="secondary"
|
||||
key="cancel-button"
|
||||
size="medium"
|
||||
data-cy="cancel-button-cy"
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() =>
|
||||
onSubmit({
|
||||
name: values.name,
|
||||
values: userValues,
|
||||
namespace: values.namespace,
|
||||
chart: values.chart,
|
||||
repo: version.Repo,
|
||||
version: version.Version,
|
||||
})
|
||||
}
|
||||
color="primary"
|
||||
key="update-button"
|
||||
size="medium"
|
||||
data-cy="update-button-cy"
|
||||
>
|
||||
Upgrade
|
||||
</Button>
|
||||
</Modal.Footer>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export async function openUpgradeHelmModal(
|
||||
values: UpdateHelmReleasePayload,
|
||||
versions: ChartVersion[]
|
||||
) {
|
||||
return openModal(withReactQuery(withCurrentUser(UpgradeHelmModal)), {
|
||||
values,
|
||||
versions,
|
||||
});
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue