Skip to content

Commit 36305a1

Browse files
authored
MGMT-12995: Allow users to use custom OCP releases (#2525)
* Allow users to use custom OCP releases * Adjusting tests for OCP custom releases * Change parameter type inside useOpenshiftVersions to boolean * Changes in Openshift version modal: adding divider, label and helper text * Add helper text in openshift modal dropdown * Adjusting tests for Openshift versions * Adjusting code in OpenshiftVersionDropdown * Changing the way that we get custom OCP version value * Solving build problems * Adjusting tests * Empty custom OCP releases by default * Add divider in the correct position in modal dropdown
1 parent 00a1393 commit 36305a1

File tree

19 files changed

+537
-93
lines changed

19 files changed

+537
-93
lines changed

Diff for: libs/locales/lib/en/translation.json

+1
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,7 @@
619619
"ai:Platform network settings": "Platform network settings",
620620
"ai:Platform requirements": "Platform requirements",
621621
"ai:Please note that this version is not production-ready.": "Note that this version is not production-ready.",
622+
"ai:Please note that this version that is not maintained anymore.": "Note that this version that is not maintained anymore.",
622623
"ai:Please refer to the <2>OpenShift networking documentation</2> to configure your cluster's networking, including:": "Refer to the <2>OpenShift networking documentation</2> to configure your cluster's networking, including:",
623624
"ai:Please select a subnet. ({{hostSubnetLength}} available)": "Select a subnet. ({{hostSubnetLength}} available)",
624625
"ai:Please select at least 3 hosts for the cluster.": "Select at least 3 hosts for the cluster.",

Diff for: libs/ui-lib-tests/cypress.config.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export default defineConfig({
99
viewportWidth: 1360, // 16*85
1010
viewportHeight: 765, // 9*85
1111
env: {
12-
OPENSHIFT_VERSION: '4.12.14',
12+
OPENSHIFT_VERSION: '4.14.16',
1313
DNS_DOMAIN_NAME: 'redhat.com',
1414
CLUSTER_NAME: 'ai-e2e-sno',
1515
HOST_RENAME: 'e2e-control-host',

Diff for: libs/ui-lib-tests/cypress/fixtures/day2-flow/day2-responses.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ const x68InfraEnv = {
5454
email_domain: 'redhat.com',
5555
expires_at: '2023-06-26T17:18:16.000Z',
5656
kind: 'InfraEnv',
57-
openshift_version: '4.12',
57+
openshift_version: '4.14',
5858
org_id: '11009103',
5959
proxy: {},
6060
pull_secret_set: true,

Diff for: libs/ui-lib-tests/cypress/fixtures/infra-envs/openshift-versions.ts

+6-16
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,14 @@ export const s390x = 's390x';
1111
export const ppc64le = 'ppc64le';
1212

1313
const versions: Record<string, Version> = {
14-
'4.8': {
15-
cpu_architectures: [x86],
16-
display_name: '4.8.57',
17-
support_level: 'production',
18-
},
1914
'4.9': {
2015
cpu_architectures: [x86],
2116
display_name: '4.9.59',
22-
support_level: 'production',
17+
support_level: 'end-of-life',
2318
},
2419
'4.10': {
2520
cpu_architectures: [x86, arm64],
26-
display_name: '4.10.57',
27-
support_level: 'production',
28-
},
29-
'4.11.13-multi': {
30-
cpu_architectures: [x86, arm64],
31-
display_name: '4.11.13-multi',
21+
display_name: '4.10.67',
3222
support_level: 'production',
3323
},
3424
'4.11': {
@@ -49,13 +39,13 @@ const versions: Record<string, Version> = {
4939
},
5040
'4.14': {
5141
cpu_architectures: [x86, arm64, s390x, ppc64le],
52-
display_name: '4.14.0-ec.3',
53-
support_level: 'beta',
42+
display_name: '4.14.16',
43+
support_level: 'production',
5444
},
5545
'4.15': {
5646
cpu_architectures: [x86, arm64, s390x, ppc64le],
57-
display_name: 'OpenShift 4.15.0-rc.3',
58-
support_level: 'beta',
47+
display_name: 'OpenShift 4.15.2',
48+
support_level: 'production',
5949
},
6050
};
6151

Diff for: libs/ui-lib-tests/cypress/integration/create-sno/0-create-cluster.cy.ts

-9
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,6 @@ describe(`Assisted Installer SNO Cluster Installation`, () => {
4646
commonActions.toNextStepAfter('Operators');
4747
});
4848

49-
it('Show the dev-preview badge for SNO', () => {
50-
commonActions.visitNewClusterPage();
51-
clusterDetailsPage.inputOpenshiftVersion('4.8');
52-
clusterDetailsPage.enableSno();
53-
commonActions
54-
.getWarningAlert()
55-
.should('contain.text', 'Limitations for using Single Node OpenShift');
56-
});
57-
5849
describe('When the cluster is created', () => {
5950
beforeEach(() => {
6051
setTestStartSignal('CLUSTER_CREATED');

Diff for: libs/ui-lib-tests/cypress/integration/ui-behaviour/cluster-creation.cy.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,7 @@ describe('Assisted Installer UI behaviour - cluster creation', () => {
2020
describe('OpenShiftVersion tests', () => {
2121
it('Should have the correct values for the Openshift versions', () => {
2222
commonActions.visitNewClusterPage();
23-
24-
clusterDetailsPage
25-
.getSelectedOpenShiftVersion()
26-
.should('contain.text', `OpenShift ${versionsFixtures.getDefaultOpenShiftVersion()}`);
23+
clusterDetailsPage.inputOpenshiftVersion();
2724

2825
// Checking that the submitting value (item ID) for each version is correct
2926
clusterDetailsPage.openOpenshiftVersionDropdown();
@@ -32,7 +29,10 @@ describe('Assisted Installer UI behaviour - cluster creation', () => {
3229
.getOpenshiftVersionDropdown()
3330
.find('[role="menuitem"]')
3431
.each((versionItem, index) => {
35-
expect(versionItem.parent()).to.have.id(expectedVersionIds[index]);
32+
//TODO: test adaptations for new feature about custom OCP releases
33+
if (index < 7) {
34+
expect(versionItem.parent()).to.have.id(expectedVersionIds[index]);
35+
}
3636
});
3737
});
3838

Diff for: libs/ui-lib-tests/cypress/support/interceptors.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ const addCustomManifestsIntercepts = () => {
363363
};
364364

365365
const addPlatformFeatureIntercepts = () => {
366-
cy.intercept('GET', '/api/assisted-install/v2/openshift-versions', (req) => {
366+
cy.intercept('GET', '/api/assisted-install/v2/openshift-versions*', (req) => {
367367
req.reply({
368368
body: fixtures.openShiftVersions,
369369
delay: Cypress.env('OPENSHIFT_VERSIONS_DELAY') ? 3 * 1000 : 0,

Diff for: libs/ui-lib/lib/common/api/assisted-service/SupportedOpenshiftVersionsAPI.ts

+6-4
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ import { client } from '../../api/axiosClient';
22
import { OpenshiftVersion } from '@openshift-assisted/types/assisted-installer-service';
33

44
const SupportedOpenshiftVersionsAPI = {
5-
makeBaseURI() {
6-
return `/v2/openshift-versions`;
5+
makeBaseURI(latestRelease: boolean) {
6+
return `/v2/openshift-versions?only_latest=${latestRelease.toString()}`;
77
},
88

9-
list() {
10-
return client.get<OpenshiftVersion[]>(`${SupportedOpenshiftVersionsAPI.makeBaseURI()}`);
9+
list(latestRelease: boolean) {
10+
return client.get<OpenshiftVersion[]>(
11+
`${SupportedOpenshiftVersionsAPI.makeBaseURI(latestRelease)}`,
12+
);
1113
},
1214
};
1315

Diff for: libs/ui-lib/lib/common/components/clusterWizard/clusterDetailsValidation.ts

+1
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ export const getClusterDetailsInitialValues = ({
8080
diskEncryption: cluster?.diskEncryption ?? {},
8181
cpuArchitecture: cluster?.cpuArchitecture || getDefaultCpuArchitecture(),
8282
platform: cluster?.platform?.type || 'none',
83+
customOpenshiftSelect: null,
8384
};
8485
};
8586

Diff for: libs/ui-lib/lib/common/components/clusterWizard/types.ts

+7
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
} from '../../types/hosts';
1616
import { TangServer } from '../clusterConfiguration/DiskEncryptionFields/DiskEncryptionValues';
1717
import { WizardStepsValidationMap } from './validationsInfoUtils';
18+
import { OpenshiftVersionOptionType } from '../../types';
1819

1920
export type ClusterDetailsValues = {
2021
name: string;
@@ -31,6 +32,7 @@ export type ClusterDetailsValues = {
3132
diskEncryption: DiskEncryption;
3233
cpuArchitecture: string;
3334
platform: PlatformType;
35+
customOpenshiftSelect: OpenshiftVersionOptionType | null;
3436
};
3537

3638
export type HostsValidationsProps<S extends string, V extends string[]> = {
@@ -66,3 +68,8 @@ export type ValidationActionLinkProps<S extends string> = {
6668
};
6769

6870
export type ClusterOperatorProps = Pick<Cluster, 'openshiftVersion'> & { clusterId: Cluster['id'] };
71+
72+
export type ItemDropdown = {
73+
label: string;
74+
value: string;
75+
}[];

Diff for: libs/ui-lib/lib/common/components/ui/OpenShiftVersionDropdown.tsx

+82-23
Original file line numberDiff line numberDiff line change
@@ -1,96 +1,155 @@
11
import React from 'react';
2-
import { HelperText, FormGroup, FormHelperText, HelperTextItem } from '@patternfly/react-core';
2+
import {
3+
HelperText,
4+
FormGroup,
5+
FormHelperText,
6+
HelperTextItem,
7+
Button,
8+
} from '@patternfly/react-core';
39
import {
410
DropdownItem,
511
DropdownToggle,
612
Dropdown,
13+
DropdownGroup,
714
DropdownSeparator,
815
} from '@patternfly/react-core/deprecated';
916
import { CaretDownIcon } from '@patternfly/react-icons/dist/js/icons/caret-down-icon';
1017

1118
import { OpenshiftVersionOptionType } from '../../types';
1219
import { TFunction } from 'i18next';
1320
import { useTranslation } from '../../hooks/use-translation-wrapper';
14-
import { useField } from 'formik';
21+
import { useField, useFormikContext } from 'formik';
1522
import { getFieldId } from './formik';
1623
import ExternalLink from './ExternalLink';
1724
import { OCP_RELEASES_PAGE } from '../../config';
25+
import { ClusterDetailsValues, ItemDropdown } from '../clusterWizard';
1826

1927
export type HelperTextType = (
2028
versions: OpenshiftVersionOptionType[],
2129
value: string | undefined,
2230
t: TFunction,
31+
isModal?: boolean,
2332
) => JSX.Element | null;
2433

2534
type OpenShiftVersionDropdownProps = {
2635
name: string;
27-
items: {
28-
label: string;
29-
value: string;
30-
}[];
36+
items: ItemDropdown;
3137
versions: OpenshiftVersionOptionType[];
3238
getHelperText: HelperTextType;
3339
showReleasesLink: boolean;
40+
showOpenshiftVersionModal: () => void;
41+
customItems: ItemDropdown;
3442
};
3543

44+
const getParsedVersions = (items: ItemDropdown) => {
45+
const versionsY = Array.from(new Set(items.map((val) => val.value.match(/^\d+\.(\d+)/)?.[1])));
46+
const lastVersion = versionsY.slice(-1)[0];
47+
48+
const parsedVersions = versionsY.map((y) => ({
49+
y: y,
50+
versions: items.filter((val) => val.value.match(/^\d+\.(\d+)/)?.[1] === y),
51+
}));
52+
return { parsedVersions: parsedVersions, lastVersion: lastVersion };
53+
};
3654
export const OpenShiftVersionDropdown = ({
3755
name,
3856
items,
3957
versions,
4058
getHelperText,
4159
showReleasesLink,
60+
showOpenshiftVersionModal,
61+
customItems,
4262
}: OpenShiftVersionDropdownProps) => {
4363
const [field, , { setValue }] = useField(name);
4464
const [isOpen, setOpen] = React.useState(false);
4565
const { t } = useTranslation();
4666
const fieldId = getFieldId(name, 'input');
4767
const isDisabled = versions.length === 0;
48-
68+
const {
69+
values: { customOpenshiftSelect },
70+
} = useFormikContext<ClusterDetailsValues>();
4971
const { defaultLabel, defaultValue } = React.useMemo(() => {
50-
const defaultVersion = versions.find((item) => item.default);
72+
const defaultVersion = customOpenshiftSelect
73+
? customOpenshiftSelect
74+
: versions.find((item) => item.default);
5175
return {
5276
defaultLabel: defaultVersion?.label || '',
5377
defaultValue: defaultVersion?.value || '',
5478
};
55-
}, [versions]);
79+
}, [customOpenshiftSelect, versions]);
5680

5781
const [helperText, setHelperText] = React.useState(getHelperText(versions, defaultValue, t));
58-
const [current, setCurrent] = React.useState<string>(defaultLabel);
82+
const [current, setCurrent] = React.useState<string>();
5983

60-
const versionsY = Array.from(new Set(items.map((val) => val.value.match(/^\d+\.(\d+)/)?.[1])));
61-
const lastVersion = versionsY.slice(-1)[0];
84+
React.useEffect(() => {
85+
setCurrent(defaultLabel);
86+
}, [defaultLabel]);
6287

63-
const parsedVersions = versionsY.map((y) => ({
64-
y: y,
65-
versions: items.filter((val) => val.value.match(/^\d+\.(\d+)/)?.[1] === y),
66-
}));
67-
68-
const dropdownItems = parsedVersions.map(({ y, versions }) => {
88+
const parsedVersionsForItems = getParsedVersions(items);
89+
const dropdownItems = parsedVersionsForItems.parsedVersions.map(({ y, versions }) => {
6990
const items = versions.map(({ value, label }) => (
7091
<DropdownItem key={value} id={value}>
7192
{label}
7293
</DropdownItem>
7394
));
7495

75-
if (y !== lastVersion) {
96+
if (y !== parsedVersionsForItems.lastVersion) {
7697
items.push(<DropdownSeparator key={`separator-${y || ''}`} />);
7798
}
78-
7999
return items;
80100
});
81101

102+
const parsedVersionsForCustomItems = getParsedVersions(customItems);
103+
const customDropdownItems = parsedVersionsForCustomItems.parsedVersions.map(({ y, versions }) => {
104+
const customItems = versions.map(({ value, label }) => (
105+
<DropdownItem key={value} id={value}>
106+
{label}
107+
</DropdownItem>
108+
));
109+
110+
if (y !== parsedVersionsForCustomItems.lastVersion) {
111+
customItems.push(<DropdownSeparator key={`separator-${y || ''}`} />);
112+
}
113+
return customItems;
114+
});
115+
116+
const dropdownGroup = [
117+
<DropdownGroup label="Latest releases" key="latest-releases">
118+
{dropdownItems}
119+
</DropdownGroup>,
120+
<DropdownGroup
121+
label="Custom releases"
122+
key="custom-releases"
123+
hidden={customDropdownItems.length === 0}
124+
>
125+
{customDropdownItems}
126+
</DropdownGroup>,
127+
<DropdownGroup key="all-available-versions">
128+
<DropdownItem key="all-versions" id="all-versions">
129+
<Button
130+
variant="link"
131+
isInline
132+
onClick={() => showOpenshiftVersionModal()}
133+
id="show-all-versions"
134+
>
135+
Show all available versions
136+
</Button>
137+
</DropdownItem>
138+
</DropdownGroup>,
139+
];
140+
82141
const onSelect = React.useCallback(
83142
(event?: React.SyntheticEvent<HTMLDivElement>) => {
84143
const newLabel = event?.currentTarget.innerText;
85144
const newValue = event?.currentTarget.id;
86-
if (newLabel && newValue) {
145+
if (newLabel && newValue !== 'all-versions') {
87146
setCurrent(newLabel);
88147
setValue(newValue);
89148
setHelperText(getHelperText(versions, newValue, t));
90149
setOpen(false);
91150
}
92151
},
93-
[setCurrent, setHelperText, setOpen, getHelperText, t, versions, setValue],
152+
[setValue, getHelperText, versions, t],
94153
);
95154

96155
const toggle = React.useMemo(
@@ -120,7 +179,7 @@ export const OpenShiftVersionDropdown = ({
120179
name={name}
121180
id={fieldId}
122181
onSelect={onSelect}
123-
dropdownItems={dropdownItems}
182+
dropdownItems={dropdownGroup}
124183
toggle={toggle}
125184
isOpen={isOpen}
126185
className="pf-v5-u-w-100"

0 commit comments

Comments
 (0)