Skip to content

Commit

Permalink
feat: move file system forms to side panel (#5365)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jay-Topher authored Mar 21, 2024
1 parent 2bcd18b commit 0bf1d6f
Show file tree
Hide file tree
Showing 15 changed files with 500 additions and 234 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import configureStore from "redux-mock-store";

import DeleteFilesystem from "./DeleteFilesystem";

import { actions as machineActions } from "@/app/store/machine";
import type { RootState } from "@/app/store/root/types";
import * as factory from "@/testing/factories";
import { renderWithBrowserRouter, screen, userEvent } from "@/testing/utils";

const mockStore = configureStore<RootState>();
const filesystem = factory.nodeFilesystem({ mount_point: "/disk-fs/path" });
const disk = factory.nodeDisk({ filesystem, partitions: [] });
const machine = factory.machineDetails({
disks: [disk],
system_id: "abc123",
});
const state = factory.rootState({
machine: factory.machineState({
items: [machine],
statuses: factory.machineStatuses({
abc123: factory.machineStatus(),
}),
}),
});

it("renders a delete confirmation form", () => {
renderWithBrowserRouter(
<DeleteFilesystem close={vi.fn()} storageDevice={disk} systemId="abc123" />,
{ state }
);

expect(
screen.getByRole("form", { name: "Delete filesystem" })
).toBeInTheDocument();
});

it("can remove a disk's filesystem", async () => {
const store = mockStore(state);
renderWithBrowserRouter(
<DeleteFilesystem close={vi.fn()} storageDevice={disk} systemId="abc123" />,
{ store }
);

expect(
screen.getByRole("form", { name: "Delete filesystem" })
).toBeInTheDocument();
expect(
screen.getByText("Are you sure you want to remove this filesystem?")
).toBeInTheDocument();
await userEvent.click(screen.getByRole("button", { name: "Remove" }));
const expectedAction = machineActions.deleteFilesystem({
blockDeviceId: disk.id,
filesystemId: filesystem.id,
systemId: machine.system_id,
});

expect(
store.getActions().find((action) => action.type === expectedAction.type)
).toStrictEqual(expectedAction);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { useDispatch } from "react-redux";

import ModelActionForm from "@/app/base/components/ModelActionForm";
import { actions as machineActions } from "@/app/store/machine";
import type { Machine } from "@/app/store/machine/types";
import type { Disk, Partition } from "@/app/store/types/node";
import { isDisk, isMounted } from "@/app/store/utils";

type Props = {
close: () => void;
systemId: Machine["system_id"];
storageDevice: Disk | Partition;
};

const DeleteFilesystem = ({ close, systemId, storageDevice }: Props) => {
const dispatch = useDispatch();
const deviceIsDisk = isDisk(storageDevice);
const storageFs = storageDevice.filesystem;
const isDiskFsDelete = deviceIsDisk && isMounted(storageFs);

return (
<ModelActionForm
aria-label="Delete filesystem"
initialValues={{}}
message={<>Are you sure you want to remove this filesystem?</>}
modelType="filesystem"
onCancel={close}
onSaveAnalytics={{
action: `Delete ${isDiskFsDelete ? "disk" : "partition"} filesystem`,
category: "Machine storage",
label: "Remove",
}}
onSubmit={() => {
dispatch(machineActions.cleanup());
if (isDiskFsDelete) {
dispatch(
machineActions.deleteFilesystem({
blockDeviceId: storageDevice.id,
filesystemId: storageFs.id,
systemId,
})
);
} else {
dispatch(
machineActions.deletePartition({
partitionId: storageDevice.id,
systemId,
})
);
}
close();
}}
submitAppearance="negative"
submitLabel="Remove"
/>
);
};

export default DeleteFilesystem;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./DeleteFilesystem";
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import configureStore from "redux-mock-store";

import DeleteSpecialFilesystem from "./DeleteSpecialFilesystem";

import { actions as machineActions } from "@/app/store/machine";
import type { RootState } from "@/app/store/root/types";
import * as factory from "@/testing/factories";
import { renderWithBrowserRouter, screen, userEvent } from "@/testing/utils";

const mockStore = configureStore<RootState>();
const filesystem = factory.nodeFilesystem({ mount_point: "/disk-fs/path" });
const disk = factory.nodeDisk({ filesystem, partitions: [] });
const machine = factory.machineDetails({
disks: [disk],
system_id: "abc123",
});
const state = factory.rootState({
machine: factory.machineState({
items: [machine],
statuses: factory.machineStatuses({
abc123: factory.machineStatus(),
}),
}),
});

it("renders a delete confirmation form", () => {
renderWithBrowserRouter(
<DeleteSpecialFilesystem
close={vi.fn()}
mountPoint={filesystem.mount_point}
systemId="abc123"
/>,
{ state }
);

expect(
screen.getByRole("form", { name: "Delete special filesystem" })
).toBeInTheDocument();
});

it("can remove a special filesystem", async () => {
const store = mockStore(state);
renderWithBrowserRouter(
<DeleteSpecialFilesystem
close={vi.fn()}
mountPoint={filesystem.mount_point}
systemId="abc123"
/>,
{ store }
);

expect(
screen.getByRole("form", { name: "Delete special filesystem" })
).toBeInTheDocument();
expect(
screen.getByText("Are you sure you want to remove this special filesystem?")
).toBeInTheDocument();
await userEvent.click(screen.getByRole("button", { name: "Remove" }));
const expectedAction = machineActions.unmountSpecial({
mountPoint: filesystem.mount_point,
systemId: machine.system_id,
});

expect(
store.getActions().find((action) => action.type === expectedAction.type)
).toStrictEqual(expectedAction);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { useDispatch } from "react-redux";

import ModelActionForm from "@/app/base/components/ModelActionForm";
import { actions as machineActions } from "@/app/store/machine";
import type { Machine } from "@/app/store/machine/types";
import type { Filesystem } from "@/app/store/types/node";

type Props = {
close: () => void;
mountPoint: Filesystem["mount_point"];
systemId: Machine["system_id"];
};

const DeleteSpecialFilesystem = ({ close, systemId, mountPoint }: Props) => {
const dispatch = useDispatch();

return (
<ModelActionForm
aria-label="Delete special filesystem"
initialValues={{}}
message={<>Are you sure you want to remove this special filesystem?</>}
modelType="special filesystem"
onCancel={close}
onSaveAnalytics={{
action: "Unmount special filesystem",
category: "Machine storage",
label: "Remove",
}}
onSubmit={() => {
dispatch(machineActions.cleanup());
dispatch(
machineActions.unmountSpecial({
mountPoint,
systemId,
})
);
close();
}}
submitAppearance="negative"
submitLabel="Remove"
/>
);
};

export default DeleteSpecialFilesystem;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./DeleteSpecialFilesystem";
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,24 @@ import configureStore from "redux-mock-store";

import FilesystemsTable from "./FilesystemsTable";

import { actions as machineActions } from "@/app/store/machine";
import * as sidePanelHooks from "@/app/base/side-panel-context";
import { MachineSidePanelViews } from "@/app/machines/constants";
import * as factory from "@/testing/factories";
import { userEvent, render, screen } from "@/testing/utils";

const mockStore = configureStore();
const setSidePanelContent = vi.fn();
beforeEach(() => {
vi.spyOn(sidePanelHooks, "useSidePanel").mockReturnValue({
setSidePanelContent,
sidePanelContent: null,
setSidePanelSize: vi.fn(),
sidePanelSize: "regular",
});
});
afterEach(() => {
vi.restoreAllMocks();
});

it("can show an empty message", () => {
const machine = factory.machineDetails({
Expand Down Expand Up @@ -263,19 +276,9 @@ it("can remove a disk's filesystem if node is a machine", async () => {
await userEvent.click(
screen.getByRole("button", { name: "Remove filesystem..." })
);
await userEvent.click(screen.getByRole("button", { name: "Remove" }));

const expectedAction = machineActions.deleteFilesystem({
blockDeviceId: disk.id,
filesystemId: filesystem.id,
systemId: machine.system_id,
});
expect(
screen.getByText("Are you sure you want to remove this filesystem?")
).toBeInTheDocument();
expect(
store.getActions().find((action) => action.type === expectedAction.type)
).toStrictEqual(expectedAction);
expect(setSidePanelContent).toHaveBeenCalledWith(
expect.objectContaining({ view: MachineSidePanelViews.DELETE_FILESYSTEM })
);
});

it("can remove a partition's filesystem if node is a machine", async () => {
Expand Down Expand Up @@ -309,18 +312,9 @@ it("can remove a partition's filesystem if node is a machine", async () => {
await userEvent.click(
screen.getByRole("button", { name: "Remove filesystem..." })
);
await userEvent.click(screen.getByRole("button", { name: "Remove" }));

const expectedAction = machineActions.deletePartition({
partitionId: partition.id,
systemId: machine.system_id,
});
expect(
screen.getByText("Are you sure you want to remove this filesystem?")
).toBeInTheDocument();
expect(
store.getActions().find((action) => action.type === expectedAction.type)
).toStrictEqual(expectedAction);
expect(setSidePanelContent).toHaveBeenCalledWith(
expect.objectContaining({ view: MachineSidePanelViews.DELETE_FILESYSTEM })
);
});

it("can remove a special filesystem if node is a machine", async () => {
Expand Down Expand Up @@ -356,18 +350,11 @@ it("can remove a special filesystem if node is a machine", async () => {
await userEvent.click(
screen.getByRole("button", { name: "Remove filesystem..." })
);
await userEvent.click(screen.getByRole("button", { name: "Remove" }));

const expectedAction = machineActions.unmountSpecial({
mountPoint: filesystem.mount_point,
systemId: machine.system_id,
});
expect(
screen.getByText("Are you sure you want to remove this special filesystem?")
).toBeInTheDocument();
expect(
store.getActions().find((action) => action.type === expectedAction.type)
).toStrictEqual(expectedAction);
expect(setSidePanelContent).toHaveBeenCalledWith(
expect.objectContaining({
view: MachineSidePanelViews.DELETE_SPECIAL_FILESYSTEM,
})
);
});

it("can unmount a disk's filesystem if node is a machine", async () => {
Expand Down Expand Up @@ -400,20 +387,9 @@ it("can unmount a disk's filesystem if node is a machine", async () => {
await userEvent.click(
screen.getByRole("button", { name: "Unmount filesystem..." })
);
await userEvent.click(screen.getByRole("button", { name: "Unmount" }));

const expectedAction = machineActions.updateFilesystem({
blockId: disk.id,
mountOptions: "",
mountPoint: "",
systemId: machine.system_id,
});
expect(
screen.getByText("Are you sure you want to unmount this filesystem?")
).toBeInTheDocument();
expect(
store.getActions().find((action) => action.type === expectedAction.type)
).toStrictEqual(expectedAction);
expect(setSidePanelContent).toHaveBeenCalledWith(
expect.objectContaining({ view: MachineSidePanelViews.UNMOUNT_FILESYSTEM })
);
});

it("can unmount a partition's filesystem if node is a machine", async () => {
Expand Down Expand Up @@ -447,18 +423,7 @@ it("can unmount a partition's filesystem if node is a machine", async () => {
await userEvent.click(
screen.getByRole("button", { name: "Unmount filesystem..." })
);
await userEvent.click(screen.getByRole("button", { name: "Unmount" }));

const expectedAction = machineActions.updateFilesystem({
mountOptions: "",
mountPoint: "",
partitionId: partition.id,
systemId: machine.system_id,
});
expect(
screen.getByText("Are you sure you want to unmount this filesystem?")
).toBeInTheDocument();
expect(
store.getActions().find((action) => action.type === expectedAction.type)
).toStrictEqual(expectedAction);
expect(setSidePanelContent).toHaveBeenCalledWith(
expect.objectContaining({ view: MachineSidePanelViews.UNMOUNT_FILESYSTEM })
);
});
Loading

0 comments on commit 0bf1d6f

Please sign in to comment.