Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion service/lib/agama/storage/config_checkers/alias.rb
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def formatted_issue
target_users = storage_config.target_users(config.alias)
any_user = (users + target_users).any?

return unless users.any? || target_users.any?
return unless any_user

error(
format(
Expand Down
39 changes: 6 additions & 33 deletions web/src/components/storage/ConfigEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import Text from "~/components/core/Text";
import DriveEditor from "~/components/storage/DriveEditor";
import VolumeGroupEditor from "~/components/storage/VolumeGroupEditor";
import MdRaidEditor from "~/components/storage/MdRaidEditor";
import { useDevices } from "~/hooks/api/system/storage";
import { useReset } from "~/hooks/api/config/storage";
import ConfigureDeviceMenu from "./ConfigureDeviceMenu";
import { useModel } from "~/hooks/storage/model";
Expand Down Expand Up @@ -57,24 +56,8 @@ const NoDevicesConfiguredAlert = () => {
);
};

/**
* @fixme Adapt components (DriveEditor, MdRaidEditor, etc) to receive a list name and an index
* instead of a device object. Each component will retrieve the device from the model if needed.
*
* That will allow to:
* * Simplify the model types (list and listIndex properties are not needed).
* * All the components (DriveEditor, PartitionPage, etc) work in a similar way. They receive a
* list and an index and each component retrieves the device from the model if needed.
* * The components always have all the needed info for generating an url.
* * The partitions and logical volumes can also be referenced by an index, so it opens the door
* to have partitions and lvs without a mount path.
*
* These changes will be done once creating partitions without a mount path is needed (e.g., for
* manually creating physical volumes).
*/
export default function ConfigEditor() {
const model = useModel();
const devices = useDevices();
const drives = model.drives;
const mdRaids = model.mdRaids;
const volumeGroups = model.volumeGroups;
Expand All @@ -89,22 +72,12 @@ export default function ConfigEditor() {
{volumeGroups.map((vg, i) => {
return <VolumeGroupEditor key={`vg-${i}`} vg={vg} />;
})}
{mdRaids.map((raid, i) => {
const device = devices.find((d) => d.name === raid.name);

return <MdRaidEditor key={`md-${i}`} raid={raid} raidDevice={device} />;
})}
{drives.map((drive, i) => {
const device = devices.find((d) => d.name === drive.name);

/**
* @fixme Make DriveEditor to work when the device is not found (e.g., after disabling
* a iSCSI device).
*/
if (device === undefined) return null;

return <DriveEditor key={`drive-${i}`} drive={drive} driveDevice={device} />;
})}
{mdRaids.map((_, i) => (
<MdRaidEditor key={`md-${i}`} index={i} />
))}
{drives.map((_, i) => (
<DriveEditor key={`drive-${i}`} index={i} />
))}
</DataList>
<Flex>
<ConfigureDeviceMenu />
Expand Down
21 changes: 12 additions & 9 deletions web/src/components/storage/DeviceEditorContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,25 @@ import UnusedMenu from "~/components/storage/UnusedMenu";
import FilesystemMenu from "~/components/storage/FilesystemMenu";
import PartitionsSection from "~/components/storage/PartitionsSection";
import SpacePolicyMenu from "~/components/storage/SpacePolicyMenu";
import type { model } from "~/storage";
import type { storage } from "~/api/system";
import { useDevice } from "~/hooks/storage/model";

type DeviceEditorContentProps = { deviceModel: model.Drive | model.MdRaid; device: storage.Device };
type DeviceEditorContentProps = {
collection: "drives" | "mdRaids";
index: number;
};

export default function DeviceEditorContent({
deviceModel,
device,
collection,
index,
}: DeviceEditorContentProps): React.ReactNode {
if (!deviceModel.isUsed) return <UnusedMenu deviceModel={deviceModel} />;
const deviceModel = useDevice(collection, index);
if (!deviceModel.isUsed) return <UnusedMenu collection={collection} index={index} />;

return (
<>
{deviceModel.filesystem && <FilesystemMenu deviceModel={deviceModel} />}
{!deviceModel.filesystem && <PartitionsSection device={deviceModel} />}
{!deviceModel.filesystem && <SpacePolicyMenu modelDevice={deviceModel} device={device} />}
{deviceModel.filesystem && <FilesystemMenu collection={collection} index={index} />}
{!deviceModel.filesystem && <PartitionsSection collection={collection} index={index} />}
{!deviceModel.filesystem && <SpacePolicyMenu collection={collection} index={index} />}
</>
);
}
33 changes: 22 additions & 11 deletions web/src/components/storage/DriveEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,14 @@ import { CustomToggleProps } from "~/components/core/MenuButton";
import { useDeleteDrive } from "~/hooks/storage/drive";
import { Button, Flex, FlexItem } from "@patternfly/react-core";
import textStyles from "@patternfly/react-styles/css/utilities/Text/text";
import { useDrive } from "~/hooks/storage/model";
import { useDevice } from "~/hooks/api/system/storage";
import type { model } from "~/storage";
import type { storage } from "~/api/system";

type DriveDeviceMenuProps = {
drive: model.Drive;
selected: storage.Device;
};
import type { storage as system } from "~/api/system";

type DriveDeviceMenuToggleProps = CustomToggleProps & {
drive: model.Drive | model.MdRaid;
device: storage.Device;
device: system.Device;
};

const DriveDeviceMenuToggle = forwardRef(
Expand Down Expand Up @@ -71,6 +68,11 @@ const DriveDeviceMenuToggle = forwardRef(
},
);

type DriveDeviceMenuProps = {
drive: model.Drive;
selected: system.Device;
};

/**
* Internal component that renders generic actions available for a Drive device.
*/
Expand All @@ -88,16 +90,25 @@ const DriveDeviceMenu = ({ drive, selected }: DriveDeviceMenuProps) => {
);
};

export type DriveEditorProps = { drive: model.Drive; driveDevice: storage.Device };
export type DriveEditorProps = { index: number };

/**
* Component responsible for displaying detailed information and available actions
* related to a specific Drive device within the storage ConfigEditor.
*/
export default function DriveEditor({ drive, driveDevice }: DriveEditorProps) {
export default function DriveEditor({ index }: DriveEditorProps) {
const driveModel = useDrive(index);
const drive = useDevice(driveModel.name);

/**
* @fixme Make DriveEditor to work when the device is not found (e.g., after disabling
* a iSCSI device).
*/
if (drive === undefined) return null;

return (
<ConfigEditorItem header={<DriveDeviceMenu drive={drive} selected={driveDevice} />}>
<DeviceEditorContent deviceModel={drive} device={driveDevice} />
<ConfigEditorItem header={<DriveDeviceMenu drive={driveModel} selected={drive} />}>
<DeviceEditorContent collection="drives" index={index} />
</ConfigEditorItem>
);
}
19 changes: 13 additions & 6 deletions web/src/components/storage/FilesystemMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,11 @@ import MenuButton, { CustomToggleProps } from "~/components/core/MenuButton";
import { STORAGE as PATHS } from "~/routes/paths";
import { model } from "~/storage";
import { filesystemType, formattedPath } from "~/components/storage/utils";
import { useDevice } from "~/hooks/storage/model";
import { sprintf } from "sprintf-js";
import { _ } from "~/i18n";

type FilesystemMenuProps = { deviceModel: model.Drive | model.MdRaid };

function deviceDescription(deviceModel: FilesystemMenuProps["deviceModel"]): string {
function deviceDescription(deviceModel: model.Drive | model.MdRaid): string {
const fs = filesystemType(deviceModel.filesystem);
const mountPath = deviceModel.mountPath;
const reuse = deviceModel.filesystem.reuse;
Expand Down Expand Up @@ -82,10 +81,18 @@ const FilesystemMenuToggle = forwardRef(
},
);

export default function FilesystemMenu({ deviceModel }: FilesystemMenuProps): React.ReactNode {
type FilesystemMenuProps = {
collection: "drives" | "mdRaids";
index: number;
};

export default function FilesystemMenu({
collection,
index,
}: FilesystemMenuProps): React.ReactNode {
const navigate = useNavigate();
const { list, listIndex } = deviceModel;
const editFilesystemPath = generatePath(PATHS.formatDevice, { list, listIndex });
const deviceModel = useDevice(collection, index);
const editFilesystemPath = generatePath(PATHS.formatDevice, { collection, index });

return (
<MenuButton
Expand Down
40 changes: 22 additions & 18 deletions web/src/components/storage/FormattableDevicePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,13 @@ import { Page, SelectWrapper as Select } from "~/components/core/";
import { SelectWrapperProps as SelectProps } from "~/components/core/SelectWrapper";
import SelectTypeaheadCreatable from "~/components/core/SelectTypeaheadCreatable";
import { useAddFilesystem } from "~/hooks/storage/filesystem";
import { useModel, useMissingMountPaths } from "~/hooks/storage/model";
import { useDevices, useVolumeTemplate } from "~/hooks/api/system/storage";
import {
useModel,
useMissingMountPaths,
useDrive as useDriveModel,
useMdRaid as useMdRaidModel,
} from "~/hooks/storage/model";
import { useDevice, useVolumeTemplate } from "~/hooks/api/system/storage";
import { data, model } from "~/storage";
import { deviceBaseName, filesystemLabel } from "~/components/storage/utils";
import { _ } from "~/i18n";
Expand Down Expand Up @@ -138,20 +143,19 @@ function toFormValue(deviceModel: DeviceModel): FormValue {
};
}

function useDeviceModel(): DeviceModel {
const { list, listIndex } = useParams();
const model = useModel();
return model[list].at(listIndex);
function useDeviceModelFromParams(): model.Drive | model.MdRaid | null {
const { collection, index } = useParams();
const deviceModel = collection === "drives" ? useDriveModel : useMdRaidModel;
return deviceModel(Number(index));
}

function useDevice(): system.Device {
const deviceModel = useDeviceModel();
const devices = useDevices();
return devices.find((d) => d.name === deviceModel.name);
function useDeviceFromParams(): system.Device {
const deviceModel = useDeviceModelFromParams();
return useDevice(deviceModel.name);
}

function useCurrentFilesystem(): string | null {
const device = useDevice();
const device = useDeviceFromParams();
return device?.filesystem?.type || null;
}

Expand All @@ -161,14 +165,14 @@ function useDefaultFilesystem(mountPoint: string): string {
}

function useInitialFormValue(): FormValue | null {
const deviceModel = useDeviceModel();
const deviceModel = useDeviceModelFromParams();
return React.useMemo(() => (deviceModel ? toFormValue(deviceModel) : null), [deviceModel]);
}

/** Unused predefined mount points. Includes the currently used mount point when editing. */
function useUnusedMountPoints(): string[] {
const unusedMountPaths = useMissingMountPaths();
const deviceModel = useDeviceModel();
const deviceModel = useDeviceModelFromParams();
return compact([deviceModel?.mountPath, ...unusedMountPaths]);
}

Expand Down Expand Up @@ -204,7 +208,7 @@ function useUsableFilesystems(mountPoint: string): string[] {
function useMountPointError(value: FormValue): Error | undefined {
const model = useModel();
const mountPoints = model?.getMountPaths() || [];
const deviceModel = useDeviceModel();
const deviceModel = useDeviceModelFromParams();
const mountPoint = value.mountPoint;

if (mountPoint === NO_VALUE) {
Expand Down Expand Up @@ -291,7 +295,7 @@ type FilesystemOptionsProps = {
};

function FilesystemOptions({ mountPoint }: FilesystemOptionsProps): React.ReactNode {
const device = useDevice();
const device = useDeviceFromParams();
const volume = useVolumeTemplate(mountPoint);
const defaultFilesystem = useDefaultFilesystem(mountPoint);
const usableFilesystems = useUsableFilesystems(mountPoint);
Expand Down Expand Up @@ -402,7 +406,8 @@ export default function FormattableDevicePage() {
const value = { mountPoint, filesystem, filesystemLabel };
const { errors, getVisibleError } = useErrors(value);

const device = useDeviceModel();
const { collection, index } = useParams();
const device = useDeviceModelFromParams();
const unusedMountPoints = useUnusedMountPoints();
const addFilesystem = useAddFilesystem();

Expand Down Expand Up @@ -436,8 +441,7 @@ export default function FormattableDevicePage() {

const onSubmit = () => {
const data = toData(value);
const { list, listIndex } = device;
addFilesystem(list, listIndex, data);
addFilesystem(collection, Number(index), data);
navigate(PATHS.root);
};

Expand Down
12 changes: 8 additions & 4 deletions web/src/components/storage/MdRaidEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import { CustomToggleProps } from "~/components/core/MenuButton";
import { useDeleteMdRaid } from "~/hooks/storage/md-raid";
import { Button, Flex, FlexItem } from "@patternfly/react-core";
import textStyles from "@patternfly/react-styles/css/utilities/Text/text";
import { useMdRaid } from "~/hooks/storage/model";
import { useDevice } from "~/hooks/api/system/storage";
import type { model } from "~/storage";
import type { storage } from "~/api/system";

Expand Down Expand Up @@ -88,16 +90,18 @@ const MdRaidDeviceMenu = ({ raid, selected }: MdRaidDeviceMenuProps): React.Reac
);
};

type MdRaidEditorProps = { raid: model.MdRaid; raidDevice: storage.Device };
type MdRaidEditorProps = { index: number };

/**
* Component responsible for displaying detailed information and available
* actions related to a specific MdRaid device within the storage ConfigEditor.
*/
export default function MdRaidEditor({ raid, raidDevice }: MdRaidEditorProps) {
export default function MdRaidEditor({ index }: MdRaidEditorProps) {
const raidModel = useMdRaid(index);
const raid = useDevice(raidModel.name);
return (
<ConfigEditorItem header={<MdRaidDeviceMenu raid={raid} selected={raidDevice} />}>
<DeviceEditorContent deviceModel={raid} device={raidDevice} />
<ConfigEditorItem header={<MdRaidDeviceMenu raid={raidModel} selected={raid} />}>
<DeviceEditorContent collection="mdRaids" index={index} />
</ConfigEditorItem>
);
}
Loading
Loading