diff --git a/web/src/components/storage/SpaceActionsTable.test.tsx b/web/src/components/storage/SpaceActionsTable.test.tsx
index 1d6a60ace2..1de9f9d53b 100644
--- a/web/src/components/storage/SpaceActionsTable.test.tsx
+++ b/web/src/components/storage/SpaceActionsTable.test.tsx
@@ -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,
@@ -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.
*
@@ -101,6 +118,8 @@ describe("SpaceActionsTable", () => {
deviceAction,
onActionChange: jest.fn(),
};
+
+ mockUseConfigModelFn.mockReturnValue({ drives: [] });
});
it("shows the devices to configure the space actions", () => {
@@ -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();
+
+ 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();
diff --git a/web/src/components/storage/SpaceActionsTable.tsx b/web/src/components/storage/SpaceActionsTable.tsx
index 196b3b41fa..7dd5221255 100644
--- a/web/src/components/storage/SpaceActionsTable.tsx
+++ b/web/src/components/storage/SpaceActionsTable.tsx
@@ -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,
@@ -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 => {
+ return partition.filesystem !== undefined || partition.alias !== undefined;
+};
+
+// FIXME: there is too much logic here. This is one of those cases that should be considered
+// 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.
@@ -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(
@@ -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 (
@@ -124,20 +152,21 @@ const DeviceActionSelector = ({
changeAction("keep")}
/>
changeAction("resizeIfNeeded")}
/>
changeAction("delete")}
/>