Skip to content

Commit

Permalink
web: WIP first version of the new location dialog
Browse files Browse the repository at this point in the history
  • Loading branch information
joseivanlopez committed Apr 30, 2024
1 parent d88d1f0 commit 7fb343b
Show file tree
Hide file tree
Showing 11 changed files with 305 additions and 153 deletions.
29 changes: 29 additions & 0 deletions web/src/client/storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,35 @@ class ProposalManager {
return proxy.AvailableDevices.map(path => findDevice(systemDevices, path)).filter(d => d);
}

/**
* Gets the devices that can be selected as target for a volume.
*
* @returns {Promise<StorageDevice[]>}
*/
async getVolumeDevices() {
const availableDevices = await this.getAvailableDevices();

const isAvailable = (device) => {
const isChildren = (device, parentDevice) => {
const partitions = parentDevice.partitionTable?.partitions || [];
return !!partitions.find(d => d.name === device.name);
};

return (
!!availableDevices.find(d => d.name === device.name) ||
!!availableDevices.find(d => isChildren(device, d))
);
};

const allAvailable = (devices) => devices.every(isAvailable);

const system = await this.system.getDevices();
const mds = system.filter(d => d.type === "md" && allAvailable(d.devices));
const vgs = system.filter(d => d.type === "lvmVg" && allAvailable(d.physicalVolumes));

return [...availableDevices, ...mds, ...vgs];
}

/**
* Gets the list of meaningful mount points for the selected product
*
Expand Down
2 changes: 1 addition & 1 deletion web/src/components/core/ExpandableSelector.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ const sanitizeSelection = (selection, allowMultiple) => {
* @property {(item: object) => boolean} [itemSelectable=() => true] - Whether an item will be selectable or not.
* @property {(item: object) => (string|undefined)} [itemClassNames=() => ""] - Callback that allows adding additional CSS class names to item row.
* @property {object[]} [itemsSelected=[]] - Collection of selected items.
* @property {string[]} [initialExpandedKeys=[]] - Ids of initially expanded items.
* @property {any[]} [initialExpandedKeys=[]] - Ids of initially expanded items.
* @property {(selection: Array<object>) => void} [onSelectionChange=noop] - Callback to be triggered when selection changes.
*
* @typedef {ExpandableSelectorBaseProps & TableProps & HTMLTableProps} ExpandableSelectorProps
Expand Down
6 changes: 3 additions & 3 deletions web/src/components/storage/BootConfigField.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ const Button = ({ isBold = false, onClick }) => {
* @param {boolean} props.configureBoot
* @param {StorageDevice|undefined} props.bootDevice
* @param {StorageDevice|undefined} props.defaultBootDevice
* @param {StorageDevice[]} props.devices
* @param {StorageDevice[]} props.availableDevices
* @param {boolean} props.isLoading
* @param {(boot: BootConfig) => void} props.onChange
*
Expand All @@ -72,7 +72,7 @@ export default function BootConfigField({
configureBoot,
bootDevice,
defaultBootDevice,
devices,
availableDevices,
isLoading,
onChange
}) {
Expand Down Expand Up @@ -113,7 +113,7 @@ export default function BootConfigField({
configureBoot={configureBoot}
bootDevice={bootDevice}
defaultBootDevice={defaultBootDevice}
devices={devices}
availableDevices={availableDevices}
onAccept={onAccept}
onCancel={closeDialog}
/>
Expand Down
6 changes: 3 additions & 3 deletions web/src/components/storage/BootSelectionDialog.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ const RadioOption = ({ id, onChange, defaultChecked, children }) => {
* @param {boolean} props.configureBoot - Whether the boot is configurable
* @param {StorageDevice|undefined} props.bootDevice - Currently selected booting device.
* @param {StorageDevice|undefined} props.defaultBootDevice - Default booting device.
* @param {StorageDevice[]} props.devices - Devices that user can select to boot from.
* @param {StorageDevice[]} props.availableDevices - Devices that user can select to boot from.
* @param {boolean} [props.isOpen=false] - Whether the dialog is visible or not.
* @param {function} [props.onCancel=noop]
* @param {(boot: Boot) => void} [props.onAccept=noop]
Expand All @@ -75,7 +75,7 @@ export default function BootSelectionDialog({
configureBoot: configureBootProp,
bootDevice: bootDeviceProp,
defaultBootDevice,
devices,
availableDevices,
isOpen,
onCancel = noop,
onAccept = noop,
Expand Down Expand Up @@ -161,7 +161,7 @@ partitions in the appropriate disk."
</div>
<DevicesFormSelect
aria-label={_("Choose a disk for placing the boot loader")}
devices={devices}
devices={availableDevices}
selectedDevice={bootDevice}
onChange={setBootDevice}
isDisabled={!isBootManual}
Expand Down
2 changes: 1 addition & 1 deletion web/src/components/storage/DevicesManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ export default class DevicesManager {
* @returns {StorageDevice[]}
*/
usedDevices() {
const isTarget = (device) => device.isDrive || device.type === "lvmVg";
const isTarget = (device) => device.isDrive || ["md", "lvmVg"].includes(device.type);

// Check in system devices to detect removals.
const targetSystem = this.system.filter(isTarget);
Expand Down
63 changes: 34 additions & 29 deletions web/src/components/storage/PartitionsField.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -328,21 +328,21 @@ const VolumeActions = ({ volume, onEdit, onResetLocation, onLocation, onDelete }
* @param {Volume} [props.volume] - Volume to show
* @param {Volume[]} [props.volumes] - List of current volumes
* @param {Volume[]} [props.templates] - List of available templates
* @param {StorageDevice[]} [props.devices=[]] - Devices available for installation
* @param {ProposalTarget} [props.target] - Installation target
* @param {StorageDevice} [props.targetDevice] - Device selected for installation, if target is a disk
* @param {StorageDevice[]} [props.volumeDevices=[]] - Devices available for installation
* @param {ProposalTarget} [props.target]
* @param {StorageDevice[]} [props.targetDevices] - Device selected for installation, if target is a disk
* @param {boolean} props.isLoading - Whether to show the row as loading
* @param {(volume: Volume) => void} [props.onEdit=noop] - Function to use for editing the volume
* @param {(volume: Volume) => void} [props.onDelete=noop] - Function to use for deleting the volume
* @param {() => void} [props.onDelete=noop] - Function to use for deleting the volume
*/
const VolumeRow = ({
columns,
volume,
volumes,
templates,
devices,
volumeDevices,
target,
targetDevice,
targetDevices,
isLoading,
onEdit = noop,
onDelete = noop
Expand Down Expand Up @@ -412,9 +412,9 @@ const VolumeRow = ({
<VolumeLocationDialog
isOpen
volume={volume}
devices={devices}
target={target}
targetDevice={targetDevice}
volumes={volumes}
volumeDevices={volumeDevices}
targetDevices={targetDevices}
onAccept={acceptForm}
onCancel={closeDialog}
/>
Expand All @@ -431,18 +431,18 @@ const VolumeRow = ({
* @param {object} props
* @param {Volume[]} props.volumes - Volumes to show
* @param {Volume[]} props.templates - List of available templates
* @param {StorageDevice[]} props.devices - Devices available for installation
* @param {ProposalTarget} props.target - Installation target
* @param {StorageDevice|undefined} props.targetDevice - Device selected for installation, if target is a disk
* @param {StorageDevice[]} props.volumeDevices
* @param {ProposalTarget} props.target
* @param {StorageDevice[]} props.targetDevices
* @param {boolean} props.isLoading - Whether to show the table as loading
* @param {(volumes: Volume[]) => void} props.onVolumesChange - Function to submit changes in volumes
*/
const VolumesTable = ({
volumes,
templates,
devices,
volumeDevices,
target,
targetDevice,
targetDevices,
isLoading,
onVolumesChange
}) => {
Expand Down Expand Up @@ -481,9 +481,9 @@ const VolumesTable = ({
volume={volume}
volumes={volumes}
templates={templates}
devices={devices}
volumeDevices={volumeDevices}
target={target}
targetDevice={targetDevice}
targetDevices={targetDevices}
isLoading={isLoading}
onEdit={editVolume}
onDelete={() => deleteVolume(volume)}
Expand Down Expand Up @@ -608,9 +608,10 @@ const AddVolumeButton = ({ options, onClick }) => {
* @param {object} props
* @param {Volume[]} props.volumes
* @param {Volume[]} props.templates
* @param {StorageDevice[]} props.devices
* @param {StorageDevice[]} props.availableDevices
* @param {StorageDevice[]} props.volumeDevices
* @param {ProposalTarget} props.target
* @param {StorageDevice|undefined} props.targetDevice
* @param {StorageDevice[]} props.targetDevices
* @param {boolean} props.configureBoot
* @param {StorageDevice|undefined} props.bootDevice
* @param {StorageDevice|undefined} props.defaultBootDevice
Expand All @@ -621,9 +622,10 @@ const AddVolumeButton = ({ options, onClick }) => {
const Advanced = ({
volumes,
templates,
devices,
availableDevices,
volumeDevices,
target,
targetDevice,
targetDevices,
configureBoot,
bootDevice,
defaultBootDevice,
Expand Down Expand Up @@ -713,9 +715,9 @@ const Advanced = ({
<VolumesTable
volumes={volumes}
templates={templates}
devices={devices}
volumeDevices={volumeDevices}
target={target}
targetDevice={targetDevice}
targetDevices={targetDevices}
onVolumesChange={onVolumesChange}
isLoading={isLoading}
/>
Expand Down Expand Up @@ -744,7 +746,7 @@ const Advanced = ({
configureBoot={configureBoot}
bootDevice={bootDevice}
defaultBootDevice={defaultBootDevice}
devices={devices}
availableDevices={availableDevices}
isLoading={isLoading}
onChange={onBootChange}
/>
Expand All @@ -762,9 +764,10 @@ const Advanced = ({
* @typedef {object} PartitionsFieldProps
* @property {Volume[]} volumes - Volumes to show
* @property {Volume[]} templates - Templates to use for new volumes
* @property {StorageDevice[]} devices - Devices available for installation
* @property {StorageDevice[]} availableDevices - Devices available for installation
* @property {StorageDevice[]} volumeDevices
* @property {ProposalTarget} target - Installation target
* @property {StorageDevice|undefined} targetDevice - Device selected for installation, if target is a disk
* @property {StorageDevice[]} targetDevices
* @property {boolean} configureBoot - Whether to configure boot partitions.
* @property {StorageDevice|undefined} bootDevice - Device to use for creating boot partitions.
* @property {StorageDevice|undefined} defaultBootDevice - Default device for boot partitions if no device has been indicated yet.
Expand All @@ -781,9 +784,10 @@ const Advanced = ({
export default function PartitionsField({
volumes,
templates,
devices,
availableDevices,
volumeDevices,
target,
targetDevice,
targetDevices,
configureBoot,
bootDevice,
defaultBootDevice,
Expand All @@ -807,9 +811,10 @@ export default function PartitionsField({
<Advanced
volumes={volumes}
templates={templates}
devices={devices}
volumeDevices={volumeDevices}
availableDevices={availableDevices}
target={target}
targetDevice={targetDevice}
targetDevices={targetDevices}
configureBoot={configureBoot}
bootDevice={bootDevice}
defaultBootDevice={defaultBootDevice}
Expand Down
16 changes: 15 additions & 1 deletion web/src/components/storage/ProposalPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { IDLE } from "~/client/status";
const initialState = {
loading: true,
availableDevices: [],
volumeDevices: [],
volumeTemplates: [],
encryptionMethods: [],
settings: {},
Expand All @@ -60,6 +61,11 @@ const reducer = (state, action) => {
return { ...state, availableDevices };
}

case "UPDATE_VOLUME_DEVICES": {
const { volumeDevices } = action.payload;
return { ...state, volumeDevices };
}

case "UPDATE_ENCRYPTION_METHODS": {
const { encryptionMethods } = action.payload;
return { ...state, encryptionMethods };
Expand Down Expand Up @@ -105,6 +111,10 @@ export default function ProposalPage() {
return await cancellablePromise(client.proposal.getAvailableDevices());
}, [client, cancellablePromise]);

const loadVolumeDevices = useCallback(async () => {
return await cancellablePromise(client.proposal.getVolumeDevices());
}, [client, cancellablePromise]);

const loadEncryptionMethods = useCallback(async () => {
return await cancellablePromise(client.proposal.getEncryptionMethods());
}, [client, cancellablePromise]);
Expand Down Expand Up @@ -153,6 +163,9 @@ export default function ProposalPage() {
const availableDevices = await loadAvailableDevices();
dispatch({ type: "UPDATE_AVAILABLE_DEVICES", payload: { availableDevices } });

const volumeDevices = await loadVolumeDevices();
dispatch({ type: "UPDATE_VOLUME_DEVICES", payload: { volumeDevices } });

const encryptionMethods = await loadEncryptionMethods();
dispatch({ type: "UPDATE_ENCRYPTION_METHODS", payload: { encryptionMethods } });

Expand All @@ -169,7 +182,7 @@ export default function ProposalPage() {
dispatch({ type: "UPDATE_ERRORS", payload: { errors } });

if (result !== undefined) dispatch({ type: "STOP_LOADING" });
}, [calculateProposal, cancellablePromise, client, loadAvailableDevices, loadDevices, loadEncryptionMethods, loadErrors, loadProposalResult, loadVolumeTemplates]);
}, [calculateProposal, cancellablePromise, client, loadAvailableDevices, loadVolumeDevices, loadDevices, loadEncryptionMethods, loadErrors, loadProposalResult, loadVolumeTemplates]);

const calculate = useCallback(async (settings) => {
dispatch({ type: "START_LOADING" });
Expand Down Expand Up @@ -231,6 +244,7 @@ export default function ProposalPage() {
/>
<ProposalSettingsSection
availableDevices={state.availableDevices}
volumeDevices={state.volumeDevices}
encryptionMethods={state.encryptionMethods}
volumeTemplates={state.volumeTemplates}
settings={state.settings}
Expand Down
8 changes: 4 additions & 4 deletions web/src/components/storage/ProposalResultTable.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const MountPoint = ({ item }) => {
* @param {TableItem} props.item
* @param {DevicesManager} props.devicesManager
*/
const ExtendedDeviceDetails = ({ item, devicesManager }) => {
const DeviceCustomDetails = ({ item, devicesManager }) => {
const isNew = () => {
const device = toStorageDevice(item);
if (!device) return false;
Expand All @@ -83,7 +83,7 @@ const ExtendedDeviceDetails = ({ item, devicesManager }) => {
* @param {TableItem} props.item
* @param {DevicesManager} props.devicesManager
*/
const ExtendedDeviceSize = ({ item, devicesManager }) => {
const DeviceCustomSize = ({ item, devicesManager }) => {
const device = toStorageDevice(item);
const isResized = device && devicesManager.isShrunk(device);
const sizeBefore = isResized ? devicesManager.systemDevice(device.sid).size : item.size;
Expand Down Expand Up @@ -121,12 +121,12 @@ const columns = (devicesManager) => {

/** @type {() => (item: TableItem) => React.ReactNode} */
const detailsRender = () => {
return (item) => <ExtendedDeviceDetails item={item} devicesManager={devicesManager} />;
return (item) => <DeviceCustomDetails item={item} devicesManager={devicesManager} />;
};

/** @type {() => (item: TableItem) => React.ReactNode} */
const sizeRender = () => {
return (item) => <ExtendedDeviceSize item={item} devicesManager={devicesManager} />;
return (item) => <DeviceCustomSize item={item} devicesManager={devicesManager} />;
};

return [
Expand Down
9 changes: 7 additions & 2 deletions web/src/components/storage/ProposalSettingsSection.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import SpacePolicyField from "~/components/storage/SpacePolicyField";
* @typedef {object} ProposalSettingsSectionProps
* @property {ProposalSettings} settings
* @property {StorageDevice[]} availableDevices
* @property {StorageDevice[]} volumeDevices
* @property {String[]} encryptionMethods
* @property {Volume[]} volumeTemplates
* @property {boolean} [isLoading=false]
Expand All @@ -57,6 +58,7 @@ import SpacePolicyField from "~/components/storage/SpacePolicyField";
export default function ProposalSettingsSection({
settings,
availableDevices,
volumeDevices,
encryptionMethods,
volumeTemplates,
isLoading = false,
Expand Down Expand Up @@ -112,6 +114,8 @@ export default function ProposalSettingsSection({
const defaultBootDevice = findDevice(settings.defaultBootDevice);
const spacePolicy = SPACE_POLICIES.find(p => p.id === settings.spacePolicy);

const targetDevices = compact([targetDevice, ...targetPVDevices]);

return (
<>
<Section title={_("Settings")}>
Expand All @@ -133,9 +137,10 @@ export default function ProposalSettingsSection({
<PartitionsField
volumes={volumes}
templates={volumeTemplates}
devices={availableDevices}
availableDevices={availableDevices}
volumeDevices={volumeDevices}
target={settings.target}
targetDevice={targetDevice}
targetDevices={targetDevices}
configureBoot={settings.configureBoot}
bootDevice={bootDevice}
defaultBootDevice={defaultBootDevice}
Expand Down
Loading

0 comments on commit 7fb343b

Please sign in to comment.