-
Notifications
You must be signed in to change notification settings - Fork 43
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
web: Move storage/BootConfigField to its own file
And adapts it to looks a bit different according the changes proposed in the context of https://trello.com/c/czpTfm3y (internal link). It enables type checking in the storage/BootSelectionDialog.test.jsx too.
- Loading branch information
Showing
6 changed files
with
254 additions
and
76 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
/* | ||
* 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 version 2 of the GNU General Public License as published | ||
* by the Free Software Foundation. | ||
* | ||
* 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. | ||
*/ | ||
|
||
// @ts-check | ||
|
||
import React, { useState } from "react"; | ||
import { Skeleton } from "@patternfly/react-core"; | ||
|
||
import { _ } from "~/i18n"; | ||
import { sprintf } from "sprintf-js"; | ||
import { deviceLabel } from "~/components/storage/utils"; | ||
import { If } from "~/components/core"; | ||
import { Icon } from "~/components/layout"; | ||
import BootSelectionDialog from "~/components/storage/BootSelectionDialog"; | ||
|
||
/** | ||
* @typedef {import ("~/client/storage").StorageDevice} StorageDevice | ||
*/ | ||
|
||
/** | ||
* Internal component for building the button that opens the dialog | ||
* | ||
* @param {object} props | ||
* @param {boolean} [props.isBold=false] - Whether text should be wrapped by <b>. | ||
* @param {() => void} props.onClick - Callback to trigger when user clicks. | ||
*/ | ||
const Button = ({ isBold = false, onClick }) => { | ||
const text = _("Change boot options"); | ||
|
||
return ( | ||
<button onClick={onClick} className="inline-flex-button"> | ||
{isBold ? <b>{text}</b> : text} <Icon name="shadow" size="xxs" /> | ||
</button> | ||
); | ||
}; | ||
|
||
/** | ||
* Allows to select the boot config. | ||
* @component | ||
* | ||
* @param {object} props | ||
* @param {boolean} props.configureBoot | ||
* @param {StorageDevice|undefined} props.bootDevice | ||
* @param {StorageDevice|undefined} props.defaultBootDevice | ||
* @param {StorageDevice[]} props.devices | ||
* @param {boolean} props.isLoading | ||
* @param {(boot: Boot) => void} props.onChange | ||
* | ||
* @typedef {object} Boot | ||
* @property {boolean} configureBoot | ||
* @property {StorageDevice} bootDevice | ||
*/ | ||
export default function BootConfigField ({ | ||
configureBoot, | ||
bootDevice, | ||
defaultBootDevice, | ||
devices, | ||
isLoading, | ||
onChange | ||
}) { | ||
const [isDialogOpen, setIsDialogOpen] = useState(false); | ||
|
||
const openDialog = () => setIsDialogOpen(true); | ||
|
||
const closeDialog = () => setIsDialogOpen(false); | ||
|
||
const onAccept = ({ configureBoot, bootDevice }) => { | ||
closeDialog(); | ||
onChange({ configureBoot, bootDevice }); | ||
}; | ||
|
||
if (isLoading) { | ||
return <Skeleton screenreaderText={_("Waiting for information about boot config")} width="75%" />; | ||
} | ||
|
||
let value; | ||
|
||
if (!configureBoot) { | ||
value = <><Icon name="feedback" size="xs" /> {_("Installation will not create boot partitions.")}</>; | ||
} else if (!bootDevice) { | ||
value = _("Installation might create boot partitions at the installation device."); | ||
} else { | ||
// TRANSLATORS: %s is the disk used to configure the boot-related partitions (eg. "/dev/sda, 80 GiB) | ||
value = sprintf(_("Installation might create boot partitions at %s."), deviceLabel(bootDevice)); | ||
} | ||
|
||
return ( | ||
<div> | ||
{ value } <Button onClick={openDialog} isBold={!configureBoot} /> | ||
<If | ||
condition={isDialogOpen} | ||
then={ | ||
<BootSelectionDialog | ||
isOpen | ||
configureBoot={configureBoot} | ||
bootDevice={bootDevice} | ||
defaultBootDevice={defaultBootDevice} | ||
devices={devices} | ||
onAccept={onAccept} | ||
onCancel={closeDialog} | ||
/> | ||
} | ||
/> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
/* | ||
* 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 version 2 of the GNU General Public License as published | ||
* by the Free Software Foundation. | ||
* | ||
* 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. | ||
*/ | ||
|
||
// @ts-check | ||
|
||
import React from "react"; | ||
import { screen, within } from "@testing-library/react"; | ||
import { plainRender } from "~/test-utils"; | ||
import BootConfigField from "~/components/storage/BootConfigField"; | ||
|
||
const sda = { | ||
sid: 59, | ||
description: "A fake disk for testing", | ||
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, | ||
recoverableSize: 0, | ||
systems : [], | ||
udevIds: ["ata-Micron_1100_SATA_512GB_12563", "scsi-0ATA_Micron_1100_SATA_512GB"], | ||
udevPaths: ["pci-0000:00-12", "pci-0000:00-12-ata"], | ||
}; | ||
|
||
let props; | ||
|
||
beforeEach(() => { | ||
props = { | ||
configureBoot: false, | ||
bootDevice: undefined, | ||
defaultBootDevice: undefined, | ||
devices: [sda], | ||
isLoading: false, | ||
onChange: jest.fn() | ||
}; | ||
}); | ||
|
||
/** | ||
* Helper function that implicitly test that field provides a button for | ||
* opening the dialog | ||
*/ | ||
const openBootConfigDialog = async () => { | ||
const { user } = plainRender(<BootConfigField {...props} />); | ||
const button = screen.getByRole("button"); | ||
await user.click(button); | ||
const dialog = screen.getByRole("dialog", { name: "Partitions for booting" }); | ||
|
||
return { user, dialog }; | ||
}; | ||
|
||
describe("BootConfigField", () => { | ||
it("triggers onChange callback when user confirms the dialog", async () => { | ||
const { user, dialog } = await openBootConfigDialog(); | ||
const button = within(dialog).getByRole("button", { name: "Confirm" }); | ||
await user.click(button); | ||
expect(props.onChange).toHaveBeenCalled(); | ||
}); | ||
|
||
it("does not trigger onChange callback when user cancels the dialog", async () => { | ||
const { user, dialog } = await openBootConfigDialog(); | ||
const button = within(dialog).getByRole("button", { name: "Cancel" }); | ||
await user.click(button); | ||
expect(props.onChange).not.toHaveBeenCalled(); | ||
}); | ||
|
||
describe("when installation is set for not configuring boot", () => { | ||
it("renders a text warning about it", () => { | ||
plainRender(<BootConfigField {...props} />); | ||
screen.getByText(/will not create boot partitions/); | ||
}); | ||
}); | ||
|
||
describe("when installation is set for automatically configuring boot", () => { | ||
it("renders a text reporting about it", () => { | ||
plainRender(<BootConfigField {...props} configureBoot />); | ||
screen.getByText(/create boot partitions at the installation device/); | ||
}); | ||
}); | ||
|
||
describe("when installation is set for configuring boot at specific device", () => { | ||
it("renders a text reporting about it", () => { | ||
plainRender(<BootConfigField {...props} configureBoot bootDevice={sda} />); | ||
screen.getByText(/boot partitions at \/dev\/sda/); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters