diff --git a/rust/agama-utils/src/api/scope.rs b/rust/agama-utils/src/api/scope.rs index ce657c9ad0..63e87d7cdc 100644 --- a/rust/agama-utils/src/api/scope.rs +++ b/rust/agama-utils/src/api/scope.rs @@ -47,6 +47,8 @@ pub enum Scope { Software, Storage, Files, + #[strum(serialize = "iscsi")] + #[serde(rename = "iscsi")] ISCSI, #[strum(serialize = "dasd")] #[serde(rename = "dasd")] diff --git a/rust/share/system.iscsi.schema.json b/rust/share/system.iscsi.schema.json new file mode 100644 index 0000000000..80b49cde87 --- /dev/null +++ b/rust/share/system.iscsi.schema.json @@ -0,0 +1,53 @@ +{ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "$id": "https://github.com/openSUSE/agama/blob/master/rust/share/system.storage.schema.json", + "title": "System", + "description": "API description of the iSCSI system", + "type": "object", + "additionalProperties": false, + "required": ["initiator", "targets"], + "properties": { + "initiator": { + "title": "Initiator", + "type": "object", + "additionalProperties": false, + "required": ["name", "ibft"], + "properties": { + "name": { "type": "string" }, + "ibft": { "type": "boolean" } + } + }, + "targets": { + "type": "array", + "items": { "$ref": "#/$defs/target" } + } + }, + "$defs": { + "target": { + "type": "object", + "additionalProperties": false, + "required": ["name", "address", "port", "interface", "ibtf", "startup", "connected", "locked"], + "properties": { + "name": { "type": "string" }, + "address": { "type": "string" }, + "port": { "type": "number" }, + "interface": { "type": "string" }, + "ibft": { + "description": "Whether the target was initiated by iBFT.", + "type": "boolean" + }, + "startup": { + "enum": ["onboot", "manual", "automatic"] + }, + "connected": { + "description": "Whether the node is connected (there is a session).", + "type": "boolean" + }, + "locked": { + "description": "Whether the node is locked (cannot be deactivated)", + "type": "boolean" + } + } + } + } +} diff --git a/web/package/agama-web-ui.changes b/web/package/agama-web-ui.changes index fdb1e0d41d..4e8067802b 100644 --- a/web/package/agama-web-ui.changes +++ b/web/package/agama-web-ui.changes @@ -1,3 +1,10 @@ +------------------------------------------------------------------- +Thu Feb 12 11:56:57 UTC 2026 - David Diaz + +- Restore the interface for managing iSCSI in the web client + (gh#agama-project/agama#3092). +- Restore the "Rescan devices" storage option (bsc#1258089). + ------------------------------------------------------------------- Wed Feb 11 14:24:03 UTC 2026 - Imobach Gonzalez Sosa diff --git a/web/src/api.ts b/web/src/api.ts index db75afbf75..fa9bcda060 100644 --- a/web/src/api.ts +++ b/web/src/api.ts @@ -28,7 +28,7 @@ import type { Proposal } from "~/model/proposal"; import type { Question } from "~/model/question"; import type { Status } from "~/model/status"; import type { System } from "~/model/system"; -import type { Action, L10nSystemConfig } from "~/model/action"; +import type { Action, L10nSystemConfig, DiscoverISCSIConfig } from "~/model/action"; import type { AxiosResponse } from "axios"; import type { Job } from "~/types/job"; @@ -78,6 +78,8 @@ const activateStorageAction = () => postAction({ activateStorage: null }); const probeStorageAction = () => postAction({ probeStorage: null }); +const discoverISCSIAction = (config: DiscoverISCSIConfig) => postAction({ discoverISCSI: config }); + const finishInstallation = () => postAction({ finish: "reboot" }); /** @@ -102,6 +104,7 @@ export { configureL10nAction, activateStorageAction, probeStorageAction, + discoverISCSIAction, finishInstallation, getStorageJobs, }; diff --git a/web/src/assets/styles/index.scss b/web/src/assets/styles/index.scss index 1d84600696..436d4d257e 100644 --- a/web/src/assets/styles/index.scss +++ b/web/src/assets/styles/index.scss @@ -559,6 +559,11 @@ span.in-quotes { } } +nav.agm-breadcrumb h1 { + // Allow heading in breadcrumb use fontSize from its parent + font-size: inherit; +} + // FIXME: make ir more generic, if possible, or even without CSS but not // rendering such a label if "storage instructions" are more than one .storage-structure:has(> li:nth-child(2)) span.action-text { diff --git a/web/src/components/core/Breadcrumbs.test.tsx b/web/src/components/core/Breadcrumbs.test.tsx index 5b5e1aeca4..634d919288 100644 --- a/web/src/components/core/Breadcrumbs.test.tsx +++ b/web/src/components/core/Breadcrumbs.test.tsx @@ -109,4 +109,16 @@ describe("Breadcrumbs.Item", () => { expect(label).not.toHaveClass(textStyles.fontSizeLg); expect(label).not.toHaveClass(textStyles.fontWeightBold); }); + + it("renders menu when provided", () => { + installerRender( + } + />, + ); + + screen.getByRole("menu", { name: "Software menu" }); + }); }); diff --git a/web/src/components/core/Breadcrumbs.tsx b/web/src/components/core/Breadcrumbs.tsx index 2d3b5978a8..5833294f06 100644 --- a/web/src/components/core/Breadcrumbs.tsx +++ b/web/src/components/core/Breadcrumbs.tsx @@ -28,12 +28,47 @@ import Icon from "~/components/layout/Icon"; import { TranslatedString, _ } from "~/i18n"; import textStyles from "@patternfly/react-styles/css/utilities/Text/text"; +import displayStyles from "@patternfly/react-styles/css/utilities/Display/display"; export type BreadcrumbProps = { /** The label to display for the breadcrumb item */ label: React.ReactNode | TranslatedString; /** The URL path the breadcrumb item links to */ path?: string; + /** + * Optional menu providing contextual navigation for the breadcrumb item. + * + * When provided, it appears adjacent to the breadcrumb label and is intended + * to contain navigation options related to the area or section represented by + * the breadcrumb. + * + * @remarks + * + * **Accessibility requirement** + * + * The menu trigger must be fully accessible. + * Missing or incorrect ARIA attributes may result in an inaccessible breadcrumb. + * + * At a minimum, the trigger is expected to define: + * - aria-label="[Descriptive label]" + * - aria-haspopup="true" + * - aria-expanded="true | false" + * + * @example + * ```tsx + * + * Advanced settings + * iSCSI configuration + * + * } + * /> + * ``` + */ + menu?: React.ReactNode; /** Option to hide the divider (e.g., chevron icon) between breadcrumb items */ hideDivider?: boolean; /** Flag to indicate if the breadcrumb item should have special editorial @@ -51,6 +86,7 @@ export type BreadcrumbProps = { const Breadcrumb = ({ label, path, + menu, isCurrent = false, hideDivider = false, isEditorial = false, @@ -70,12 +106,13 @@ const Breadcrumb = ({ > {!hideDivider && } {isCurrent ? ( -

{content}

+

{content}

) : ( {content} )} + {menu} ); }; @@ -92,10 +129,10 @@ const Breadcrumb = ({ */ const Breadcrumbs = ({ a11yName = _("Breadcrumbs"), children }) => { return ( -