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
35 changes: 35 additions & 0 deletions web/src/components/storage/SpaceActionsTable.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { deviceChildren, gib } from "~/components/storage/utils";
import { plainRender } from "~/test-utils";
import SpaceActionsTable, { SpaceActionsTableProps } from "~/components/storage/SpaceActionsTable";
import { StorageDevice } from "~/types/storage";
import * as configModel from "~/api/storage/types/config-model";

const sda: StorageDevice = {
sid: 59,
Expand Down Expand Up @@ -80,6 +81,22 @@ sda.partitionTable = {
unusedSlots: [{ start: 3, size: gib(2) }],
};

const mockDrive: configModel.Drive = {
name: "/dev/sda",
partitions: [
{
name: "/dev/sda2",
mountPath: "swap",
filesystem: { reuse: false, default: true },
},
],
};

const mockUseConfigModelFn = jest.fn();
jest.mock("~/queries/storage/config-model", () => ({
useConfigModel: () => mockUseConfigModelFn(),
}));

/**
* Function to ask for the action of a device.
*
Expand All @@ -101,6 +118,8 @@ describe("SpaceActionsTable", () => {
deviceAction,
onActionChange: jest.fn(),
};

mockUseConfigModelFn.mockReturnValue({ drives: [] });
});

it("shows the devices to configure the space actions", () => {
Expand Down Expand Up @@ -141,6 +160,22 @@ describe("SpaceActionsTable", () => {
expect(sda2ShrinkButton).not.toBeDisabled();
});

describe("if a partition is going to be used", () => {
beforeEach(() => {
mockUseConfigModelFn.mockReturnValue({ drives: [mockDrive] });
});

it("disables shrink and delete actions for the partition", () => {
plainRender(<SpaceActionsTable {...props} />);

const sda2Row = screen.getByRole("row", { name: /sda2/ });
const sda2ShrinkButton = within(sda2Row).getByRole("button", { name: "Allow shrink" });
const sda2DeleteButton = within(sda2Row).getByRole("button", { name: "Delete" });
expect(sda2ShrinkButton).toBeDisabled();
expect(sda2DeleteButton).toBeDisabled();
});
});

it("allows to change the action", async () => {
const { user } = plainRender(<SpaceActionsTable {...props} />);

Expand Down
41 changes: 35 additions & 6 deletions web/src/components/storage/SpaceActionsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import {
import { sprintf } from "sprintf-js";

import { _ } from "~/i18n";
import { deviceSize } from "~/components/storage/utils";
import { deviceSize, formattedPath } from "~/components/storage/utils";
import {
DeviceName,
DeviceDetails,
Expand All @@ -43,8 +43,25 @@ import {
} from "~/components/storage/device-utils";
import { Icon } from "~/components/layout";
import { PartitionSlot, SpacePolicyAction, StorageDevice } from "~/types/storage";
import { configModel } from "~/api/storage/types";
import { TreeTableColumn } from "~/components/core/TreeTable";
import { Table, Td, Th, Tr, Thead, Tbody } from "@patternfly/react-table";
import { useConfigModel } from "~/queries/storage/config-model";

const isUsedPartition = (partition: configModel.Partition): boolean => {
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.

NP: these are the things I still envision in a storage utils module. But it's hard to convince you guys.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Is not that we don't agree. There is also a comment right below that like saying tht we need to reconsider all that. It currently feels like dealing with the old YaST huge storage "maps" (pre storage-ng).

return partition.filesystem !== undefined || partition.alias !== undefined;
};

// FIXME: there is too much logic here. This is one of those cases that should be considered
Comment thread
dgdavid marked this conversation as resolved.
// when restructuring the hooks and queries.
const useReusedPartition = (name: string): configModel.Partition | undefined => {
const model = useConfigModel();

if (!model || !name) return;

const allPartitions = model.drives.flatMap((d) => d.partitions);
return allPartitions.find((p) => p.name === name && isUsedPartition(p));
};

/**
* Info about the device.
Expand All @@ -53,6 +70,14 @@ import { Table, Td, Th, Tr, Thead, Tbody } from "@patternfly/react-table";
const DeviceInfoContent = ({ device }: { device: StorageDevice }) => {
const minSize = device.shrinking?.supported;

const reused = useReusedPartition(device.name);
if (reused) {
if (!reused.mountPath) return _("The device will be used by the new system.");

// TRANSLATORS: %s is a mount path like "/home".
return sprintf(_("The device will be mounted at %s."), formattedPath(reused.mountPath));
}

if (minSize) {
const recoverable = device.size - minSize;
return sprintf(
Expand Down Expand Up @@ -114,8 +139,11 @@ const DeviceActionSelector = ({
}) => {
const changeAction = (value) => onChange({ deviceName: device.name, value });

const isResizeDisabled = device.shrinking?.supported === undefined;
const hasInfo = device.shrinking !== undefined;
const forceKeep = !!useReusedPartition(device.name);
const isResizeDisabled = forceKeep || device.shrinking?.supported === undefined;
const isDeleteDisabled = forceKeep;
const hasInfo = forceKeep || device.shrinking !== undefined;
const adjustedAction = forceKeep ? "keep" : action;

return (
<Flex>
Expand All @@ -124,20 +152,21 @@ const DeviceActionSelector = ({
<ToggleGroupItem
text="Do not modify"
buttonId="not-modify"
isSelected={action === "keep"}
isSelected={adjustedAction === "keep"}
onChange={() => changeAction("keep")}
/>
<ToggleGroupItem
text="Allow shrink"
buttonId="resize"
isDisabled={isResizeDisabled}
isSelected={action === "resizeIfNeeded"}
isSelected={adjustedAction === "resizeIfNeeded"}
onChange={() => changeAction("resizeIfNeeded")}
/>
<ToggleGroupItem
text="Delete"
buttonId="delete"
isSelected={action === "delete"}
isDisabled={isDeleteDisabled}
isSelected={adjustedAction === "delete"}
onChange={() => changeAction("delete")}
/>
</ToggleGroup>
Expand Down