Feat UI host transfer delete warnings (#26287)

For #25656

changed the copy for the delete and transfer host modal to be more clear
about the disk encryption key behaviour

**delete host modal**


![image](https://github.com/user-attachments/assets/e2f74f3b-fdd1-4cae-970e-44035c7630af)

**Transfer host modal**


![image](https://github.com/user-attachments/assets/8271eaae-9d80-4385-9704-860d7dc02588)


If some of the following don't apply, delete the relevant line.

<!-- Note that API documentation changes are now addressed by the
product design team. -->

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
- [x ] Added/updated automated tests
- [x] Manual QA for all new/changed functionality
This commit is contained in:
Gabriel Hernandez
2025-02-17 13:25:22 +00:00
committed by GitHub
parent 56b3a4bbef
commit 63bec832aa
5 changed files with 174 additions and 47 deletions
@@ -0,0 +1,2 @@
- changed the copy for the delete and transfer host modal to be more clear about the disk encryption
key behavior
@@ -0,0 +1,64 @@
import React from "react";
import { noop } from "lodash";
import { render, screen } from "@testing-library/react";
import DeleteHostModal from "./DeleteHostModal";
describe("DeleteHostModal", () => {
it("renders the number of hosts selected", () => {
render(
<DeleteHostModal
selectedHostIds={[1, 2, 3]}
onSubmit={noop}
onCancel={noop}
isUpdating={false}
/>
);
expect(screen.getByText("3 hosts")).toBeVisible();
});
it("renders the host name when only the host name is provided", () => {
render(
<DeleteHostModal
hostName="Host1"
onSubmit={noop}
onCancel={noop}
isUpdating={false}
/>
);
expect(screen.getByText("Host1")).toBeVisible();
});
it("renders the number of hosts selected with '+' after when select all matching hosts is true", () => {
render(
<DeleteHostModal
selectedHostIds={[1, 2, 3]}
hostsCount={50}
isAllMatchingHostsSelected
onSubmit={noop}
onCancel={noop}
isUpdating={false}
/>
);
expect(screen.getByText("3+ hosts")).toBeVisible();
});
it("renders the host count with '+' and an additional warning when there are more than 500 hosts and select all matching hosts is true", () => {
render(
<DeleteHostModal
selectedHostIds={[1, 2, 3]}
hostsCount={500}
isAllMatchingHostsSelected
onSubmit={noop}
onCancel={noop}
isUpdating={false}
/>
);
expect(screen.getByText("3+ hosts")).toBeVisible();
expect(
screen.getByText(
"When deleting a large volume of hosts, it may take some time for this change to be reflected in the UI."
)
).toBeVisible();
});
});
@@ -47,25 +47,26 @@ const DeleteHostModal = ({
}
return hostName;
};
const largeVolumeText = (): string => {
if (
selectedHostIds &&
isAllMatchingHostsSelected &&
hostsCount &&
hostsCount >= 500
) {
return " When deleting a large volume of hosts, it may take some time for this change to be reflected in the UI.";
}
return "";
};
const hasManyHosts =
selectedHostIds &&
isAllMatchingHostsSelected &&
hostsCount &&
hostsCount >= 500;
return (
<Modal title="Delete host" onExit={onCancel} className={baseClass}>
<>
<p>
This will remove the record of <b>{hostText()}</b> and associated data
(e.g. unlock PINs).{largeVolumeText()}
such as unlock PINs and disk encryption keys.
</p>
{hasManyHosts && (
<p>
When deleting a large volume of hosts, it may take some time for
this change to be reflected in the UI.
</p>
)}
<ul>
<li>
macOS, Windows, or Linux hosts will re-appear unless Fleet&apos;s
@@ -0,0 +1,45 @@
import React from "react";
import { noop } from "lodash";
import { render, screen } from "@testing-library/react";
import TransferHostModal from "./TransferHostModal";
describe("TransferHostModal", () => {
it("renders the correct message when more than one host is being transfered", () => {
render(
<TransferHostModal
multipleHosts
teams={[]}
onSubmit={noop}
onCancel={noop}
isUpdating={false}
isGlobalAdmin={false}
/>
);
expect(
screen.getByText(
"The hosts' disk encryption keys are deleted if they're transferred to a team with disk encryption turned off."
)
).toBeVisible();
});
it("render the correct message when one host is being transfered", () => {
render(
<TransferHostModal
multipleHosts={false}
teams={[]}
onSubmit={noop}
onCancel={noop}
isUpdating={false}
isGlobalAdmin={false}
/>
);
expect(
screen.getByText(
"The host's disk encryption key is deleted if it's transferred to a team with disk encryption turned off."
)
).toBeVisible();
});
});
@@ -65,43 +65,58 @@ const TransferHostModal = ({
return [NO_TEAM_OPTION, ...teamOptions];
};
const diskEncryptionMsg = (
<>
The {multipleHosts ? "hosts'" : "host's"} disk encryption{" "}
{multipleHosts ? "keys are" : "key is"} deleted if{" "}
{multipleHosts ? "they're" : "it's"} transferred to a team with disk
encryption turned off.
</>
);
return (
<Modal onExit={onCancel} title="Transfer hosts" className={baseClass}>
<form className={`${baseClass}__form`}>
<Dropdown
wrapperClassName={`${baseClass}__team-dropdown-wrapper`}
label={`Transfer ${multipleHosts ? "selected hosts" : "host"} to:`}
value={selectedTeam && selectedTeam.id}
options={createTeamDropdownOptions()}
onChange={onChangeSelectTeam}
placeholder="Select a team"
searchable={false}
autoFocus
/>
{isGlobalAdmin ? (
<p>
Team not here?{" "}
<Link to={PATHS.ADMIN_TEAMS} className={`${baseClass}__team-link`}>
Create a team
</Link>
</p>
) : null}
<div className="modal-cta-wrap">
<Button
disabled={selectedTeam === undefined}
type="button"
variant="brand"
onClick={onSubmitTransferHost}
className="transfer-loading"
isLoading={isUpdating}
>
Transfer
</Button>
<Button onClick={onCancel} variant="inverse">
Cancel
</Button>
</div>
</form>
<>
<p>{diskEncryptionMsg}</p>
<form className={`${baseClass}__form`}>
<Dropdown
wrapperClassName={`${baseClass}__team-dropdown-wrapper`}
label={`Transfer ${multipleHosts ? "selected hosts" : "host"} to:`}
value={selectedTeam && selectedTeam.id}
options={createTeamDropdownOptions()}
onChange={onChangeSelectTeam}
placeholder="Select a team"
searchable={false}
autoFocus
/>
{isGlobalAdmin ? (
<p>
Team not here?{" "}
<Link
to={PATHS.ADMIN_TEAMS}
className={`${baseClass}__team-link`}
>
Create a team
</Link>
</p>
) : null}
<div className="modal-cta-wrap">
<Button
disabled={selectedTeam === undefined}
type="button"
variant="brand"
onClick={onSubmitTransferHost}
className="transfer-loading"
isLoading={isUpdating}
>
Transfer
</Button>
<Button onClick={onCancel} variant="inverse">
Cancel
</Button>
</div>
</form>
</>
</Modal>
);
};