Wizard: Improve file system configuration error messaging
This commit improves the file system configuration step's error handling by performing validation only when the next button is clicked. This allows an invalid state to temporarily exist while the user is modifying the mountpoints without bothersome error messages needlessly appearing. Broadly speaking there were two options for the implementation: (1) delay the validation, performing validation only upon clicking the next button -or- (2) perform validation immediately as normal but hide error messages until the next button is clicked. Option (1) proved to be untenable - Data Driven Forms does provide `pauseValidation()` and `resumeValidation()` functions from React Final Form which theoretically would make this option possible... However, we need to call `resumeValidation()` in the next button's click handler and then immediately make a decision based on the validation results either to remain on the step and display the errors or move to the next step. When we tried implmenting this we found that `resumeValidation()` does not immediately peform validation - validation only resumes after exiting the handler. Therefore, this approach was not considered and option (2) was used. In order to gain control over the behavior of the next button, custom buttons are implemented for this step. Sharing state between the custom buttons and the form was a challenge. With pure React it would have been as simple as moving the relevant state to the parent component, but that was not possible due to Data Driven Forms. Instead, state is shared using the form state. A new property, `'file-system-config-show-errors'`, in the form state is used to determine whether or not error messages should be displayed. In order to cause a re-render upon a change in `'file-system-config-show-errors'`, the file system configuration component is wrapped in a `<FormSpy>` component.
This commit is contained in:
parent
e868ffcaa6
commit
de4e9bea07
3 changed files with 211 additions and 136 deletions
|
|
@ -25,6 +25,7 @@ import useFormApi from '@data-driven-forms/react-form-renderer/use-form-api';
|
|||
import useFieldApi from '@data-driven-forms/react-form-renderer/use-field-api';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
import { FormSpy } from '@data-driven-forms/react-form-renderer';
|
||||
import MountPoint from './MountPoint';
|
||||
import SizeUnit from './SizeUnit';
|
||||
import { UNIT_GIB } from '../../../constants';
|
||||
|
|
@ -71,6 +72,9 @@ const FileSystemConfiguration = ({ ...props }) => {
|
|||
setItemOrder(newOrder);
|
||||
}, []);
|
||||
|
||||
const showErrors = () =>
|
||||
getState()?.values?.['file-system-config-show-errors'];
|
||||
|
||||
useEffect(() => {
|
||||
change(
|
||||
input.name,
|
||||
|
|
@ -238,143 +242,154 @@ const FileSystemConfiguration = ({ ...props }) => {
|
|||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<TextContent>
|
||||
<Text component={TextVariants.h3}>Configure partitions</Text>
|
||||
</TextContent>
|
||||
{rows.length > 1 &&
|
||||
getState()?.errors?.['file-system-configuration']?.duplicates && (
|
||||
<Alert
|
||||
variant="danger"
|
||||
isInline
|
||||
title="Duplicate mount points: All mount points must be unique. Remove the duplicate or choose a new mount point."
|
||||
/>
|
||||
)}
|
||||
{rows.length >= 1 &&
|
||||
getState()?.errors?.['file-system-configuration']?.root === false && (
|
||||
<Alert
|
||||
variant="danger"
|
||||
isInline
|
||||
title="No root partition configured."
|
||||
/>
|
||||
)}
|
||||
<TextContent>
|
||||
<Text>
|
||||
Partitions have been generated and given default values based on best
|
||||
practices from Red Hat, and your selections in previous steps of the
|
||||
wizard.
|
||||
</Text>
|
||||
</TextContent>
|
||||
<TableComposable
|
||||
aria-label="File system table"
|
||||
className={isDragging && styles.modifiers.dragOver}
|
||||
variant="compact"
|
||||
>
|
||||
<Thead>
|
||||
<Tr>
|
||||
<Th />
|
||||
<Th>Mount point</Th>
|
||||
<Th>Type</Th>
|
||||
<Th>
|
||||
Minimum size
|
||||
<Popover
|
||||
hasAutoWidth
|
||||
bodyContent={
|
||||
<TextContent>
|
||||
<Text>
|
||||
Image Builder may extend this size based on requirements,
|
||||
selected packages, and configurations.
|
||||
</Text>
|
||||
</TextContent>
|
||||
}
|
||||
>
|
||||
<Button
|
||||
variant="plain"
|
||||
aria-label="File system configuration info"
|
||||
aria-describedby="file-system-configuration-info"
|
||||
className="pf-c-form__group-label-help"
|
||||
>
|
||||
<HelpIcon />
|
||||
</Button>
|
||||
</Popover>
|
||||
</Th>
|
||||
<Th />
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody
|
||||
ref={bodyref}
|
||||
onDragOver={onDragOver}
|
||||
onDrop={onDragOver}
|
||||
onDragLeave={onDragLeave}
|
||||
data-testid="file-system-configuration-tbody"
|
||||
>
|
||||
{rows.map((row, rowIndex) => (
|
||||
<Tr
|
||||
key={rowIndex}
|
||||
id={row.id}
|
||||
draggable
|
||||
onDrop={onDrop}
|
||||
onDragEnd={onDragEnd}
|
||||
onDragStart={onDragStart}
|
||||
>
|
||||
<Td
|
||||
draggableRow={{
|
||||
id: `draggable-row-${row.id}`,
|
||||
}}
|
||||
<FormSpy>
|
||||
{() => (
|
||||
<>
|
||||
<TextContent>
|
||||
<Text component={TextVariants.h3}>Configure partitions</Text>
|
||||
</TextContent>
|
||||
{rows.length > 1 &&
|
||||
getState()?.errors?.['file-system-configuration']?.duplicates
|
||||
?.length !== 0 &&
|
||||
showErrors() && (
|
||||
<Alert
|
||||
variant="danger"
|
||||
isInline
|
||||
title="Duplicate mount points: All mount points must be unique. Remove the duplicate or choose a new mount point."
|
||||
data-testid="fsc-warning"
|
||||
/>
|
||||
<Td className="pf-m-width-30">
|
||||
<MountPoint
|
||||
key={row.id + '-mountpoint'}
|
||||
mountpoint={row.mountpoint}
|
||||
onChange={(mp) => setMountpoint(row.id, mp)}
|
||||
/>
|
||||
{getState().errors['file-system-configuration']?.duplicates &&
|
||||
getState().errors[
|
||||
'file-system-configuration'
|
||||
]?.duplicates.indexOf(row.mountpoint) !== -1 && (
|
||||
<Alert
|
||||
variant="danger"
|
||||
isInline
|
||||
isPlain
|
||||
title="Duplicate mount point."
|
||||
)}
|
||||
{rows.length >= 1 &&
|
||||
getState()?.errors?.['file-system-configuration']?.root === false &&
|
||||
showErrors() && (
|
||||
<Alert
|
||||
variant="danger"
|
||||
isInline
|
||||
title="No root partition configured."
|
||||
/>
|
||||
)}
|
||||
<TextContent>
|
||||
<Text>
|
||||
Partitions have been generated and given default values based on
|
||||
best practices from Red Hat, and your selections in previous steps
|
||||
of the wizard.
|
||||
</Text>
|
||||
</TextContent>
|
||||
<TableComposable
|
||||
aria-label="File system table"
|
||||
className={isDragging && styles.modifiers.dragOver}
|
||||
variant="compact"
|
||||
>
|
||||
<Thead>
|
||||
<Tr>
|
||||
<Th />
|
||||
<Th>Mount point</Th>
|
||||
<Th>Type</Th>
|
||||
<Th>
|
||||
Minimum size
|
||||
<Popover
|
||||
hasAutoWidth
|
||||
bodyContent={
|
||||
<TextContent>
|
||||
<Text>
|
||||
Image Builder may extend this size based on
|
||||
requirements, selected packages, and configurations.
|
||||
</Text>
|
||||
</TextContent>
|
||||
}
|
||||
>
|
||||
<Button
|
||||
variant="plain"
|
||||
aria-label="File system configuration info"
|
||||
aria-describedby="file-system-configuration-info"
|
||||
className="pf-c-form__group-label-help"
|
||||
>
|
||||
<HelpIcon />
|
||||
</Button>
|
||||
</Popover>
|
||||
</Th>
|
||||
<Th />
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody
|
||||
ref={bodyref}
|
||||
onDragOver={onDragOver}
|
||||
onDrop={onDragOver}
|
||||
onDragLeave={onDragLeave}
|
||||
data-testid="file-system-configuration-tbody"
|
||||
>
|
||||
{rows.map((row, rowIndex) => (
|
||||
<Tr
|
||||
key={rowIndex}
|
||||
id={row.id}
|
||||
draggable
|
||||
onDrop={onDrop}
|
||||
onDragEnd={onDragEnd}
|
||||
onDragStart={onDragStart}
|
||||
>
|
||||
<Td
|
||||
draggableRow={{
|
||||
id: `draggable-row-${row.id}`,
|
||||
}}
|
||||
/>
|
||||
<Td className="pf-m-width-30">
|
||||
<MountPoint
|
||||
key={row.id + '-mountpoint'}
|
||||
mountpoint={row.mountpoint}
|
||||
onChange={(mp) => setMountpoint(row.id, mp)}
|
||||
/>
|
||||
)}
|
||||
</Td>
|
||||
<Td className="pf-m-width-20">
|
||||
{/* always xfs */}
|
||||
{row.fstype}
|
||||
</Td>
|
||||
<Td className="pf-m-width-30">
|
||||
<SizeUnit
|
||||
key={row.id + '-sizeunit'}
|
||||
size={row.size}
|
||||
unit={row.unit}
|
||||
onChange={(s, u) => setSize(row.id, s, u)}
|
||||
/>
|
||||
</Td>
|
||||
<Td className="pf-m-width-10">
|
||||
<Button
|
||||
variant="link"
|
||||
icon={<MinusCircleIcon />}
|
||||
onClick={() => removeRow(row.id)}
|
||||
/>
|
||||
</Td>
|
||||
</Tr>
|
||||
))}
|
||||
</Tbody>
|
||||
</TableComposable>
|
||||
<TextContent>
|
||||
<Button
|
||||
data-testid="file-system-add-partition"
|
||||
className="pf-u-text-align-left"
|
||||
variant="link"
|
||||
icon={<PlusCircleIcon />}
|
||||
onClick={addRow}
|
||||
>
|
||||
Add partition
|
||||
</Button>
|
||||
</TextContent>
|
||||
</>
|
||||
{getState().errors['file-system-configuration']?.duplicates
|
||||
.length !== 0 &&
|
||||
getState().errors[
|
||||
'file-system-configuration'
|
||||
]?.duplicates.indexOf(row.mountpoint) !== -1 &&
|
||||
showErrors() && (
|
||||
<Alert
|
||||
variant="danger"
|
||||
isInline
|
||||
isPlain
|
||||
title="Duplicate mount point."
|
||||
/>
|
||||
)}
|
||||
</Td>
|
||||
<Td className="pf-m-width-20">
|
||||
{/* always xfs */}
|
||||
{row.fstype}
|
||||
</Td>
|
||||
<Td className="pf-m-width-30">
|
||||
<SizeUnit
|
||||
key={row.id + '-sizeunit'}
|
||||
size={row.size}
|
||||
unit={row.unit}
|
||||
onChange={(s, u) => setSize(row.id, s, u)}
|
||||
/>
|
||||
</Td>
|
||||
<Td className="pf-m-width-10">
|
||||
<Button
|
||||
variant="link"
|
||||
icon={<MinusCircleIcon />}
|
||||
onClick={() => removeRow(row.id)}
|
||||
data-testid="remove-mount-point"
|
||||
/>
|
||||
</Td>
|
||||
</Tr>
|
||||
))}
|
||||
</Tbody>
|
||||
</TableComposable>
|
||||
<TextContent>
|
||||
<Button
|
||||
data-testid="file-system-add-partition"
|
||||
className="pf-u-text-align-left"
|
||||
variant="link"
|
||||
icon={<PlusCircleIcon />}
|
||||
onClick={addRow}
|
||||
>
|
||||
Add partition
|
||||
</Button>
|
||||
</TextContent>
|
||||
</>
|
||||
)}
|
||||
</FormSpy>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue