Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support to select chart version in the helm install form #5718

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -30,9 +30,10 @@ export type HelmInstallUpgradePageProps = RouteComponentProps<{
export type HelmInstallUpgradeFormData = {
helmReleaseName: string;
helmChartURL?: string;
chartName?: string;
chartName: string;
chartValuesYAML: string;
chartVersion?: string;
chartVersion: string;
appVersion: string;
};

const HelmInstallUpgradePage: React.FunctionComponent<HelmInstallUpgradePageProps> = ({
Expand All @@ -52,6 +53,7 @@ const HelmInstallUpgradePage: React.FunctionComponent<HelmInstallUpgradePageProp
const [chartHasValues, setChartHasValues] = React.useState<boolean>(false);
const [YAMLData, setYAMLData] = React.useState<string>('');
const [activeChartVersion, setActiveChartVersion] = React.useState<string>('');
const [appVersion, setAppVersion] = React.useState<string>('');

const helmAction: HelmActionType =
chartURL !== 'null' ? HelmActionType.Install : HelmActionType.Upgrade;
Expand All @@ -70,21 +72,15 @@ const HelmInstallUpgradePage: React.FunctionComponent<HelmInstallUpgradePageProp
res = await coFetchJSON(config.helmReleaseApi);
} catch {} // eslint-disable-line no-empty
if (ignore) return;

if (helmAction === HelmActionType.Install) {
const chartValues = getChartValuesYAML(res);
setYAMLData(chartValues);
setChartHasValues(!!chartValues);
} else {
const chart: HelmChart = res?.chart;
const releaseValues = !_.isEmpty(res?.config) ? safeDump(res?.config) : '';
const chartValues = getChartValuesYAML(chart);
const values = releaseValues || chartValues;
setYAMLData(values);
setChartHasValues(!!values);
setChartName(chart.metadata.name);
setActiveChartVersion(chart.metadata.version);
}
const chart: HelmChart = res?.chart || res;
const chartValues = getChartValuesYAML(chart);
const releaseValues = !_.isEmpty(res?.config) ? safeDump(res?.config) : '';
const values = releaseValues || chartValues;
setYAMLData(values);
setChartName(chart.metadata.name);
setActiveChartVersion(chart.metadata.version);
setAppVersion(chart.metadata.appVersion);
setChartHasValues(!!values);
setChartDataLoaded(true);
};

Expand All @@ -100,6 +96,7 @@ const HelmInstallUpgradePage: React.FunctionComponent<HelmInstallUpgradePageProp
helmChartURL: chartURL,
chartName,
chartValuesYAML: YAMLData,
appVersion,
chartVersion: activeChartVersion,
};

Expand Down Expand Up @@ -180,7 +177,7 @@ const HelmInstallUpgradePage: React.FunctionComponent<HelmInstallUpgradePageProp
<HelmInstallUpgradeForm
{...props}
chartHasValues={chartHasValues}
submitLabel={helmAction}
helmAction={helmAction}
/>
)}
</Formik>
Expand Down
Expand Up @@ -54,9 +54,13 @@ describe('Helm Releases Utils', () => {
);
});

it('should return the chart versions available for the helm chart', () => {
it('should return the chart versions, contenated with the App Version, available for the helm chart', () => {
const chartVersions = getChartVersions(mockHelmChartData);
expect(chartVersions).toEqual({ '1.0.3': '1.0.3', '1.0.2': '1.0.2', '1.0.1': '1.0.1' });
expect(chartVersions).toEqual({
'1.0.1': '1.0.1 / App Version 3.10.5',
'1.0.2': '1.0.2 / App Version 3.12',
'1.0.3': '1.0.3 / App Version 3.12',
});
});

it('should omit resources with no data and flatten them', () => {
Expand Down
Expand Up @@ -5,21 +5,64 @@ import { FormikValues, useFormikContext } from 'formik';
import { GridItem } from '@patternfly/react-core';
import { coFetchJSON, coFetch } from '@console/internal/co-fetch';
import { DropdownField } from '@console/shared';
import { HelmChartMetaData, HelmRelease, HelmChart } from '../helm-types';
import { confirmModal } from '@console/internal/components/modals/confirm-modal';
import { HelmChartMetaData, HelmRelease, HelmChart, HelmActionType } from '../helm-types';
import { getChartURL, getChartVersions, getChartValuesYAML } from '../helm-utils';

export type HelmChartVersionDropdownProps = {
chartVersion: string;
chartName: string;
helmAction: string;
};
type ModalCallback = () => void;

const HelmChartVersionDropdown: React.FunctionComponent<HelmChartVersionDropdownProps> = ({
chartVersion,
chartName,
helmAction,
}) => {
const { setFieldValue } = useFormikContext<FormikValues>();
const {
setFieldValue,
values: { chartValuesYAML, appVersion },
setFieldTouched,
} = useFormikContext<FormikValues>();
const [helmChartVersions, setHelmChartVersions] = React.useState({});
const [helmChartEntries, setHelmChartEntries] = React.useState<HelmChartMetaData[]>([]);
const [initialChartYAMLValues, setInitialChartYAMLValues] = React.useState('');

const warnOnChartVersionChange = (
onAccept: ModalCallback,
currentVersion: string,
newVersion: string,
) => {
confirmModal({
title: 'Change Chart Version?',
message: (
<>
Are you sure you want to change the chart version from <strong>{currentVersion}</strong>{' '}
to <strong>{newVersion}</strong>? <br />
You have data entered for version <strong>{currentVersion}</strong> in the YAML editor.
All data entered will be lost when changed to <strong>{newVersion}</strong>.
</>
),
submitDanger: true,
btnText: 'Yes',
cancelText: 'No',
executeFn: () => {
onAccept();
return Promise.resolve();
},
cancel: () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need to set any value on cancel?

Copy link
Contributor Author

@debsmita1 debsmita1 Jun 11, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because, when I select an option from the dropdown the chartVersion is immediately set to the selected option and then the modal opens up. Now, if I cancel the modal the chart version is not reset to the initial version, which is why I had to manually reset it by setting the chartversion value to the initial version.

setFieldValue('chartVersion', currentVersion);
setFieldTouched('chartVersion', false);
},
});
};

React.useEffect(() => {
setInitialChartYAMLValues(chartValuesYAML);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

React.useEffect(() => {
let ignore = false;
Expand All @@ -45,8 +88,6 @@ const HelmChartVersionDropdown: React.FunctionComponent<HelmChartVersionDropdown
}, [chartName]);

const onChartVersionChange = (value: string) => {
if (chartVersion === value) return;

const chartURL = getChartURL(helmChartEntries, value);

setFieldValue('chartVersion', value);
Expand All @@ -56,23 +97,40 @@ const HelmChartVersionDropdown: React.FunctionComponent<HelmChartVersionDropdown
.then((res: HelmChart) => {
const chartValues = getChartValuesYAML(res);
setFieldValue('chartValuesYAML', chartValues);
setInitialChartYAMLValues(chartValues);
})
.catch((err) => {
// eslint-disable-next-line no-console
console.error(err);
});
};

const handleChartVersionChange = (val: string) => {
if (val !== chartVersion) {
const isDirty = !_.isEqual(initialChartYAMLValues, chartValuesYAML);
if (isDirty) {
warnOnChartVersionChange(() => onChartVersionChange(val), chartVersion, val);
} else {
onChartVersionChange(val);
}
}
};

const helpText =
helmAction === HelmActionType.Install
? 'Select the Chart Version.'
: 'Select the version to upgrade to.';

return (
<GridItem span={6}>
<DropdownField
name="chartVersion"
label="Chart Version"
items={helmChartVersions}
helpText={'Select the version to upgrade to.'}
disabled={_.isEmpty(helmChartVersions)}
title={chartVersion}
onChange={onChartVersionChange}
helpText={helpText}
disabled={_.isEmpty(helmChartVersions) || _.keys(helmChartVersions).length === 1}
title={helmChartVersions[chartVersion] || `${chartVersion} / App Version ${appVersion}`}
onChange={handleChartVersionChange}
required
fullWidth
/>
Expand Down
Expand Up @@ -9,7 +9,7 @@ import HelmChartVersionDropdown from './HelmChartVersionDropdown';

export interface HelmInstallUpgradeFormProps {
chartHasValues: boolean;
submitLabel: string;
helmAction: string;
}

const HelmInstallUpgradeForm: React.FC<FormikProps<FormikValues> & HelmInstallUpgradeFormProps> = ({
Expand All @@ -19,37 +19,41 @@ const HelmInstallUpgradeForm: React.FC<FormikProps<FormikValues> & HelmInstallUp
handleReset,
status,
isSubmitting,
submitLabel,
helmAction,
values,
dirty,
}) => {
const { chartName, chartVersion } = values;
const isSubmitDisabled =
(helmAction === HelmActionType.Upgrade && !dirty) || status?.isSubmitting || !_.isEmpty(errors);
return (
<FlexForm onSubmit={handleSubmit}>
<FormSection fullWidth>
<Grid gutter={'md'}>
<GridItem span={submitLabel === HelmActionType.Install ? 12 : 6}>
<GridItem span={6}>
<InputField
type={TextInputTypes.text}
name="helmReleaseName"
label="Release Name"
helpText="A unique name for the Helm Chart release."
required
isDisabled={!!chartVersion}
isDisabled={helmAction === HelmActionType.Upgrade}
/>
</GridItem>
{chartVersion && (
<HelmChartVersionDropdown chartName={chartName} chartVersion={chartVersion} />
)}
<HelmChartVersionDropdown
chartName={chartName}
chartVersion={chartVersion}
helmAction={helmAction}
/>
</Grid>
</FormSection>
{chartHasValues && <YAMLEditorField name="chartValuesYAML" onSave={handleSubmit} />}
<FormFooter
handleReset={handleReset}
errorMessage={status && status.submitError}
isSubmitting={status?.isSubmitting || isSubmitting}
submitLabel={submitLabel}
disableSubmit={(chartVersion && !dirty) || status?.isSubmitting || !_.isEmpty(errors)}
submitLabel={helmAction}
disableSubmit={isSubmitDisabled}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The submit button is not getting disabled now while submitting the form.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

resetLabel="Cancel"
/>
</FlexForm>
Expand Down
Expand Up @@ -2,14 +2,13 @@ import * as React from 'react';
import { shallow } from 'enzyme';
import { InputField, YAMLEditorField } from '@console/shared';
import HelmInstallUpgradeForm from '../HelmInstallUpgradeForm';
import HelmChartVersionDropdown from '../HelmChartVersionDropdown';

let helmInstallUpgradeFormProps: React.ComponentProps<typeof HelmInstallUpgradeForm>;

describe('HelmInstallUpgradeForm', () => {
helmInstallUpgradeFormProps = {
chartHasValues: true,
submitLabel: 'Install',
helmAction: 'Install',
values: {
helmReleaseName: 'helm-release',
chartName: 'helm-release',
Expand Down Expand Up @@ -60,23 +59,13 @@ describe('HelmInstallUpgradeForm', () => {

let helmInstallUpgradeForm = shallow(<HelmInstallUpgradeForm {...helmInstallUpgradeFormProps} />);

it('should render only the input field component and not the dropdown field when no active version exists', () => {
expect(helmInstallUpgradeForm.find(InputField).exists()).toBe(true);
expect(helmInstallUpgradeForm.find(InputField).props().isDisabled).toBe(false);
expect(helmInstallUpgradeForm.find(HelmChartVersionDropdown).exists()).toBe(false);
});

it('should render the YAML Editor component', () => {
expect(helmInstallUpgradeForm.find(YAMLEditorField).exists()).toBe(true);
});

it('should render the Dropdown Field component when active version exists', () => {
helmInstallUpgradeFormProps.values.chartVersion = '0.1';
it('should have the Release Name field disabled in the Helm Upgrade Form', () => {
helmInstallUpgradeFormProps.helmAction = 'Upgrade';
helmInstallUpgradeForm = shallow(<HelmInstallUpgradeForm {...helmInstallUpgradeFormProps} />);
expect(helmInstallUpgradeForm.find(HelmChartVersionDropdown).exists()).toBe(true);
});

it('should have the Release Name field disabled when active version exists', () => {
expect(helmInstallUpgradeForm.find(InputField).props().label).toBe('Release Name');
expect(helmInstallUpgradeForm.find(InputField).props().isDisabled).toBe(true);
});
Expand Down
Expand Up @@ -86,7 +86,7 @@ export const getChartVersions = (chartEntries: HelmChartMetaData[]) => {
const chartVersions = _.reduce(
chartEntries,
(obj, chart) => {
obj[chart.version] = chart.version;
obj[chart.version] = `${chart.version} / App Version ${chart.appVersion}`;
return obj;
},
{},
Expand Down