V2Wizard: Add <ReleaseSelect> to Image Output step

The `<ReleaseSelect>` component now uses RTK instead of DDF. Some
additional small changes  were necessary due to Typescript - in
particular, we use a Map() to store the releases (in order to ensure
they appear in the correct order) and .tsconfig had to be modified to
allow iteration over the Map() object.
This commit is contained in:
lucasgarfield 2024-01-05 19:56:02 +01:00 committed by Sanne Raymaekers
parent 2465ab4b84
commit ad2bd7a31a
5 changed files with 70 additions and 48 deletions

View file

@ -1,15 +1,11 @@
import React, { useState } from 'react';
import React, { ReactElement, useState } from 'react';
import { FormSpy } from '@data-driven-forms/react-form-renderer';
import useFieldApi from '@data-driven-forms/react-form-renderer/use-field-api';
import useFormApi from '@data-driven-forms/react-form-renderer/use-form-api';
import { FormGroup } from '@patternfly/react-core';
import {
Select,
SelectOption,
SelectVariant,
} from '@patternfly/react-core/deprecated';
import PropTypes from 'prop-types';
import {
RELEASES,
@ -19,18 +15,27 @@ import {
RHEL_9,
RHEL_9_FULL_SUPPORT,
RHEL_9_MAINTENANCE_SUPPORT,
} from '../../../constants';
import isRhel from '../../../Utilities/isRhel';
import { toMonthAndYear } from '../../../Utilities/time';
} from '../../../../constants';
import { useAppDispatch, useAppSelector } from '../../../../store/hooks';
import { Distributions } from '../../../../store/imageBuilderApi';
import {
changeDistribution,
selectDistribution,
} from '../../../../store/wizardSlice';
import isRhel from '../../../../Utilities/isRhel';
import { toMonthAndYear } from '../../../../Utilities/time';
const ImageOutputReleaseSelect = ({ label, isRequired, ...props }) => {
const { change, getState } = useFormApi();
const { input } = useFieldApi(props);
const ReleaseSelect = () => {
// What the UI refers to as the "release" is referred to as the "distribution" in the API.
// The Redux store follows the API convention, and data read from or to the store will use
// the word "Distribution" instead of "Release".
const distribution = useAppSelector((state) => selectDistribution(state));
const dispatch = useAppDispatch();
const [isOpen, setIsOpen] = useState(false);
const [showDevelopmentOptions, setShowDevelopmentOptions] = useState(false);
const setRelease = (_, selection) => {
change(input.name, selection);
const handleSelect = (_event: React.MouseEvent, selection: Distributions) => {
dispatch(changeDistribution(selection));
setIsOpen(false);
};
@ -38,7 +43,7 @@ const ImageOutputReleaseSelect = ({ label, isRequired, ...props }) => {
setShowDevelopmentOptions(true);
};
const setDescription = (key) => {
const setDescription = (key: Distributions) => {
let fullSupportEnd = '';
let maintenanceSupportEnd = '';
@ -58,7 +63,7 @@ const ImageOutputReleaseSelect = ({ label, isRequired, ...props }) => {
};
const setSelectOptions = () => {
var options = [];
const options: ReactElement[] = [];
const filteredRhel = new Map(
[...RELEASES].filter(([key]) => {
// Only show non-RHEL distros if expanded
@ -71,7 +76,11 @@ const ImageOutputReleaseSelect = ({ label, isRequired, ...props }) => {
filteredRhel.forEach((value, key) => {
options.push(
<SelectOption key={value} value={key} description={setDescription(key)}>
<SelectOption
key={value}
value={key}
description={setDescription(key as Distributions)}
>
{RELEASES.get(key)}
</SelectOption>
);
@ -81,34 +90,25 @@ const ImageOutputReleaseSelect = ({ label, isRequired, ...props }) => {
};
return (
<FormSpy>
{() => (
<FormGroup isRequired={isRequired} label={label}>
<Select
ouiaId="release_select"
variant={SelectVariant.single}
onToggle={() => setIsOpen(!isOpen)}
onSelect={setRelease}
selections={RELEASES.get(getState()?.values?.[input.name])}
isOpen={isOpen}
{...(!showDevelopmentOptions && {
loadingVariant: {
text: 'Show options for further development of RHEL',
onClick: handleExpand,
},
})}
>
{setSelectOptions()}
</Select>
</FormGroup>
)}
</FormSpy>
<FormGroup isRequired={true} label="Release">
<Select
ouiaId="release_select"
variant={SelectVariant.single}
onToggle={() => setIsOpen(!isOpen)}
onSelect={handleSelect}
selections={RELEASES.get(distribution)}
isOpen={isOpen}
{...(!showDevelopmentOptions && {
loadingVariant: {
text: 'Show options for further development of RHEL',
onClick: handleExpand,
},
})}
>
{setSelectOptions()}
</Select>
</FormGroup>
);
};
ImageOutputReleaseSelect.propTypes = {
label: PropTypes.node,
isRequired: PropTypes.bool,
};
export default ImageOutputReleaseSelect;
export default ReleaseSelect;

View file

@ -2,6 +2,8 @@ import React from 'react';
import { Text, Form, Title } from '@patternfly/react-core';
import ReleaseSelect from './ReleaseSelect';
import DocumentationButton from '../../../sharedComponents/DocumentationButton';
const ImageOutputStep = () => {
@ -14,6 +16,7 @@ const ImageOutputStep = () => {
<br />
<DocumentationButton />
</Text>
<ReleaseSelect />
</Form>
);
};

View file

@ -14,6 +14,7 @@ export const UNIT_KIB = 1024 ** 1;
export const UNIT_MIB = 1024 ** 2;
export const UNIT_GIB = 1024 ** 3;
// Use a Map() to ensure order is preserved (order is not gauranteed by an Object())
export const RELEASES = new Map([
[RHEL_9, 'Red Hat Enterprise Linux (RHEL) 9'],
[RHEL_8, 'Red Hat Enterprise Linux (RHEL) 8'],

View file

@ -1,16 +1,33 @@
import { createSlice } from '@reduxjs/toolkit';
import { PayloadAction, createSlice } from '@reduxjs/toolkit';
type wizardState = {};
import { Distributions } from './imageBuilderApi';
const initialState: wizardState = {};
import { RHEL_9 } from '../constants';
import { RootState } from '.';
type wizardState = {
distribution: Distributions;
};
const initialState: wizardState = {
distribution: RHEL_9,
};
export const selectDistribution = (state: RootState) => {
return state.wizard.distribution;
};
export const wizardSlice = createSlice({
name: 'wizard',
initialState,
reducers: {
initializeWizard: () => initialState,
changeDistribution: (state, action: PayloadAction<Distributions>) => {
state.distribution = action.payload;
},
},
});
export const { initializeWizard } = wizardSlice.actions;
export const { initializeWizard, changeDistribution } = wizardSlice.actions;
export default wizardSlice.reducer;

View file

@ -4,6 +4,7 @@
"noImplicitAny": true,
"module": "es6",
"target": "es5",
"downlevelIteration": true, // Needed to allow iteration over some objects like Map() while target is es5
"jsx": "react-jsx",
"allowJs": true,
"moduleResolution": "node",