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
6 changes: 6 additions & 0 deletions web/package/agama-web-ui.changes
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
-------------------------------------------------------------------
Tue Feb 25 15:57:49 UTC 2025 - Ancor Gonzalez Sosa <ancor@suse.com>

- Display the file system labels in most selectors for disks and
partitions (gh#agama-project/agama#2070).

-------------------------------------------------------------------
Tue Feb 25 13:08:43 UTC 2025 - Imobach Gonzalez Sosa <igonzalezsosa@suse.com>

Expand Down
14 changes: 13 additions & 1 deletion web/src/components/storage/AddExistingDeviceMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ import {
MenuToggleElement,
MenuToggle,
Divider,
Split,
Flex,
Label,
} from "@patternfly/react-core";
import { MenuHeader } from "~/components/core";
import MenuDeviceDescription from "./MenuDeviceDescription";
Expand Down Expand Up @@ -90,7 +93,16 @@ export default function AddExistingDeviceMenu() {
description={<MenuDeviceDescription device={device} />}
onClick={() => modelHook.addDrive(device.name)}
>
{deviceLabel(device)}
<Split hasGutter>
Comment thread
dgdavid marked this conversation as resolved.
{deviceLabel(device)}
<Flex columnGap={{ default: "columnGapXs" }}>
{device.systems.map((s, i) => (
<Label key={i} isCompact>
{s}
</Label>
))}
</Flex>
</Split>
</DropdownItem>
))}
</DropdownGroup>
Expand Down
32 changes: 25 additions & 7 deletions web/src/components/storage/DriveEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import { STORAGE as PATHS } from "~/routes/paths";
import { useDrive } from "~/queries/storage/config-model";
import * as driveUtils from "~/components/storage/utils/drive";
import * as partitionUtils from "~/components/storage/utils/partition";
import { typeDescription, contentDescription } from "~/components/storage/utils/device";
import { contentDescription } from "~/components/storage/utils/device";
import { Icon } from "../layout";
import { MenuHeader } from "~/components/core";
import MenuDeviceDescription from "./MenuDeviceDescription";
Expand Down Expand Up @@ -273,6 +273,26 @@ const SearchSelectorIntro = ({ drive }: { drive: configModel.Drive }) => {
return <MenuHeader title={mainText()} description={extraText()} />;
};

const DiskSelectorTitle = ({ device, isSelected = false }) => {
const Name = () => (isSelected ? <b>{deviceLabel(device)}</b> : deviceLabel(device));
const Systems = () => (
<Flex columnGap={{ default: "columnGapXs" }}>
{device.systems.map((s, i) => (
<Label key={i} isCompact>
{s}
</Label>
))}
</Flex>
);

return (
<Split hasGutter>
<Name />
<Systems />
</Split>
);
};

const SearchSelectorMultipleOptions = ({ selected, withNewVg = false, onChange }) => {
const navigate = useNavigate();
const devices = useAvailableDevices();
Expand All @@ -296,9 +316,7 @@ const SearchSelectorMultipleOptions = ({ selected, withNewVg = false, onChange }
return (
<>
{devices.map((device) => {
const isSelected = device === selected;
// FIXME: use PF/Content with #component prop instead when migrating to PF6
const Name = () => (isSelected ? <b>{deviceLabel(device)}</b> : deviceLabel(device));
const isSelected = device.sid === selected.sid;

return (
<MenuItem
Expand All @@ -308,7 +326,7 @@ const SearchSelectorMultipleOptions = ({ selected, withNewVg = false, onChange }
description={<MenuDeviceDescription device={device} />}
onClick={() => onChange(device.name)}
>
<Name />
<DiskSelectorTitle device={device} isSelected={isSelected} />
</MenuItem>
);
})}
Expand All @@ -323,9 +341,9 @@ const SearchSelectorSingleOption = ({ selected }) => {
isSelected
key={selected.sid}
itemId={selected.sid}
description={<>{typeDescription(selected)}</>}
description={<MenuDeviceDescription device={selected} />}
>
<b>{deviceLabel(selected)}</b>
<DiskSelectorTitle device={selected} isSelected />
</MenuItem>
);
};
Expand Down
16 changes: 10 additions & 6 deletions web/src/components/storage/MenuDeviceDescription.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,12 @@
*/

import React from "react";
import { Stack, Split, Label } from "@patternfly/react-core";
import { typeDescription, contentDescription } from "~/components/storage/utils/device";
import { Stack, Flex, Split, Label } from "@patternfly/react-core";
import {
typeDescription,
contentDescription,
filesystemLabels,
} from "~/components/storage/utils/device";
import { StorageDevice } from "~/types/storage";

/**
Expand All @@ -38,13 +42,13 @@ export default function MenuDeviceDescription({ device }: { device: StorageDevic
<span>{typeDescription(device)}</span>
<span>{contentDescription(device)}</span>
</Split>
<Split hasGutter>
{device.systems.map((s, i) => (
<Label key={i} isCompact>
<Flex columnGap={{ default: "columnGapXs" }}>
{filesystemLabels(device).map((s, i) => (
<Label key={i} variant="outline" isCompact>
{s}
</Label>
Comment thread
dgdavid marked this conversation as resolved.
))}
</Split>
</Flex>
</Stack>
);
}
24 changes: 20 additions & 4 deletions web/src/components/storage/PartitionPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,13 @@ import {
FormHelperText,
HelperText,
HelperTextItem,
Label,
SelectGroup,
SelectList,
SelectOption,
SelectOptionProps,
Split,
SplitItem,
Stack,
TextInput,
} from "@patternfly/react-core";
Expand All @@ -54,7 +56,13 @@ import {
editPartition,
} from "~/queries/storage/config-model";
import { StorageDevice } from "~/types/storage";
import { baseName, deviceSize, filesystemLabel, parseToBytes } from "~/components/storage/utils";
import {
baseName,
deviceSize,
deviceLabel,
filesystemLabel,
parseToBytes,
} from "~/components/storage/utils";
import { _, formatList } from "~/i18n";
import { sprintf } from "sprintf-js";
import { configModel } from "~/api/storage/types";
Expand Down Expand Up @@ -491,10 +499,18 @@ type PartitionDescriptionProps = {
};

function PartitionDescription({ partition }: PartitionDescriptionProps): React.ReactNode {
const label = partition.filesystem?.label;

return (
<Split hasGutter>
<span>{partition.description}</span>
<span>{deviceSize(partition.size)}</span>
<SplitItem>{partition.description}</SplitItem>
{label && (
<SplitItem>
<Label isCompact variant="outline">
{label}
</Label>
</SplitItem>
Comment on lines 505 to +512
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about still using the Flex with custom size approach?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I like the separation given by Split here.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, go ahead.

As commented in IRC, it should not be a question of taste but consistence and correct abstractions to improve maintenance and those things that we use to make so important in the backend side 😉

)}
</Split>
);
}
Expand All @@ -515,7 +531,7 @@ function TargetOptions(): React.ReactNode {
value={partition.name}
description={<PartitionDescription partition={partition} />}
>
{partition.name}
{deviceLabel(partition)}
</SelectOption>
))}
{partitions.length === 0 && (
Expand Down
15 changes: 14 additions & 1 deletion web/src/components/storage/utils/device.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import { _ } from "~/i18n";
import { sprintf } from "sprintf-js";
import { StorageDevice } from "~/types/storage";
import { compact } from "~/utils";

/*
* Description of the device type.
Expand Down Expand Up @@ -91,4 +92,16 @@ const contentDescription = (device: StorageDevice): string => {
return device.description;
};

export { typeDescription, contentDescription };
/*
* Labels of the filesystems included at the device
*/
const filesystemLabels = (device: StorageDevice): string[] => {
if (device.partitionTable) {
return compact(device.partitionTable.partitions.map((p) => p.filesystem?.label));
}

const label = device.filesystem?.label;
return label ? [label] : [];
};

export { typeDescription, contentDescription, filesystemLabels };