diff --git a/web/src/api/storage/proposal.ts b/web/src/api/storage/proposal.ts
deleted file mode 100644
index 333f3ae633..0000000000
--- a/web/src/api/storage/proposal.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (c) [2024-2025] SUSE LLC
- *
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, contact SUSE LLC.
- *
- * To contact SUSE LLC about this file by physical or electronic mail, you may
- * find current contact information at www.suse.com.
- */
-
-import { put } from "../http";
-import { ProposalSettingsPatch } from "~/api/storage/types";
-
-const calculate = (settings: ProposalSettingsPatch) =>
- put("/api/storage/proposal/settings", settings);
-
-export { calculate };
diff --git a/web/src/api/storage/types/config-model.ts b/web/src/api/storage/types/config-model.ts
index 079d6bb8f4..2095531c99 100644
--- a/web/src/api/storage/types/config-model.ts
+++ b/web/src/api/storage/types/config-model.ts
@@ -1,4 +1,3 @@
-/* eslint-disable */
/**
* This file was automatically generated by json-schema-to-typescript.
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
diff --git a/web/src/api/storage/types/config.ts b/web/src/api/storage/types/config.ts
index 7a7864a01d..dbaaa13af1 100644
--- a/web/src/api/storage/types/config.ts
+++ b/web/src/api/storage/types/config.ts
@@ -1,4 +1,3 @@
-/* eslint-disable */
/**
* This file was automatically generated by json-schema-to-typescript.
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
diff --git a/web/src/components/core/ExpandableSelector.test.tsx b/web/src/components/core/ExpandableSelector.test.tsx
deleted file mode 100644
index 9f1f9e6815..0000000000
--- a/web/src/components/core/ExpandableSelector.test.tsx
+++ /dev/null
@@ -1,454 +0,0 @@
-/*
- * Copyright (c) [2024] SUSE LLC
- *
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, contact SUSE LLC.
- *
- * To contact SUSE LLC about this file by physical or electronic mail, you may
- * find current contact information at www.suse.com.
- */
-
-import React from "react";
-import { screen, within } from "@testing-library/react";
-import { plainRender } from "~/test-utils";
-import { ExpandableSelector } from "~/components/core";
-import { ExpandableSelectorColumn } from "./ExpandableSelector";
-
-let consoleErrorSpy: jest.SpyInstance;
-
-/* eslint-disable @typescript-eslint/no-explicit-any */
-
-const sda: any = {
- sid: "59",
- isDrive: true,
- type: "disk",
- vendor: "Micron",
- model: "Micron 1100 SATA",
- driver: ["ahci", "mmcblk"],
- bus: "IDE",
- busId: "",
- transport: "usb",
- dellBOSS: false,
- sdCard: true,
- active: true,
- name: "/dev/sda",
- size: 1024,
- shrinking: { unsupported: ["Resizing is not supported"] },
- systems: [],
- udevIds: ["ata-Micron_1100_SATA_512GB_12563", "scsi-0ATA_Micron_1100_SATA_512GB"],
- udevPaths: ["pci-0000:00-12", "pci-0000:00-12-ata"],
-};
-
-const sda1 = {
- sid: "60",
- isDrive: false,
- type: "",
- active: true,
- name: "/dev/sda1",
- size: 512,
- shrinking: { supported: 128 },
- systems: [],
- udevIds: [],
- udevPaths: [],
-};
-
-const sda2 = {
- sid: "61",
- isDrive: false,
- type: "",
- active: true,
- name: "/dev/sda2",
- size: 512,
- shrinking: { unsupported: ["Resizing is not supported"] },
- systems: [],
- udevIds: [],
- udevPaths: [],
-};
-
-sda.partitionTable = {
- type: "gpt",
- partitions: [sda1, sda2],
- unpartitionedSize: 512,
-};
-
-const sdb = {
- sid: "62",
- isDrive: true,
- type: "disk",
- vendor: "Samsung",
- model: "Samsung Evo 8 Pro",
- driver: ["ahci"],
- bus: "IDE",
- busId: "",
- transport: "",
- dellBOSS: false,
- sdCard: false,
- active: true,
- name: "/dev/sdb",
- size: 2048,
- shrinking: { unsupported: ["Resizing is not supported"] },
- systems: [],
- udevIds: [],
- udevPaths: ["pci-0000:00-19"],
-};
-
-const lv1 = {
- sid: "163",
- name: "/dev/system/vg/lv1",
- content: "Personal Data",
-};
-
-const vg = {
- sid: "162",
- type: "vg",
- name: "/dev/system/vg",
- lvs: [lv1],
-};
-
-const columns: ExpandableSelectorColumn[] = [
- // FIXME: do not use any but the right types once storage part is rewritten.
- // Or even better, write a test not coupled to storage
- { name: "Device", value: (item: any) => item.name },
- {
- name: "Content",
- value: (item: any) => {
- if (item.isDrive) return item.systems.map((s, i) =>
{s}
);
- if (item.type === "vg") return `${item.lvs.length} logical volume(s)`;
-
- return item.content;
- },
- },
- { name: "Size", value: (item: any) => item.size },
-];
-
-const onChangeFn = jest.fn();
-
-let props;
-const commonProps = {
- columns,
- items: [sda, sdb, vg],
- itemIdKey: "sid",
- initialExpandedKeys: [sda.sid, vg.sid],
- itemChildren: (item) => (item.isDrive ? item.partitionTable?.partitions : item.lvs),
- onSelectionChange: onChangeFn,
- "aria-label": "Device selector",
-};
-
-describe("ExpandableSelector", () => {
- beforeAll(() => {
- consoleErrorSpy = jest.spyOn(console, "error");
- consoleErrorSpy.mockImplementation();
- });
-
- afterAll(() => {
- consoleErrorSpy.mockRestore();
- });
-
- beforeEach(() => {
- props = { ...commonProps };
- });
-
- it("renders a table with given name", () => {
- plainRender();
- screen.getByRole("grid", { name: "Device selector" });
- });
-
- it("renders the table headers", () => {
- plainRender();
- const table = screen.getByRole("grid");
- within(table).getByRole("columnheader", { name: "Device" });
- within(table).getByRole("columnheader", { name: "Content" });
- within(table).getByRole("columnheader", { name: "Size" });
- });
-
- it("renders a rowgroup per parent item", () => {
- plainRender();
- const groups = screen.getAllByRole("rowgroup");
- // NOTE: since has also the rowgroup role, we expect to found 4 in
- // this example: 1 thead + 3 tbody (sda, sdb, vg)
- expect(groups.length).toEqual(4);
- });
-
- it("renders a row per given item and found children", () => {
- plainRender();
- const table = screen.getByRole("grid");
- within(table).getByRole("row", { name: /dev\/sda 1024/ });
- within(table).getByRole("row", { name: /dev\/sdb 2048/ });
- within(table).getByRole("row", { name: /dev\/system\/vg 1 logical/ });
- within(table).getByRole("row", { name: /dev\/sda1 512/ });
- within(table).getByRole("row", { name: /dev\/sda2 512/ });
- within(table).getByRole("row", { name: /Personal Data/ });
- });
-
- it("renders a expand toggler in items with children", () => {
- plainRender();
- const table = screen.getByRole("grid");
- const sdaRow = within(table).getByRole("row", { name: /dev\/sda 1024/ });
- const sdbRow = within(table).getByRole("row", { name: /dev\/sdb 2048/ });
- const lvRow = within(table).getByRole("row", { name: /dev\/system\/vg 1 logical/ });
-
- within(sdaRow).getByRole("button", { name: "Details" });
- within(lvRow).getByRole("button", { name: "Details" });
- // `/dev/sdb` does not have children, toggler must not be there
- const sdbChildrenToggler = within(sdbRow).queryByRole("button", { name: "Details" });
- expect(sdbChildrenToggler).toBeNull();
- });
-
- it("renders as expanded items which value for `itemIdKey` is included in `initialExpandedKeys` prop", () => {
- plainRender(
- ,
- );
- const table = screen.getByRole("grid");
- within(table).getByRole("row", { name: /dev\/sda1 512/ });
- within(table).getByRole("row", { name: /dev\/sda2 512/ });
- });
-
- it("keeps track of expanded items", async () => {
- const { user } = plainRender(
- ,
- );
- const table = screen.getByRole("grid");
- const sdaRow = within(table).getByRole("row", { name: /sda 1024/ });
- const sdaToggler = within(sdaRow).getByRole("button", { name: "Details" });
- const vgRow = within(table).getByRole("row", { name: /vg 1 logical/ });
- const vgToggler = within(vgRow).getByRole("button", { name: "Details" });
-
- within(table).getByRole("row", { name: /dev\/sda1 512/ });
- within(table).getByRole("row", { name: /dev\/sda2 512/ });
-
- await user.click(vgToggler);
-
- within(table).getByRole("row", { name: /Personal Data/ });
-
- await user.click(sdaToggler);
- const sdaPartitionsRows = within(table).queryAllByRole("row", { name: /sda[d] 512/ });
- expect(sdaPartitionsRows.length).toEqual(0);
- });
-
- it("uses 'id' as key when `itemIdKey` prop is not given", () => {
- plainRender();
-
- const table = screen.getByRole("grid");
- // Since itemIdKey does not match the id used for the item, they are
- // collapsed by default and their children are not visible
- const sdaChild = within(table).queryByRole("row", { name: /dev\/sda1 512/ });
- expect(sdaChild).toBeNull();
- });
-
- it("uses given `itemIdKey` as key", () => {
- plainRender(
- ,
- );
-
- const table = screen.getByRole("grid");
- // Since itemIdKey === "name", "/dev/sda" is properly mounted as expanded. Its
- // children must be visible
- const sdaChild = within(table).queryByRole("row", { name: /dev\/sda1 512/ });
- expect(sdaChild).not.toBeNull();
- });
-
- describe("when `itemsSelected` is given", () => {
- it("renders nothing as checked if value is an empty array", () => {
- plainRender();
- const table = screen.getByRole("grid");
- const selection = within(table).queryAllByRole("radio", { checked: true });
- expect(selection.length).toEqual(0);
- });
-
- describe("but it isn't an array", () => {
- it("outputs to console.error", () => {
- plainRender();
- expect(console.error).toHaveBeenCalledWith(
- expect.stringContaining("prop must be an array"),
- "Whatever",
- );
- });
-
- it("renders nothing as selected", () => {
- plainRender();
- const table = screen.getByRole("grid");
- const selection = within(table).queryAllByRole("radio", { checked: true });
- expect(selection.length).toEqual(0);
- });
- });
- });
-
- describe("when mounted as single selector", () => {
- describe.each([undefined, null, false])("because isMultiple={%s}", (isMultiple) => {
- beforeEach(() => {
- props = { ...props, isMultiple };
- });
-
- it("renders a radio per item row", () => {
- plainRender();
- const table = screen.getByRole("grid");
- const radios = within(table).getAllByRole("radio");
- expect(radios.length).toEqual(6);
- });
-
- describe("but `itemSelectable` is given", () => {
- it("renders a radio only for items for which it returns true", () => {
- const itemSelectable = (item) => item.isDrive || item.type === "vg";
- plainRender();
- const table = screen.getByRole("grid");
- const radios = within(table).getAllByRole("radio");
-
- // Expected only three radios
- expect(radios.length).toEqual(3);
-
- // Not in below items
- const sda1Row = within(table).getByRole("row", { name: /dev\/sda1/ });
- const sda2Row = within(table).getByRole("row", { name: /dev\/sda2/ });
- const lv1Row = within(table).getByRole("row", { name: /lv1/ });
- expect(within(sda1Row).queryAllByRole("radio")).toEqual([]);
- expect(within(sda2Row).queryAllByRole("radio")).toEqual([]);
- expect(within(lv1Row).queryAllByRole("radio")).toEqual([]);
- });
- });
-
- describe("and `itemsSelected` is given", () => {
- describe("and it is an array with just one item", () => {
- it("renders it as checked", async () => {
- plainRender();
- const table = screen.getByRole("grid");
- const sda1Row = within(table).getByRole("row", { name: /dev\/sda1/ });
- const selection = screen.getAllByRole("radio", { checked: true });
- expect(selection.length).toEqual(1);
- within(sda1Row).getByRole("radio", { checked: true });
- });
- });
-
- describe("but it is an array with more than one item", () => {
- it("outputs to console.error", () => {
- plainRender();
- expect(console.error).toHaveBeenCalledWith(
- expect.stringContaining("Using only the first element"),
- );
- });
-
- it("renders the first one as checked", async () => {
- plainRender();
- const table = screen.getByRole("grid");
- const selection = screen.getAllByRole("radio", { checked: true });
- const sda1Row = within(table).getByRole("row", { name: /dev\/sda1/ });
- const lv1Row = within(table).getByRole("row", { name: /Personal Data/ });
- const lv1Radio = within(lv1Row).getByRole("radio");
- within(sda1Row).getByRole("radio", { checked: true });
- expect(lv1Radio).not.toHaveAttribute("checked", true);
- expect(selection.length).toEqual(1);
- });
- });
- });
-
- describe("and user selects an already selected item", () => {
- it("does not trigger the `onSelectionChange` callback", async () => {
- const { user } = plainRender();
- const sda1row = screen.getByRole("row", { name: /dev\/sda1/ });
- const sda1radio = within(sda1row).getByRole("radio");
- await user.click(sda1radio);
- expect(onChangeFn).not.toHaveBeenCalled();
- });
- });
-
- describe("and user selects a not selected item", () => {
- it("calls the `onSelectionChange` callback with a collection holding only selected item", async () => {
- const { user } = plainRender();
- const sda2row = screen.getByRole("row", { name: /dev\/sda2/ });
- const sda2radio = within(sda2row).getByRole("radio");
- await user.click(sda2radio);
- expect(onChangeFn).toHaveBeenCalledWith([sda2]);
- });
- });
- });
- });
-
- describe("when mounted as multiple selector", () => {
- beforeEach(() => {
- props = { ...props, isMultiple: true };
- });
-
- it("renders a checkbox per item row", () => {
- plainRender();
- const table = screen.getByRole("grid");
- const checkboxes = within(table).getAllByRole("checkbox");
- expect(checkboxes.length).toEqual(6);
- });
-
- describe("but `itemSelectable` is given", () => {
- it("renders a checkbox only for items for which it returns true", () => {
- const itemSelectable = (item) => item.isDrive || item.type === "vg";
- plainRender();
- const table = screen.getByRole("grid");
- const checkboxes = within(table).getAllByRole("checkbox");
-
- // Expected only three checkboxes
- expect(checkboxes.length).toEqual(3);
-
- // Not in below items
- const sda1Row = within(table).getByRole("row", { name: /dev\/sda1/ });
- const sda2Row = within(table).getByRole("row", { name: /dev\/sda2/ });
- const lv1Row = within(table).getByRole("row", { name: /lv1/ });
- expect(within(sda1Row).queryAllByRole("checkbox")).toEqual([]);
- expect(within(sda2Row).queryAllByRole("checkbox")).toEqual([]);
- expect(within(lv1Row).queryAllByRole("checkbox")).toEqual([]);
- });
- });
-
- describe("and `itemsSelected` is given", () => {
- it("renders given items as checked", async () => {
- plainRender();
- const table = screen.getByRole("grid");
- const selection = screen.getAllByRole("checkbox", { checked: true });
- const sda1Row = within(table).getByRole("row", { name: /dev\/sda1/ });
- const lv1Row = within(table).getByRole("row", { name: /Personal Data/ });
- within(sda1Row).getByRole("checkbox", { checked: true });
- within(lv1Row).getByRole("checkbox", { checked: true });
- expect(selection.length).toEqual(2);
- });
- });
-
- it("renders initially selected items given via `itemsSelected` prop", async () => {
- plainRender();
- const table = screen.getByRole("grid");
- const sda1Row = within(table).getByRole("row", { name: /dev\/sda1/ });
- const lv1Row = within(table).getByRole("row", { name: /Personal Data/ });
- const selection = screen.getAllByRole("checkbox", { checked: true });
- expect(selection.length).toEqual(2);
- [sda1Row, lv1Row].forEach((row) => within(row).getByRole("checkbox", { checked: true }));
- });
-
- describe("and user selects an already selected item", () => {
- it("triggers the `onSelectionChange` callback with a collection not including the item", async () => {
- const { user } = plainRender(
- ,
- );
- const sda1row = screen.getByRole("row", { name: /dev\/sda1/ });
- const sda1radio = within(sda1row).getByRole("checkbox");
- await user.click(sda1radio);
- expect(onChangeFn).toHaveBeenCalledWith([sda2]);
- });
- });
-
- describe("and user selects a not selected item", () => {
- it("calls the `onSelectionChange` callback with a collection including the item", async () => {
- const { user } = plainRender();
- const sda2row = screen.getByRole("row", { name: /dev\/sda2/ });
- const sda2checkbox = within(sda2row).getByRole("checkbox");
- await user.click(sda2checkbox);
- expect(onChangeFn).toHaveBeenCalledWith([sda1, sda2]);
- });
- });
- });
-});
diff --git a/web/src/components/core/ExpandableSelector.tsx b/web/src/components/core/ExpandableSelector.tsx
deleted file mode 100644
index b8c04f58fa..0000000000
--- a/web/src/components/core/ExpandableSelector.tsx
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * Copyright (c) [2024] SUSE LLC
- *
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, contact SUSE LLC.
- *
- * To contact SUSE LLC about this file by physical or electronic mail, you may
- * find current contact information at www.suse.com.
- */
-
-import React, { useState } from "react";
-import {
- Table,
- TableProps,
- Thead,
- Tr,
- Th,
- Tbody,
- Td,
- ExpandableRowContent,
- RowSelectVariant,
-} from "@patternfly/react-table";
-
-/* eslint-disable @typescript-eslint/no-explicit-any */
-
-/**
- * An object for sharing data across nested maps
- *
- * Since function arguments are always passed by value, an object passed by
- * sharing is needed for sharing data that might be mutated from different
- * places, as it is the case of the rowIndex prop here.
- *
- * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions#passing_arguments
- */
-
-type SharedData = {
- rowIndex: number;
-};
-
-export type ExpandableSelectorColumn = {
- /** The column header text */
- name: string;
- /** A function receiving the item to work with and returns the column value */
- value: (item: object) => React.ReactNode;
- /** Space-separated list of additional CSS class names */
- classNames?: string;
-};
-
-export type ExpandableSelectorProps = {
- /** Collection of objects defining columns. */
- columns?: ExpandableSelectorColumn[];
- /** Whether multiple selection is allowed. */
- isMultiple?: boolean;
- /** Collection of items to be rendered. */
- items?: object[];
- /** The key for retrieving the item id. */
- itemIdKey?: string;
- /** Lookup method to retrieve children from given item. */
- itemChildren?: (item: object) => object[];
- /** Whether an item will be selectable or not. */
- itemSelectable?: (item: object) => boolean;
- /** Callback to add additional CSS class names to item row. */
- itemClassNames?: (item: object) => string | undefined;
- /** Collection of selected items. */
- itemsSelected?: object[];
- /** Ids of initially expanded items. */
- initialExpandedKeys?: any[];
- /** Callback to be triggered when selection changes. */
- onSelectionChange?: (selection: object[]) => void;
-} & TableProps;
-
-/**
- * Internal component for building the table header
- */
-const TableHeader = ({ columns }: { columns: ExpandableSelectorColumn[] }) => (
-
-
- |
- |
- {columns?.map((c, i) => (
-
- {c.name}
- |
- ))}
-
-
-);
-
-/**
- * Helper function for ensuring a good value for ExpandableSelector#itemsSelected prop
- *
- * It logs information to console.error if given value does not match
- * expectations.
- *
- * @param selection - The value to check.
- * @param allowMultiple - Whether the returned collection can have
- * more than one item
- * @return Empty array if given value is not valid. The first element if
- * it is a collection with more than one but selector does not allow multiple.
- * The original value otherwise.
- */
-const sanitizeSelection = (selection: any[], allowMultiple: boolean): any[] => {
- if (!Array.isArray(selection)) {
- console.error("`itemSelected` prop must be an array. Ignoring given value", selection);
- return [];
- }
-
- if (!allowMultiple && selection.length > 1) {
- console.error(
- "`itemsSelected` prop can only have more than one item when selector `isMultiple`. " +
- "Using only the first element",
- );
-
- return [selection[0]];
- }
-
- return selection;
-};
-
-/**
- * Build a expandable table with selectable items.
- * @component
- *
- * @note It only accepts one nesting level.
- *
- * @param {ExpandableSelectorProps} props
- */
-export default function ExpandableSelector({
- columns = [],
- isMultiple = false,
- items = [],
- itemIdKey = "id",
- itemChildren = () => [],
- itemSelectable = () => true,
- itemClassNames = () => "",
- itemsSelected = [],
- initialExpandedKeys = [],
- onSelectionChange,
- ...tableProps
-}: ExpandableSelectorProps) {
- const [expandedItemsKeys, setExpandedItemsKeys] = useState(initialExpandedKeys);
- const selection = sanitizeSelection(itemsSelected, isMultiple);
- const isItemSelected = (item: object) => {
- const selected = selection.find((selectionItem) => {
- return (
- Object.hasOwn(selectionItem, itemIdKey) && selectionItem[itemIdKey] === item[itemIdKey]
- );
- });
-
- return selected !== undefined || selection.includes(item);
- };
- const isItemExpanded = (key: string | number) => expandedItemsKeys.includes(key);
- const toggleExpanded = (key: string | number) => {
- if (isItemExpanded(key)) {
- setExpandedItemsKeys(expandedItemsKeys.filter((k) => k !== key));
- } else {
- setExpandedItemsKeys([...expandedItemsKeys, key]);
- }
- };
-
- const updateSelection = (item: object) => {
- if (!isMultiple) {
- onSelectionChange([item]);
- return;
- }
-
- if (isItemSelected(item)) {
- onSelectionChange(selection.filter((i) => i !== item));
- } else {
- onSelectionChange([...selection, item]);
- }
- };
-
- /**
- * Render method for building the markup for an item child
- *
- * @param item - The child to be rendered
- * @param isExpanded - Whether the child should be shown or not
- * @param sharedData - An object holding shared data
- */
- const renderItemChild = (item: object, isExpanded: boolean, sharedData: SharedData) => {
- const rowIndex = sharedData.rowIndex++;
-
- const selectProps = {
- rowIndex,
- onSelect: () => updateSelection(item),
- isSelected: isItemSelected(item),
- variant: isMultiple ? RowSelectVariant.checkbox : RowSelectVariant.radio,
- };
-
- return (
-
- |
- |
- {columns?.map((column, index) => (
-
- {column.value(item)}
- |
- ))}
-
- );
- };
-
- /**
- * Render method for building the markup for item
- *
- * @param item - The item to be rendered
- * @param sharedData - An object holding shared data
- */
- const renderItem = (item: object, sharedData: SharedData) => {
- const itemKey = item[itemIdKey];
- const rowIndex = sharedData.rowIndex++;
- const children = itemChildren(item);
- const validChildren = Array.isArray(children) && children.length > 0;
- const expandProps = validChildren && {
- rowIndex,
- isExpanded: isItemExpanded(itemKey),
- onToggle: () => toggleExpanded(itemKey),
- };
-
- const selectProps = {
- rowIndex,
- onSelect: () => updateSelection(item),
- isSelected: isItemSelected(item),
- variant: isMultiple ? RowSelectVariant.checkbox : RowSelectVariant.radio,
- };
-
- const renderChildren = () => {
- if (!validChildren) return;
-
- return children.map((item) => renderItemChild(item, isItemExpanded(itemKey), sharedData));
- };
-
- // TODO: Add label to Tbody?
- return (
-
-
- |
- |
- {columns?.map((column, index) => (
-
- {column.value(item)}
- |
- ))}
-
- {renderChildren()}
-
- );
- };
-
- // @see SharedData
- const sharedData = { rowIndex: 0 };
-
- const TableBody = () => items?.map((item) => renderItem(item, sharedData));
-
- return (
-
- );
-}
diff --git a/web/src/components/core/index.ts b/web/src/components/core/index.ts
index e77cbce6a3..d2e7babb03 100644
--- a/web/src/components/core/index.ts
+++ b/web/src/components/core/index.ts
@@ -40,7 +40,6 @@ export { default as ProgressReport } from "./ProgressReport";
export { default as ProgressText } from "./ProgressText";
export { default as PasswordInput } from "./PasswordInput";
export { default as ServerError } from "./ServerError";
-export { default as ExpandableSelector } from "./ExpandableSelector";
export { default as TreeTable } from "./TreeTable";
export { default as Link } from "./Link";
export { default as EmptyState } from "./EmptyState";
diff --git a/web/src/components/storage/DeviceSelection.tsx b/web/src/components/storage/DeviceSelection.tsx
deleted file mode 100644
index 5fc87aae9e..0000000000
--- a/web/src/components/storage/DeviceSelection.tsx
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright (c) [2024] SUSE LLC
- *
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, contact SUSE LLC.
- *
- * To contact SUSE LLC about this file by physical or electronic mail, you may
- * find current contact information at www.suse.com.
- */
-
-import React, { useEffect, useState } from "react";
-import { useNavigate } from "react-router-dom";
-import { Flex, Form, FormGroup, Radio, Stack } from "@patternfly/react-core";
-import { Page } from "~/components/core";
-import { DeviceSelectorTable } from "~/components/storage";
-import DevicesTechMenu from "./DevicesTechMenu";
-import { ProposalTarget, StorageDevice } from "~/types/storage";
-import { useAvailableDevices, useProposalMutation, useProposalResult } from "~/queries/storage";
-import { deviceChildren } from "~/components/storage/utils";
-import { compact } from "~/utils";
-import a11y from "@patternfly/react-styles/css/utilities/Accessibility/accessibility";
-import { _ } from "~/i18n";
-
-const SELECT_DISK_ID = "select-disk";
-const CREATE_LVM_ID = "create-lvm";
-const SELECT_DISK_PANEL_ID = "panel-for-disk-selection";
-const CREATE_LVM_PANEL_ID = "panel-for-lvm-creation";
-
-type DeviceSelectionState = {
- target?: ProposalTarget;
- targetDevice?: StorageDevice;
- targetPVDevices?: StorageDevice[];
-};
-
-/**
- * Allows the user to select a target device for installation.
- * @component
- */
-export default function DeviceSelection() {
- const proposal = useProposalResult();
- const availableDevices = useAvailableDevices();
- const updateProposal = useProposalMutation();
- const navigate = useNavigate();
- const [state, setState] = useState({});
-
- const isTargetDisk = state.target === ProposalTarget.DISK;
- const isTargetNewLvmVg = state.target === ProposalTarget.NEW_LVM_VG;
-
- useEffect(() => {
- if (state.target !== undefined) return;
-
- // FIXME: move to a state/reducer
- setState({
- target: proposal.settings.target,
- targetDevice: availableDevices.find((d) => d.name === proposal.settings.targetDevice),
- targetPVDevices: availableDevices.filter((d) =>
- proposal.settings.targetPVDevices?.includes(d.name),
- ),
- });
- }, [proposal, availableDevices, state.target]);
-
- const selectTargetDisk = () => setState({ ...state, target: ProposalTarget.DISK });
- const selectTargetNewLvmVG = () => setState({ ...state, target: ProposalTarget.NEW_LVM_VG });
-
- const selectTargetDevice = (devices: StorageDevice[]) =>
- setState({ ...state, targetDevice: devices[0] });
- const selectTargetPVDevices = (devices: StorageDevice[]) => {
- setState({ ...state, targetPVDevices: devices });
- };
-
- const onSubmit = async (e) => {
- e.preventDefault();
- const newSettings = {
- target: state.target,
- targetDevice: isTargetDisk ? state.targetDevice?.name : "",
- targetPVDevices: isTargetNewLvmVg ? state.targetPVDevices.map((d) => d.name) : [],
- };
-
- updateProposal.mutateAsync({ ...proposal.settings, ...newSettings });
- navigate("..");
- };
-
- const isAcceptDisabled = () => {
- if (isTargetDisk) return state.targetDevice === undefined;
- if (isTargetNewLvmVg) return state.targetPVDevices?.length === 0;
-
- return true;
- };
-
- const isDeviceSelectable = (device: StorageDevice) => device.isDrive || device.type === "md";
-
- // TRANSLATORS: description for using plain partitions for installing the
- // system, the text in the square brackets [] is displayed in bold, use only
- // one pair in the translation
- const [msgStart1, msgBold1, msgEnd1] = _(
- "The file systems will be allocated \
-by default as [new partitions in the selected device].",
- ).split(/[[\]]/);
- // TRANSLATORS: description for using logical volumes for installing the
- // system, the text in the square brackets [] is displayed in bold, use only
- // one pair in the translation
- const [msgStart2, msgBold2, msgEnd2] = _(
- "The file systems will be allocated \
-by default as [logical volumes of a new LVM Volume Group]. The corresponding \
-physical volumes will be created on demand as new partitions at the selected \
-devices.",
- ).split(/[[\]]/);
-
- return (
-
-
- {_("Select installation device")}
-
-
-
-
-
-
-
-
-
-
-
- );
-}
diff --git a/web/src/components/storage/DeviceSelectorTable.tsx b/web/src/components/storage/DeviceSelectorTable.tsx
deleted file mode 100644
index 1372dc2a8d..0000000000
--- a/web/src/components/storage/DeviceSelectorTable.tsx
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (c) [2024] SUSE LLC
- *
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, contact SUSE LLC.
- *
- * To contact SUSE LLC about this file by physical or electronic mail, you may
- * find current contact information at www.suse.com.
- */
-
-import React from "react";
-import {
- DeviceName,
- DeviceDetails,
- DeviceSize,
- FilesystemLabel,
- toStorageDevice,
-} from "~/components/storage/device-utils";
-import { ExpandableSelector } from "~/components/core";
-import { Icon } from "~/components/layout";
-import { _ } from "~/i18n";
-import { sprintf } from "sprintf-js";
-import { deviceBaseName } from "~/components/storage/utils";
-import { PartitionSlot, StorageDevice } from "~/types/storage";
-import { ExpandableSelectorColumn, ExpandableSelectorProps } from "../core/ExpandableSelector";
-import { typeDescription, contentDescription } from "./utils/device";
-import { DeviceInfo as DeviceInfoType } from "~/api/storage/types";
-
-/**
- * @component
- */
-const DeviceInfo = ({ item }: { item: PartitionSlot | StorageDevice }) => {
- const device = toStorageDevice(item);
- if (!device) return null;
-
- const DeviceType = () => {
- const type = typeDescription(device);
-
- return type && {type}
;
- };
-
- const DeviceModel = () => {
- if (!device.model || device.model === "") return null;
-
- return {device.model}
;
- };
-
- const MDInfo = () => {
- if (device.type !== "md" || !device.devices) return null;
-
- const members = device.devices.map(deviceBaseName);
-
- // TRANSLATORS: RAID details, %s is replaced by list of devices used by the array
- return {sprintf(_("Members: %s"), members.sort().join(", "))}
;
- };
-
- const RAIDInfo = () => {
- if (device.type !== "raid") return null;
-
- const devices = device.devices.map(deviceBaseName);
-
- // TRANSLATORS: RAID details, %s is replaced by list of devices used by the array
- return {sprintf(_("Devices: %s"), devices.sort().join(", "))}
;
- };
-
- const MultipathInfo = () => {
- if (device.type !== "multipath") return null;
-
- const wires = device.wires.map(deviceBaseName);
-
- // TRANSLATORS: multipath details, %s is replaced by list of connections used by the device
- return {sprintf(_("Wires: %s"), wires.sort().join(", "))}
;
- };
-
- return (
-
-
-
-
-
-
-
-
- );
-};
-
-/**
- * @component
- */
-const DeviceExtendedDetails = ({ item }: { item: PartitionSlot | StorageDevice }) => {
- const device = toStorageDevice(item);
-
- if (!device || ["partition", "lvmLv"].includes(device.type)) return ;
-
- const Description = () => {
- return (
-
- {contentDescription(device)}
-
- );
- };
-
- const Systems = () => {
- if (!device.systems || device.systems.length === 0) return null;
-
- const System = ({ system }) => {
- const isWindows = /windows/i.test(system);
-
- if (isWindows) return {system}
;
-
- return (
-
- {system}
-
- );
- };
-
- return device.systems.map((s, i) => );
- };
-
- return (
-
-
-
-
- );
-};
-
-const columns: ExpandableSelectorColumn[] = [
- { name: _("Device"), value: (item: PartitionSlot | StorageDevice) => },
- {
- name: _("Details"),
- value: (item: PartitionSlot | StorageDevice) => ,
- },
- {
- name: _("Size"),
- value: (item: PartitionSlot | StorageDevice) => ,
- classNames: "sizes-column",
- },
-];
-
-type DeviceSelectorTableProps = {
- devices: StorageDevice[];
- selectedDevices: StorageDevice[];
-} & ExpandableSelectorProps;
-
-/**
- * Table for selecting the installation device.
- * @component
- */
-export default function DeviceSelectorTable({
- devices,
- selectedDevices,
- ...props
-}: DeviceSelectorTableProps) {
- return (
- {
- if (!device.sid) {
- return "dimmed-row";
- }
- }}
- itemsSelected={selectedDevices}
- className="devices-table"
- {...props}
- />
- );
-}
diff --git a/web/src/components/storage/DevicesTechMenu.test.tsx b/web/src/components/storage/DevicesTechMenu.test.tsx
deleted file mode 100644
index 5b8bf07358..0000000000
--- a/web/src/components/storage/DevicesTechMenu.test.tsx
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) [2023-2025] SUSE LLC
- *
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, contact SUSE LLC.
- *
- * To contact SUSE LLC about this file by physical or electronic mail, you may
- * find current contact information at www.suse.com.
- */
-
-import React from "react";
-import { screen } from "@testing-library/react";
-import { installerRender } from "~/test-utils";
-import DevicesTechMenu from "./DevicesTechMenu";
-import { supportedDASD } from "~/api/storage/dasd";
-import { supportedZFCP } from "~/api/storage/zfcp";
-
-jest.mock("~/api/storage/dasd");
-jest.mock("~/api/storage/zfcp");
-
-beforeEach(() => {
- (supportedDASD as jest.Mock).mockResolvedValue(false);
- (supportedZFCP as jest.Mock).mockResolvedValue(false);
-});
-
-it("contains an entry for configuring iSCSI", async () => {
- const { user } = installerRender();
- const toggler = screen.getByRole("button");
- await user.click(toggler);
- const link = screen.getByRole("option", { name: /iSCSI/ });
- expect(link).toHaveAttribute("href", "/storage/iscsi");
-});
-
-it("does not contain an entry for configuring DASD when is NOT supported", async () => {
- const { user } = installerRender();
- const toggler = screen.getByRole("button");
- await user.click(toggler);
- expect(screen.queryByRole("option", { name: /DASD/ })).toBeNull();
-});
-
-it("contains an entry for configuring DASD when is supported", async () => {
- (supportedDASD as jest.Mock).mockResolvedValue(true);
- const { user } = installerRender();
- const toggler = screen.getByRole("button");
- await user.click(toggler);
- const link = screen.getByRole("option", { name: /DASD/ });
- expect(link).toHaveAttribute("href", "/storage/dasd");
-});
-
-it("does not contain an entry for configuring zFCP when is NOT supported", async () => {
- const { user } = installerRender();
- const toggler = screen.getByRole("button");
- await user.click(toggler);
- expect(screen.queryByRole("option", { name: /DASD/ })).toBeNull();
-});
-
-it("contains an entry for configuring zFCP when is supported", async () => {
- (supportedZFCP as jest.Mock).mockResolvedValue(true);
- const { user } = installerRender();
- const toggler = screen.getByRole("button");
- await user.click(toggler);
- const link = screen.getByRole("option", { name: /zFCP/ });
- expect(link).toHaveAttribute("href", "/storage/zfcp");
-});
diff --git a/web/src/components/storage/DevicesTechMenu.tsx b/web/src/components/storage/DevicesTechMenu.tsx
deleted file mode 100644
index 20cf3adc56..0000000000
--- a/web/src/components/storage/DevicesTechMenu.tsx
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (c) [2023-2024] SUSE LLC
- *
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, contact SUSE LLC.
- *
- * To contact SUSE LLC about this file by physical or electronic mail, you may
- * find current contact information at www.suse.com.
- */
-
-import React, { useEffect, useState } from "react";
-import { useHref } from "react-router-dom";
-import {
- MenuToggle,
- MenuToggleElement,
- Select,
- SelectList,
- SelectOption,
-} from "@patternfly/react-core";
-import { _ } from "~/i18n";
-import { supportedDASD } from "~/api/storage/dasd";
-import { supportedZFCP } from "~/api/storage/zfcp";
-
-/**
- * Internal component for building the link to Storage/DASD page
- */
-const DASDLink = () => {
- const href = useHref("/storage/dasd");
-
- return (
-
- DASD
-
- );
-};
-
-/**
- * Internal component for building the link to Storage/zFCP page
- */
-const ZFCPLink = () => {
- const href = useHref("/storage/zfcp");
-
- return (
-
- {_("zFCP")}
-
- );
-};
-
-/**
- * Internal component for building the link to Storage/iSCSI page
- * @component
- */
-const ISCSILink = () => {
- const href = useHref("/storage/iscsi");
-
- return (
-
- {_("iSCSI")}
-
- );
-};
-
-type ProposalMenuProps = {
- label: string;
-};
-
-/**
- * Component for rendering the options available from Storage/ProposalPage
- */
-export default function DevicesTechMenu({ label }: ProposalMenuProps) {
- const [isOpen, setIsOpen] = useState(false);
- const [showDasdLink, setShowDasdLink] = useState(false);
- const [showZFCPLink, setShowZFCPLink] = useState(false);
-
- useEffect(() => {
- supportedDASD().then(setShowDasdLink);
- supportedZFCP().then(setShowZFCPLink);
- }, []);
- const toggle = (toggleRef: React.Ref) => (
- setIsOpen(!isOpen)} isExpanded={isOpen}>
- {label}
-
- );
-
- const onSelect = () => {
- setIsOpen(false);
- };
-
- return (
-
- );
-}
diff --git a/web/src/components/storage/ProposalPage.test.tsx b/web/src/components/storage/ProposalPage.test.tsx
index bd1cc78388..c4e24e7f47 100644
--- a/web/src/components/storage/ProposalPage.test.tsx
+++ b/web/src/components/storage/ProposalPage.test.tsx
@@ -29,13 +29,7 @@ import React from "react";
import { screen } from "@testing-library/react";
import { installerRender } from "~/test-utils";
import { ProposalPage } from "~/components/storage";
-import {
- ProposalResult,
- ProposalTarget,
- StorageDevice,
- Volume,
- VolumeTarget,
-} from "~/types/storage";
+import { Action, StorageDevice, Volume, VolumeTarget } from "~/types/storage";
jest.mock("~/queries/issues", () => ({
...jest.requireActual("~/queries/issues"),
@@ -105,22 +99,7 @@ const volume = (mountPath: string): Volume => {
};
};
-const mockProposalResult: ProposalResult = {
- settings: {
- target: ProposalTarget.DISK,
- targetPVDevices: [],
- configureBoot: false,
- bootDevice: "",
- defaultBootDevice: "",
- encryptionPassword: "",
- encryptionMethod: "",
- spacePolicy: "",
- spaceActions: [],
- volumes: [],
- installationDevices: [],
- },
- actions: [],
-};
+const mockActions: Action[] = [];
jest.mock("~/queries/storage", () => ({
...jest.requireActual("~/queries/storage"),
@@ -132,7 +111,7 @@ jest.mock("~/queries/storage", () => ({
encryptionMethods: [],
mountPoints: ["/", "swap"],
}),
- useProposalResult: () => mockProposalResult,
+ useActions: () => mockActions,
useDeprecated: () => false,
useDeprecatedChanges: jest.fn(),
useProposalMutation: jest.fn(),
diff --git a/web/src/components/storage/ProposalPage.tsx b/web/src/components/storage/ProposalPage.tsx
index 9f8347be87..8ceb3dfd33 100644
--- a/web/src/components/storage/ProposalPage.tsx
+++ b/web/src/components/storage/ProposalPage.tsx
@@ -36,7 +36,7 @@ import {
useDevices,
useDeprecated,
useDeprecatedChanges,
- useProposalResult,
+ useActions,
useReprobeMutation,
} from "~/queries/storage";
import { _ } from "~/i18n";
@@ -69,7 +69,7 @@ export default function ProposalPage() {
const stagingDevices = useDevices("result");
const isDeprecated = useDeprecated();
const { mutateAsync: reprobe } = useReprobeMutation();
- const { actions } = useProposalResult();
+ const actions = useActions();
useDeprecatedChanges();
diff --git a/web/src/components/storage/VolumeLocationSelectorTable.tsx b/web/src/components/storage/VolumeLocationSelectorTable.tsx
deleted file mode 100644
index 764a9c3e38..0000000000
--- a/web/src/components/storage/VolumeLocationSelectorTable.tsx
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (c) [2024-2025] SUSE LLC
- *
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, contact SUSE LLC.
- *
- * To contact SUSE LLC about this file by physical or electronic mail, you may
- * find current contact information at www.suse.com.
- */
-
-import React from "react";
-import { Content, Split } from "@patternfly/react-core";
-import { _ } from "~/i18n";
-import {
- DeviceName,
- DeviceDetails,
- DeviceSize,
- toStorageDevice,
-} from "~/components/storage/device-utils";
-import { ExpandableSelector } from "~/components/core";
-import {
- ExpandableSelectorColumn,
- ExpandableSelectorProps,
-} from "~/components/core/ExpandableSelector";
-import { PartitionSlot, StorageDevice, Volume } from "~/types/storage";
-import { DeviceInfo } from "~/api/storage/types";
-
-/**
- * Returns what (volumes, installation device) is using a device.
- */
-const deviceUsers = (
- item: PartitionSlot | StorageDevice,
- targetDevices: StorageDevice[],
- volumes: Volume[],
-): string[] => {
- const device = toStorageDevice(item);
- if (!device) return [];
-
- const isTargetDevice = !!targetDevices.find((d) => d.name === device.name);
- const volumeUsers = volumes.filter((v) => v.targetDevice?.name === device.name);
-
- const users = [];
- if (isTargetDevice) users.push(_("Installation device"));
-
- return users.concat(volumeUsers.map((v) => v.mountPath));
-};
-
-/**
- * @component
- */
-const DeviceUsage = ({ users }: { users: string[] }) => {
- return (
-
- {users.map((user, index) => (
- {user}
- ))}
-
- );
-};
-
-type VolumeLocationSelectorTableBaseProps = {
- devices: StorageDevice[];
- selectedDevices: StorageDevice[];
- targetDevices: StorageDevice[];
- volumes: Volume[];
-};
-
-export type VolumeLocationSelectorTableProps = VolumeLocationSelectorTableBaseProps &
- ExpandableSelectorProps;
-
-/**
- * Table for selecting the location for a volume.
- * @component
- */
-export default function VolumeLocationSelectorTable({
- devices,
- selectedDevices,
- targetDevices,
- volumes,
- ...props
-}: VolumeLocationSelectorTableProps) {
- const columns: ExpandableSelectorColumn[] = [
- {
- name: _("Device"),
- value: (item: PartitionSlot | StorageDevice) => ,
- },
- {
- name: _("Details"),
- value: (item: PartitionSlot | StorageDevice) => ,
- },
- {
- name: _("Usage"),
- value: (item: PartitionSlot | StorageDevice) => (
-
- ),
- },
- {
- name: _("Size"),
- value: (item: PartitionSlot | StorageDevice) => ,
- classNames: "sizes-column",
- },
- ];
-
- return (
- {
- if (!device.sid) {
- return "dimmed-row";
- }
- }}
- itemsSelected={selectedDevices}
- className="devices-table"
- {...props}
- />
- );
-}
diff --git a/web/src/components/storage/index.ts b/web/src/components/storage/index.ts
index 2e1a4044c4..8cb45ed580 100644
--- a/web/src/components/storage/index.ts
+++ b/web/src/components/storage/index.ts
@@ -26,7 +26,5 @@ export { default as ProposalActionsDialog } from "./ProposalActionsDialog";
export { default as ProposalResultSection } from "./ProposalResultSection";
export { default as ISCSIPage } from "./ISCSIPage";
export { default as BootSelection } from "./BootSelection";
-export { default as DeviceSelectorTable } from "./DeviceSelectorTable";
export { default as DevicesFormSelect } from "./DevicesFormSelect";
export { default as SpaceActionsTable } from "./SpaceActionsTable";
-export { default as DeviceSelection } from "./DeviceSelection";
diff --git a/web/src/queries/storage.ts b/web/src/queries/storage.ts
index cd2b7c4f71..47d916c022 100644
--- a/web/src/queries/storage.ts
+++ b/web/src/queries/storage.ts
@@ -37,22 +37,10 @@ import {
fetchUsableDevices,
reprobe,
} from "~/api/storage";
-import { calculate } from "~/api/storage/proposal";
import { fetchDevices, fetchDevicesDirty } from "~/api/storage/devices";
import { useInstallerClient } from "~/context/installer";
-import {
- config,
- ProductParams,
- Volume as APIVolume,
- ProposalSettingsPatch,
-} from "~/api/storage/types";
-import {
- ProposalSettings,
- ProposalResult,
- StorageDevice,
- Volume,
- VolumeTarget,
-} from "~/types/storage";
+import { config, ProductParams, Volume as APIVolume } from "~/api/storage/types";
+import { Action, StorageDevice, Volume, VolumeTarget } from "~/types/storage";
import { QueryHookOptions } from "~/types/queries";
@@ -234,55 +222,11 @@ const proposalActionsQuery = {
};
/**
- * Hook that returns the current proposal (settings and actions).
+ * Hook that returns the actions to perform in the storage devices.
*/
-const useProposalResult = (): ProposalResult | undefined => {
- const { data: actions } = useSuspenseQuery(proposalActionsQuery);
-
- return { actions };
-};
-
-const useProposalMutation = () => {
- const queryClient = useQueryClient();
- const query = {
- mutationFn: (settings: ProposalSettings) => {
- const buildHttpVolume = (volume: Volume): APIVolume => {
- return {
- autoSize: volume.autoSize,
- fsType: volume.fsType,
- maxSize: volume.maxSize,
- minSize: volume.minSize,
- mountOptions: [],
- mountPath: volume.mountPath,
- snapshots: volume.snapshots,
- target: volume.target,
- targetDevice: volume.targetDevice?.name,
- };
- };
-
- const buildHttpSettings = (settings: ProposalSettings): ProposalSettingsPatch => {
- return {
- bootDevice: settings.bootDevice,
- configureBoot: settings.configureBoot,
- encryptionMethod: settings.encryptionMethod,
- encryptionPBKDFunction: settings.encryptionPBKDFunction,
- encryptionPassword: settings.encryptionPassword,
- spaceActions: settings.spacePolicy === "custom" ? settings.spaceActions : undefined,
- spacePolicy: settings.spacePolicy,
- target: settings.target,
- targetDevice: settings.targetDevice,
- targetPVDevices: settings.targetPVDevices,
- volumes: settings.volumes?.map(buildHttpVolume),
- };
- };
-
- const httpSettings = buildHttpSettings(settings);
- return calculate(httpSettings);
- },
- onSuccess: () => queryClient.invalidateQueries({ queryKey: ["storage"] }),
- };
-
- return useMutation(query);
+const useActions = (): Action[] | undefined => {
+ const { data } = useSuspenseQuery(proposalActionsQuery);
+ return data;
};
const deprecatedQuery = {
@@ -339,8 +283,7 @@ export {
useProductParams,
useVolumeTemplates,
useVolumeDevices,
- useProposalResult,
- useProposalMutation,
+ useActions,
useDeprecated,
useDeprecatedChanges,
useReprobeMutation,
diff --git a/web/src/routes/storage.tsx b/web/src/routes/storage.tsx
index 7a94b22553..3cd1f9bd71 100644
--- a/web/src/routes/storage.tsx
+++ b/web/src/routes/storage.tsx
@@ -23,7 +23,7 @@
import React from "react";
import BootSelection from "~/components/storage/BootSelection";
import SpacePolicySelection from "~/components/storage/SpacePolicySelection";
-import { DeviceSelection, ISCSIPage, ProposalPage } from "~/components/storage";
+import { ISCSIPage, ProposalPage } from "~/components/storage";
import { Route } from "~/types/routes";
import { supportedDASD, probeDASD } from "~/api/storage/dasd";
@@ -42,10 +42,6 @@ const routes = (): Route => ({
index: true,
element: ,
},
- {
- path: PATHS.targetDevice,
- element: ,
- },
{
path: PATHS.bootDevice,
element: ,
diff --git a/web/src/types/storage.ts b/web/src/types/storage.ts
index 01321780fc..ebba8e7724 100644
--- a/web/src/types/storage.ts
+++ b/web/src/types/storage.ts
@@ -1,5 +1,5 @@
/*
- * Copyright (c) [2024] SUSE LLC
+ * Copyright (c) [2024-2025] SUSE LLC
*
* All Rights Reserved.
*
@@ -84,11 +84,6 @@ type ShrinkingInfo = {
unsupported?: string[];
};
-type ProposalResult = {
- settings?: ProposalSettings;
- actions: Action[];
-};
-
type Action = {
device: number;
text: string;
@@ -102,27 +97,6 @@ type SpacePolicyAction = {
value: "delete" | "resizeIfNeeded";
};
-type ProposalSettings = {
- target: ProposalTarget;
- targetDevice?: string;
- targetPVDevices: string[];
- configureBoot: boolean;
- bootDevice: string;
- defaultBootDevice: string;
- encryptionPassword: string;
- encryptionMethod: string;
- encryptionPBKDFunction?: string;
- spacePolicy: string;
- spaceActions: SpaceAction[];
- volumes: Volume[];
- installationDevices: StorageDevice[];
-};
-
-type SpaceAction = {
- device: string;
- action: "force_delete" | "resize" | "keep";
-};
-
type Volume = {
mountPath: string;
target: VolumeTarget;
@@ -147,17 +121,6 @@ type VolumeOutline = {
sizeRelevantVolumes: string[];
};
-/**
- * Enum for the possible proposal targets.
- *
- * @readonly
- */
-enum ProposalTarget {
- DISK = "disk",
- NEW_LVM_VG = "newLvmVg",
- REUSED_LVM_VG = "reusedLvmVg",
-}
-
/**
* Enum for the possible volume targets.
*
@@ -207,14 +170,11 @@ export type {
ISCSINode,
PartitionSlot,
PartitionTable,
- ProposalResult,
- ProposalSettings,
ShrinkingInfo,
- SpaceAction,
SpacePolicyAction,
StorageDevice,
Volume,
VolumeOutline,
};
-export { EncryptionMethods, ProposalTarget, VolumeTarget };
+export { EncryptionMethods, VolumeTarget };