Skip to content

Commit be1203b

Browse files
committed
Wizard: Split FileSystemTable consts into separate components
This splits `FileSystemTable` file into individual components.
1 parent 2a71a30 commit be1203b

File tree

16 files changed

+423
-364
lines changed

16 files changed

+423
-364
lines changed

src/Components/CreateImageWizard/CreateImageWizard.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { useNavigate, useSearchParams } from 'react-router-dom';
1818
import AAPStep from './steps/AAP';
1919
import DetailsStep from './steps/Details';
2020
import FileSystemStep from './steps/FileSystem';
21-
import { FileSystemContext } from './steps/FileSystem/components/FileSystemTable';
21+
import { FileSystemContext } from './steps/FileSystem/components/Row';
2222
import FirewallStep from './steps/Firewall';
2323
import FirstBootStep from './steps/FirstBoot';
2424
import HostnameStep from './steps/Hostname';

src/Components/CreateImageWizard/steps/FileSystem/components/FileSystemTable.tsx

Lines changed: 3 additions & 349 deletions
Original file line numberDiff line numberDiff line change
@@ -1,370 +1,24 @@
11
import React, { useRef, useState } from 'react';
22

3-
import {
4-
Alert,
5-
Button,
6-
Content,
7-
MenuToggle,
8-
MenuToggleElement,
9-
Popover,
10-
Select,
11-
SelectList,
12-
SelectOption,
13-
TextInput,
14-
} from '@patternfly/react-core';
15-
import { HelpIcon, MinusCircleIcon } from '@patternfly/react-icons';
163
import styles from '@patternfly/react-styles/css/components/Table/table';
174
import {
185
Table,
196
Tbody,
207
TbodyProps,
21-
Td,
228
Th,
239
Thead,
2410
Tr,
2511
TrProps,
2612
} from '@patternfly/react-table';
2713

28-
import { UNIT_GIB, UNIT_KIB, UNIT_MIB } from '../../../../../constants';
14+
import MinimumSizePopover from './MinimumSizePopover';
15+
import Row from './Row';
16+
2917
import { useAppDispatch, useAppSelector } from '../../../../../store/hooks';
3018
import {
31-
changePartitionMinSize,
32-
changePartitionMountpoint,
3319
changePartitionOrder,
34-
changePartitionUnit,
35-
removePartition,
3620
selectFilesystemPartitions,
3721
} from '../../../../../store/wizardSlice';
38-
import { useFilesystemValidation } from '../../../utilities/useValidation';
39-
import { ValidatedInputAndTextArea } from '../../../ValidatedInput';
40-
41-
export const FileSystemContext = React.createContext<boolean>(true);
42-
43-
export const MinimumSizePopover = () => {
44-
return (
45-
<Popover
46-
maxWidth='30rem'
47-
bodyContent={
48-
<Content>
49-
<Content>
50-
Image Builder may extend this size based on requirements, selected
51-
packages, and configurations.
52-
</Content>
53-
</Content>
54-
}
55-
>
56-
<Button
57-
icon={<HelpIcon />}
58-
variant='plain'
59-
aria-label='File system configuration info'
60-
aria-describedby='file-system-configuration-info'
61-
className='popover-button pf-v6-u-p-0'
62-
/>
63-
</Popover>
64-
);
65-
};
66-
67-
export type Partition = {
68-
id: string;
69-
mountpoint: string;
70-
min_size: string;
71-
unit: Units;
72-
};
73-
74-
type RowPropTypes = {
75-
partition: Partition;
76-
onDrop?: (event: React.DragEvent<HTMLTableRowElement>) => void;
77-
onDragEnd?: (event: React.DragEvent<HTMLTableRowElement>) => void;
78-
onDragStart?: (event: React.DragEvent<HTMLTableRowElement>) => void;
79-
};
80-
81-
const normalizeSuffix = (rawSuffix: string) => {
82-
const suffix = rawSuffix.replace(/^\/+/g, '');
83-
return suffix.length > 0 ? '/' + suffix : '';
84-
};
85-
86-
const getPrefix = (mountpoint: string) => {
87-
return mountpoint.split('/')[1] ? '/' + mountpoint.split('/')[1] : '/';
88-
};
89-
const getSuffix = (mountpoint: string) => {
90-
const prefix = getPrefix(mountpoint);
91-
return normalizeSuffix(mountpoint.substring(prefix.length));
92-
};
93-
94-
const Row = ({ partition, onDragEnd, onDragStart, onDrop }: RowPropTypes) => {
95-
const dispatch = useAppDispatch();
96-
const handleRemovePartition = (id: string) => {
97-
dispatch(removePartition(id));
98-
};
99-
const stepValidation = useFilesystemValidation();
100-
const isPristine = React.useContext(FileSystemContext);
101-
102-
return (
103-
<Tr
104-
draggable
105-
id={partition.id}
106-
onDrop={onDrop}
107-
onDragStart={onDragStart}
108-
onDragEnd={onDragEnd}
109-
>
110-
<Td
111-
draggableRow={{
112-
id: `draggable-row-${partition.id}`,
113-
}}
114-
/>
115-
<Td className='pf-m-width-20'>
116-
<MountpointPrefix partition={partition} />
117-
{!isPristine && stepValidation.errors[`mountpoint-${partition.id}`] && (
118-
<Alert
119-
variant='danger'
120-
isInline
121-
isPlain
122-
title={stepValidation.errors[`mountpoint-${partition.id}`]}
123-
/>
124-
)}
125-
</Td>
126-
{partition.mountpoint !== '/' &&
127-
!partition.mountpoint.startsWith('/boot') &&
128-
!partition.mountpoint.startsWith('/usr') ? (
129-
<Td width={20}>
130-
<MountpointSuffix partition={partition} />
131-
</Td>
132-
) : (
133-
<Td width={20} />
134-
)}
135-
136-
<Td width={20}>xfs</Td>
137-
<Td width={20}>
138-
<MinimumSize partition={partition} />
139-
</Td>
140-
<Td width={10}>
141-
<SizeUnit partition={partition} />
142-
</Td>
143-
<Td width={10}>
144-
<Button
145-
variant='link'
146-
icon={<MinusCircleIcon />}
147-
onClick={() => handleRemovePartition(partition.id)}
148-
isDisabled={partition.mountpoint === '/'}
149-
/>
150-
</Td>
151-
</Tr>
152-
);
153-
};
154-
155-
export const mountpointPrefixes = [
156-
'/app',
157-
'/boot',
158-
'/data',
159-
'/home',
160-
'/opt',
161-
'/srv',
162-
'/tmp',
163-
'/usr',
164-
'/var',
165-
];
166-
167-
const units = ['GiB', 'MiB', 'KiB'];
168-
169-
type MountpointPrefixPropTypes = {
170-
partition: Partition;
171-
};
172-
173-
const MountpointPrefix = ({ partition }: MountpointPrefixPropTypes) => {
174-
const dispatch = useAppDispatch();
175-
const [isOpen, setIsOpen] = useState(false);
176-
const prefix = getPrefix(partition.mountpoint);
177-
const suffix = getSuffix(partition.mountpoint);
178-
179-
const onSelect = (event?: React.MouseEvent, selection?: string | number) => {
180-
if (selection && typeof selection === 'string') {
181-
setIsOpen(false);
182-
const mountpoint = selection + (suffix.length > 0 ? '/' + suffix : '');
183-
dispatch(
184-
changePartitionMountpoint({ id: partition.id, mountpoint: mountpoint }),
185-
);
186-
}
187-
};
188-
189-
const onToggleClick = () => {
190-
setIsOpen(!isOpen);
191-
};
192-
193-
const toggle = (toggleRef: React.Ref<MenuToggleElement>) => (
194-
<MenuToggle
195-
ref={toggleRef}
196-
onClick={onToggleClick}
197-
isExpanded={isOpen}
198-
isDisabled={prefix === '/'}
199-
isFullWidth
200-
>
201-
{prefix}
202-
</MenuToggle>
203-
);
204-
205-
return (
206-
<Select
207-
isOpen={isOpen}
208-
selected={prefix}
209-
onSelect={onSelect}
210-
onOpenChange={(isOpen) => setIsOpen(isOpen)}
211-
toggle={toggle}
212-
shouldFocusToggleOnSelect
213-
>
214-
<SelectList>
215-
{mountpointPrefixes.map((prefix, index) => {
216-
return (
217-
<SelectOption key={index} value={prefix}>
218-
{prefix}
219-
</SelectOption>
220-
);
221-
})}
222-
</SelectList>
223-
</Select>
224-
);
225-
};
226-
227-
type MountpointSuffixPropTypes = {
228-
partition: Partition;
229-
};
230-
231-
const MountpointSuffix = ({ partition }: MountpointSuffixPropTypes) => {
232-
const dispatch = useAppDispatch();
233-
const prefix = getPrefix(partition.mountpoint);
234-
const suffix = getSuffix(partition.mountpoint);
235-
236-
return (
237-
<TextInput
238-
value={suffix}
239-
type='text'
240-
onChange={(event: React.FormEvent, newValue) => {
241-
const mountpoint = prefix + normalizeSuffix(newValue);
242-
dispatch(
243-
changePartitionMountpoint({
244-
id: partition.id,
245-
mountpoint: mountpoint,
246-
}),
247-
);
248-
}}
249-
aria-label='mountpoint suffix'
250-
/>
251-
);
252-
};
253-
254-
type MinimumSizePropTypes = {
255-
partition: Partition;
256-
};
257-
258-
export type Units = 'B' | 'KiB' | 'MiB' | 'GiB';
259-
260-
export const getConversionFactor = (units: Units) => {
261-
switch (units) {
262-
case 'B':
263-
return 1;
264-
case 'KiB':
265-
return UNIT_KIB;
266-
case 'MiB':
267-
return UNIT_MIB;
268-
case 'GiB':
269-
return UNIT_GIB;
270-
}
271-
};
272-
273-
const MinimumSize = ({ partition }: MinimumSizePropTypes) => {
274-
const dispatch = useAppDispatch();
275-
const stepValidation = useFilesystemValidation();
276-
277-
return (
278-
<ValidatedInputAndTextArea
279-
ariaLabel='minimum partition size'
280-
value={partition.min_size}
281-
isDisabled={partition.unit === 'B'}
282-
warning={
283-
partition.unit === 'B'
284-
? 'The Wizard only supports KiB, MiB, or GiB. Adjust or keep the current value.'
285-
: ''
286-
}
287-
type='text'
288-
stepValidation={stepValidation}
289-
fieldName={`min-size-${partition.id}`}
290-
placeholder='File system'
291-
onChange={(event, minSize) => {
292-
if (minSize === '' || /^\d+$/.test(minSize)) {
293-
dispatch(
294-
changePartitionMinSize({
295-
id: partition.id,
296-
min_size: minSize,
297-
}),
298-
);
299-
dispatch(
300-
changePartitionUnit({ id: partition.id, unit: partition.unit }),
301-
);
302-
}
303-
}}
304-
/>
305-
);
306-
};
307-
308-
type SizeUnitPropTypes = {
309-
partition: Partition;
310-
};
311-
312-
const SizeUnit = ({ partition }: SizeUnitPropTypes) => {
313-
const dispatch = useAppDispatch();
314-
const [isOpen, setIsOpen] = useState(false);
315-
316-
const initialValue = useRef(partition).current;
317-
318-
const onSelect = (event?: React.MouseEvent, selection?: string | number) => {
319-
if (selection === undefined) return;
320-
if (initialValue.unit === 'B' && selection === ('B' as Units)) {
321-
dispatch(
322-
changePartitionMinSize({
323-
id: partition.id,
324-
min_size: initialValue.min_size,
325-
}),
326-
);
327-
}
328-
dispatch(
329-
changePartitionUnit({ id: partition.id, unit: selection as Units }),
330-
);
331-
setIsOpen(false);
332-
};
333-
334-
const onToggleClick = () => {
335-
setIsOpen(!isOpen);
336-
};
337-
338-
const toggle = (toggleRef: React.Ref<MenuToggleElement>) => (
339-
<MenuToggle ref={toggleRef} onClick={onToggleClick} isExpanded={isOpen}>
340-
{partition.unit}
341-
</MenuToggle>
342-
);
343-
344-
return (
345-
<Select
346-
isOpen={isOpen}
347-
selected={partition.unit}
348-
onSelect={onSelect}
349-
onOpenChange={(isOpen) => setIsOpen(isOpen)}
350-
toggle={toggle}
351-
shouldFocusToggleOnSelect
352-
>
353-
<SelectList>
354-
{units.map((unit, index) => (
355-
<SelectOption key={index} value={unit}>
356-
{unit}
357-
</SelectOption>
358-
))}
359-
<>
360-
{initialValue.unit === 'B' && (
361-
<SelectOption value={'B'}>B</SelectOption>
362-
)}
363-
</>
364-
</SelectList>
365-
</Select>
366-
);
367-
};
36822

36923
const FileSystemTable = () => {
37024
const [draggedItemId, setDraggedItemId] = useState<string | null>(null);

0 commit comments

Comments
 (0)