Skip to content

Commit 0b7af13

Browse files
authored
MGMT-22941: ABI: add version dropdown (#3370)
* ABI: add version dropdown * Address review comments
1 parent 464807b commit 0b7af13

File tree

12 files changed

+253
-260
lines changed

12 files changed

+253
-260
lines changed

libs/ui-lib/lib/cim/components/ClusterDeployment/clusterDetails/ClusterDetailsFormFields.tsx

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -81,15 +81,6 @@ export const ClusterDetailsFormFields: React.FC<ClusterDetailsFormFieldsProps> =
8181
nameInputRef.current?.focus();
8282
}, []);
8383

84-
const selectOptions = React.useMemo(
85-
() =>
86-
versions.map((version) => ({
87-
label: version.label,
88-
value: version.value,
89-
})),
90-
[versions],
91-
);
92-
9384
const additionalSelectOption = React.useMemo(() => {
9485
if (
9586
values.customOpenshiftSelect &&
@@ -151,16 +142,15 @@ export const ClusterDetailsFormFields: React.FC<ClusterDetailsFormFieldsProps> =
151142
<>
152143
<OpenShiftVersionDropdown
153144
name="openshiftVersion"
154-
items={selectOptions}
155145
versions={versions}
156146
showReleasesLink={false}
157147
showOpenshiftVersionModal={() => setOpenshiftVersionModalOpen(true)}
158-
customItem={additionalSelectOption}
148+
customVersion={additionalSelectOption}
159149
/>
160150
{openshiftVersionModalOpen && (
161151
<OpenShiftVersionModal
162152
allVersions={allVersions}
163-
setOpenshiftVersionModalOpen={setOpenshiftVersionModalOpen}
153+
onClose={() => setOpenshiftVersionModalOpen(false)}
164154
/>
165155
)}
166156
</>

libs/ui-lib/lib/cim/components/Hypershift/HostedClusterWizard/DetailsStep/DetailsForm.tsx

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,24 +28,15 @@ const DetailsForm: React.FC<DetailsFormProps> = ({
2828
nameInputRef.current?.focus();
2929
}, []);
3030

31-
const selectOptions = React.useMemo(
32-
() =>
33-
ocpVersions.map((version) => ({
34-
label: version.label,
35-
value: version.value,
36-
})),
37-
[ocpVersions],
38-
);
39-
4031
const additionalSelectOption = React.useMemo(() => {
4132
if (
4233
values.customOpenshiftSelect &&
43-
!selectOptions.some((option) => option.value === values.customOpenshiftSelect)
34+
!ocpVersions.some((option) => option.value === values.customOpenshiftSelect)
4435
) {
4536
return allVersions.find((version) => version.value === values.customOpenshiftSelect);
4637
}
4738
return undefined;
48-
}, [allVersions, selectOptions, values.customOpenshiftSelect]);
39+
}, [allVersions, ocpVersions, values.customOpenshiftSelect]);
4940

5041
return (
5142
<Form>
@@ -66,16 +57,15 @@ const DetailsForm: React.FC<DetailsFormProps> = ({
6657
/>
6758
<OpenShiftVersionDropdown
6859
name="openshiftVersion"
69-
items={selectOptions}
7060
versions={ocpVersions}
7161
showReleasesLink={false}
7262
showOpenshiftVersionModal={() => setOpenshiftVersionModalOpen(true)}
73-
customItem={additionalSelectOption}
63+
customVersion={additionalSelectOption}
7464
/>
7565
{openshiftVersionModalOpen && (
7666
<OpenShiftVersionModal
7767
allVersions={allVersions}
78-
setOpenshiftVersionModalOpen={setOpenshiftVersionModalOpen}
68+
onClose={() => setOpenshiftVersionModalOpen(false)}
7969
/>
8070
)}
8171

libs/ui-lib/lib/common/components/ui/OpenShiftSelectWithSearch.tsx

Lines changed: 22 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import React from 'react';
2-
import { SelectOptionProps } from '@patternfly/react-core';
32
import { useField } from 'formik';
43
import { OpenshiftVersionOptionType } from '../../types';
54
import { HelperTextType } from './OpenShiftVersionDropdown';
65
import { useTranslation } from '../../hooks';
76
import { SelectFieldWithSearch } from './formik';
87
import { ClusterDetailsValues } from '../clusterWizard';
8+
import { getVersionLabel } from './utils';
99

1010
type OpenshiftSelectWithSearchProps = {
1111
versions: OpenshiftVersionOptionType[];
@@ -19,62 +19,41 @@ export const OpenShiftSelectWithSearch: React.FunctionComponent<OpenshiftSelectW
1919
const { t } = useTranslation();
2020
const [{ value }] =
2121
useField<ClusterDetailsValues['customOpenshiftSelect']>('customOpenshiftSelect');
22-
const initialSelectOptions = React.useMemo(
23-
() =>
24-
versions.map((version) => ({
25-
children:
26-
version.supportLevel === 'beta'
27-
? version.label + ' - ' + 'Developer preview release'
28-
: version.label,
29-
value: version.value,
30-
})),
31-
[versions],
32-
);
3322

3423
const [filterValue, setFilterValue] = React.useState<string>('');
35-
const [selectOptions, setSelectOptions] =
36-
React.useState<SelectOptionProps[]>(initialSelectOptions);
37-
38-
const helperText = getHelperText && getHelperText(value, true);
39-
40-
React.useEffect(() => {
41-
let newSelectOptions: SelectOptionProps[] = initialSelectOptions;
4224

43-
// Filter menu items based on the text input value when one exists
44-
if (filterValue) {
45-
newSelectOptions = initialSelectOptions.filter((menuItem) =>
46-
String(menuItem.children).toLowerCase().includes(filterValue.toLowerCase()),
25+
const selectOptions = React.useMemo(() => {
26+
const options = versions
27+
.map((version) => ({
28+
children: getVersionLabel(version, t),
29+
value: version.value,
30+
}))
31+
.filter((v) =>
32+
filterValue ? String(v.children).toLowerCase().includes(filterValue.toLowerCase()) : true,
4733
);
4834

49-
// When no options are found after filtering, display 'No results found'
50-
if (!newSelectOptions.length) {
51-
newSelectOptions = [
52-
{
53-
isDisabled: true,
54-
children: t('ai:No results found for {{filter}}', { filter: filterValue }),
55-
value: 'no_results',
56-
},
57-
];
58-
}
35+
if (!options.length) {
36+
return [
37+
{
38+
isDisabled: true,
39+
children: t('ai:No results found for {{filter}}', { filter: filterValue }),
40+
value: 'no_results',
41+
},
42+
];
5943
}
60-
61-
const selectOptionsWithDividers = newSelectOptions.map((option, index) => {
62-
const match = (option.value as string).match(/\d+\.(\d+)\.\d+/);
44+
return options.map((option, index) => {
45+
const match = option.value.match(/\d+\.(\d+)\.\d+/);
6346
const y = match ? match[1] : null;
6447

6548
const previousY =
66-
index > 0
67-
? ((newSelectOptions[index - 1].value as string).match(/\d+\.(\d+)\.\d+/) || [])[1]
68-
: null;
49+
index > 0 ? (options[index - 1].value.match(/\d+\.(\d+)\.\d+/) || [])[1] : null;
6950

7051
return {
7152
...option,
7253
showDivider: previousY !== null && y !== previousY,
7354
};
7455
});
75-
76-
setSelectOptions(selectOptionsWithDividers);
77-
}, [filterValue, initialSelectOptions, t]);
56+
}, [filterValue, versions, t]);
7857

7958
return (
8059
<SelectFieldWithSearch
@@ -83,7 +62,7 @@ export const OpenShiftSelectWithSearch: React.FunctionComponent<OpenshiftSelectW
8362
setFilterValue={setFilterValue}
8463
name={'customOpenshiftSelect'}
8564
helperText={
86-
helperText ??
65+
getHelperText?.(value, true) ??
8766
t(
8867
'ai:Select an OpenShift version from the list or use the type ahead to narrow down the list.',
8968
)

libs/ui-lib/lib/common/components/ui/OpenShiftVersionDropdown.tsx

Lines changed: 41 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -4,81 +4,75 @@ import {
44
FormGroup,
55
FormHelperText,
66
HelperTextItem,
7-
Button,
87
DropdownItem,
98
MenuToggle,
109
MenuToggleElement,
1110
Dropdown,
1211
DropdownGroup,
1312
Divider,
13+
DropdownProps,
1414
} from '@patternfly/react-core';
1515

1616
import { OpenshiftVersionOptionType } from '../../types';
1717
import { useTranslation } from '../../hooks/use-translation-wrapper';
18-
import { useField, useFormikContext } from 'formik';
18+
import { useField } from 'formik';
1919
import { getFieldId } from './formik';
2020
import ExternalLink from './ExternalLink';
2121
import { OCP_RELEASES_PAGE } from '../../config';
22-
import { ClusterDetailsValues, ItemDropdown } from '../clusterWizard';
22+
import { getVersionLabel } from './utils';
2323

2424
export type HelperTextType = (value: string | null, inModal?: boolean) => JSX.Element | null;
2525

2626
type OpenShiftVersionDropdownProps = {
2727
name: string;
28-
items: ItemDropdown;
2928
versions: OpenshiftVersionOptionType[];
3029
getHelperText?: HelperTextType;
3130
showReleasesLink: boolean;
3231
showOpenshiftVersionModal: () => void;
33-
customItem?: OpenshiftVersionOptionType;
32+
customVersion?: OpenshiftVersionOptionType;
3433
};
3534

36-
const getParsedVersions = (items: ItemDropdown) => {
35+
const getParsedVersions = (items: OpenshiftVersionOptionType[]) => {
3736
const versionsY = Array.from(new Set(items.map((val) => val.value.match(/^\d+\.(\d+)/)?.[1])));
3837

3938
const parsedVersions = versionsY.map((y) => ({
4039
y: y,
4140
versions: items.filter((val) => val.value.match(/^\d+\.(\d+)/)?.[1] === y),
4241
}));
43-
return { parsedVersions: parsedVersions.reverse() };
42+
return parsedVersions.reverse();
4443
};
4544
export const OpenShiftVersionDropdown = ({
4645
name,
47-
items,
4846
versions,
4947
getHelperText,
5048
showReleasesLink,
5149
showOpenshiftVersionModal,
52-
customItem,
50+
customVersion,
5351
}: OpenShiftVersionDropdownProps) => {
5452
const [field, , { setValue }] = useField<string>(name);
5553
const [isOpen, setOpen] = React.useState(false);
5654
const { t } = useTranslation();
5755
const fieldId = getFieldId(name, 'input');
58-
const {
59-
values: { customOpenshiftSelect },
60-
} = useFormikContext<ClusterDetailsValues>();
61-
const [current, setCurrent] = React.useState<string>();
56+
57+
const current = (customVersion ? [...versions, customVersion] : versions).find(
58+
(item) => item.value === field.value,
59+
);
6260

6361
React.useEffect(() => {
64-
let defaultVersion = versions.find((item) => item.default);
65-
if (customOpenshiftSelect && customItem) {
66-
defaultVersion = customItem;
67-
} else if (customOpenshiftSelect) {
68-
defaultVersion = versions.find((item) => item.value === customOpenshiftSelect);
62+
if (!field.value) {
63+
const defaultVersion = versions.find((item) => item.default) || versions[0];
64+
if (defaultVersion) {
65+
setValue(defaultVersion.value);
66+
}
6967
}
68+
}, [field.value, versions, setValue]);
7069

71-
setCurrent(defaultVersion?.label || '');
72-
setValue(defaultVersion?.value || '');
73-
// eslint-disable-next-line react-hooks/exhaustive-deps
74-
}, [customOpenshiftSelect]);
75-
76-
const parsedVersionsForItems = getParsedVersions(items);
70+
const parsedVersions = getParsedVersions(versions);
7771
let lastY: string | undefined = '';
78-
const dropdownItems = parsedVersionsForItems.parsedVersions.map(({ y, versions }) => {
79-
const items = versions.map(({ value, label }) => (
80-
<DropdownItem key={value} id={value} value={value}>
81-
{label}
72+
const dropdownItems = parsedVersions.map(({ y, versions }) => {
73+
const items = versions.map((version) => (
74+
<DropdownItem key={version.value} id={version.value} value={version.value}>
75+
{getVersionLabel(version, t)}
8276
</DropdownItem>
8377
));
8478

@@ -95,43 +89,24 @@ export const OpenShiftVersionDropdown = ({
9589
{dropdownItems}
9690
</DropdownGroup>
9791
),
98-
customItem && (
92+
customVersion && (
9993
<DropdownGroup label="Custom releases" key="custom-releases">
100-
<DropdownItem key={customItem.value} id={customItem.value} value={customItem.value}>
101-
{customItem.label}
94+
<DropdownItem
95+
key={customVersion.value}
96+
id={customVersion.value}
97+
value={customVersion.value}
98+
>
99+
{getVersionLabel(customVersion, t)}
102100
</DropdownItem>
103101
</DropdownGroup>
104102
),
105103
<DropdownGroup key="all-available-versions">
106-
<DropdownItem key="all-versions" id="all-versions" onSelect={(e) => e.preventDefault()}>
107-
<Button
108-
variant="link"
109-
isInline
110-
onClick={() => {
111-
setOpen(false);
112-
showOpenshiftVersionModal();
113-
}}
114-
id="show-all-versions"
115-
>
116-
{t('ai:Show all available versions')}
117-
</Button>
104+
<DropdownItem key="all-versions" id="all-versions" value="all-versions">
105+
<div className="pf-v6-u-text-color-link">{t('ai:Show all available versions')}</div>
118106
</DropdownItem>
119107
</DropdownGroup>,
120108
].filter(Boolean);
121109

122-
const onSelect = React.useCallback(
123-
(event?: React.MouseEvent<Element, MouseEvent>, val?: string | number) => {
124-
const newLabel = event?.currentTarget.textContent;
125-
const newValue = (val as string) || '';
126-
if (newLabel && event.currentTarget.id !== 'all-versions') {
127-
setCurrent(newLabel);
128-
setValue(newValue);
129-
setOpen(false);
130-
}
131-
},
132-
[setValue],
133-
);
134-
135110
const dropdownToggle = (toggleRef: React.Ref<MenuToggleElement>) => (
136111
<MenuToggle
137112
id={fieldId}
@@ -143,12 +118,21 @@ export const OpenShiftVersionDropdown = ({
143118
isExpanded={isOpen}
144119
data-testid="openshift-version-dropdown-toggle"
145120
>
146-
{current || t('ai:OpenShift version')}
121+
{current ? getVersionLabel(current, t) : t('ai:OpenShift version')}
147122
</MenuToggle>
148123
);
149124

150125
const helperText = getHelperText && getHelperText(field.value);
151126

127+
const onSelect: DropdownProps['onSelect'] = (_, val) => {
128+
if (val === 'all-versions') {
129+
showOpenshiftVersionModal();
130+
} else if (val) {
131+
setValue(val as string);
132+
}
133+
setOpen(false);
134+
};
135+
152136
return (
153137
<FormGroup
154138
id={`form-control__${fieldId}`}

0 commit comments

Comments
 (0)