mirror of
https://github.com/fleetdm/fleet
synced 2026-05-22 16:39:01 +00:00
fix UI style bug and showing turn off mdm action correctly (#10005)
This commit is contained in:
parent
fed44dd9fa
commit
a410d0a8b4
5 changed files with 322 additions and 13 deletions
|
|
@ -0,0 +1,306 @@
|
|||
import React from "react";
|
||||
import { noop } from "lodash";
|
||||
import { screen } from "@testing-library/react";
|
||||
|
||||
import { createCustomRenderer } from "test/test-utils";
|
||||
import HostActionsDropdown from "./HostActionsDropdown";
|
||||
|
||||
describe("Host Actions Dropdown", () => {
|
||||
describe("Transfer action", () => {
|
||||
it("renders the Transfer action when on premium tier and the user is a global admin", async () => {
|
||||
const render = createCustomRenderer({
|
||||
context: {
|
||||
app: {
|
||||
isPremiumTier: true,
|
||||
isGlobalAdmin: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { user } = render(
|
||||
<HostActionsDropdown
|
||||
onSelect={noop}
|
||||
hostStatus="online"
|
||||
hostMdmEnrollemntStatus={null}
|
||||
/>
|
||||
);
|
||||
|
||||
await user.click(screen.getByText("Actions"));
|
||||
|
||||
expect(screen.getByText("Transfer")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders the Transfer action when on premium tier and the user is a global maintainer", async () => {
|
||||
const render = createCustomRenderer({
|
||||
context: {
|
||||
app: {
|
||||
isPremiumTier: true,
|
||||
isGlobalMaintainer: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { user } = render(
|
||||
<HostActionsDropdown
|
||||
onSelect={noop}
|
||||
hostStatus="online"
|
||||
hostMdmEnrollemntStatus={null}
|
||||
/>
|
||||
);
|
||||
|
||||
await user.click(screen.getByText("Actions"));
|
||||
|
||||
expect(screen.getByText("Transfer")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it("renders the Query action as disabled if the host is offline", async () => {
|
||||
const render = createCustomRenderer();
|
||||
|
||||
const { user } = render(
|
||||
<HostActionsDropdown
|
||||
onSelect={noop}
|
||||
hostStatus="offline"
|
||||
hostMdmEnrollemntStatus="On (automatic)"
|
||||
/>
|
||||
);
|
||||
|
||||
await user.click(screen.getByText("Actions"));
|
||||
|
||||
expect(screen.getByText("Query").parentNode).toHaveClass("is-disabled");
|
||||
});
|
||||
|
||||
it("renders the Show Disk Encryption Key action when on premium tier and we store the disk encryption key", async () => {
|
||||
const render = createCustomRenderer({
|
||||
context: {
|
||||
app: {
|
||||
isPremiumTier: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { user } = render(
|
||||
<HostActionsDropdown
|
||||
onSelect={noop}
|
||||
hostStatus="online"
|
||||
hostMdmEnrollemntStatus={null}
|
||||
doesStoreEncryptionKey
|
||||
/>
|
||||
);
|
||||
|
||||
await user.click(screen.getByText("Actions"));
|
||||
|
||||
expect(screen.getByText("Show disk encryption key")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
describe("Turn off MDM action", () => {
|
||||
it("renders the action when the host is enrolled in mdm and the user is a global admin", async () => {
|
||||
const render = createCustomRenderer({
|
||||
context: {
|
||||
app: {
|
||||
isMdmFeatureFlagEnabled: true, // TODO: remove when we release MDM
|
||||
isGlobalAdmin: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { user } = render(
|
||||
<HostActionsDropdown
|
||||
onSelect={noop}
|
||||
hostStatus="online"
|
||||
hostMdmEnrollemntStatus="On (automatic)"
|
||||
/>
|
||||
);
|
||||
|
||||
await user.click(screen.getByText("Actions"));
|
||||
|
||||
expect(screen.getByText("Turn off MDM")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders the action when the host is enrolled in mdm and the user is a global maintainer", async () => {
|
||||
const render = createCustomRenderer({
|
||||
context: {
|
||||
app: {
|
||||
isMdmFeatureFlagEnabled: true, // TODO: remove when we release MDM
|
||||
isGlobalMaintainer: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { user } = render(
|
||||
<HostActionsDropdown
|
||||
onSelect={noop}
|
||||
hostStatus="online"
|
||||
hostMdmEnrollemntStatus="On (automatic)"
|
||||
/>
|
||||
);
|
||||
|
||||
await user.click(screen.getByText("Actions"));
|
||||
|
||||
expect(screen.getByText("Turn off MDM")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders the action when the host is enrolled in mdm and the user is a team admin", async () => {
|
||||
const render = createCustomRenderer({
|
||||
context: {
|
||||
app: {
|
||||
isMdmFeatureFlagEnabled: true, // TODO: remove when we release MDM
|
||||
isTeamAdmin: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { user } = render(
|
||||
<HostActionsDropdown
|
||||
onSelect={noop}
|
||||
hostStatus="online"
|
||||
hostMdmEnrollemntStatus="On (automatic)"
|
||||
/>
|
||||
);
|
||||
|
||||
await user.click(screen.getByText("Actions"));
|
||||
|
||||
expect(screen.getByText("Turn off MDM")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders the action when the host is enrolled in mdm and the user is a team maintainer", async () => {
|
||||
const render = createCustomRenderer({
|
||||
context: {
|
||||
app: {
|
||||
isMdmFeatureFlagEnabled: true, // TODO: remove when we release MDM
|
||||
isTeamMaintainer: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { user } = render(
|
||||
<HostActionsDropdown
|
||||
onSelect={noop}
|
||||
hostStatus="online"
|
||||
hostMdmEnrollemntStatus="On (automatic)"
|
||||
/>
|
||||
);
|
||||
|
||||
await user.click(screen.getByText("Actions"));
|
||||
|
||||
expect(screen.getByText("Turn off MDM")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders as disabled when the host is offline", async () => {
|
||||
const render = createCustomRenderer({
|
||||
context: {
|
||||
app: {
|
||||
isMdmFeatureFlagEnabled: true, // TODO: remove when we release MDM
|
||||
isTeamMaintainer: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { user, debug } = render(
|
||||
<HostActionsDropdown
|
||||
onSelect={noop}
|
||||
hostStatus="offline"
|
||||
hostMdmEnrollemntStatus="On (automatic)"
|
||||
/>
|
||||
);
|
||||
|
||||
await user.click(screen.getByText("Actions"));
|
||||
|
||||
debug();
|
||||
|
||||
expect(screen.getByText("Turn off MDM").parentNode).toHaveClass(
|
||||
"is-disabled"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Delete action", () => {
|
||||
it("renders when the user is a global admin", async () => {
|
||||
const render = createCustomRenderer({
|
||||
context: {
|
||||
app: {
|
||||
isGlobalAdmin: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { user } = render(
|
||||
<HostActionsDropdown
|
||||
onSelect={noop}
|
||||
hostStatus="online"
|
||||
hostMdmEnrollemntStatus="On (automatic)"
|
||||
/>
|
||||
);
|
||||
|
||||
await user.click(screen.getByText("Actions"));
|
||||
|
||||
expect(screen.getByText("Delete")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders when the user is a global maintainer", async () => {
|
||||
const render = createCustomRenderer({
|
||||
context: {
|
||||
app: {
|
||||
isGlobalMaintainer: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { user } = render(
|
||||
<HostActionsDropdown
|
||||
onSelect={noop}
|
||||
hostStatus="online"
|
||||
hostMdmEnrollemntStatus="On (automatic)"
|
||||
/>
|
||||
);
|
||||
|
||||
await user.click(screen.getByText("Actions"));
|
||||
|
||||
expect(screen.getByText("Delete")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders when the user is a team admin", async () => {
|
||||
const render = createCustomRenderer({
|
||||
context: {
|
||||
app: {
|
||||
isTeamAdmin: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { user } = render(
|
||||
<HostActionsDropdown
|
||||
onSelect={noop}
|
||||
hostStatus="online"
|
||||
hostMdmEnrollemntStatus="On (automatic)"
|
||||
/>
|
||||
);
|
||||
|
||||
await user.click(screen.getByText("Actions"));
|
||||
|
||||
expect(screen.getByText("Delete")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders when the user is a team maintainer", async () => {
|
||||
const render = createCustomRenderer({
|
||||
context: {
|
||||
app: {
|
||||
isTeamMaintainer: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { user } = render(
|
||||
<HostActionsDropdown
|
||||
onSelect={noop}
|
||||
hostStatus="online"
|
||||
hostMdmEnrollemntStatus="On (automatic)"
|
||||
/>
|
||||
);
|
||||
|
||||
await user.click(screen.getByText("Actions"));
|
||||
|
||||
expect(screen.getByText("Delete")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
import React, { useContext } from "react";
|
||||
|
||||
import { MdmEnrollmentStatus } from "interfaces/mdm";
|
||||
import permissionUtils from "utilities/permissions";
|
||||
import { AppContext } from "context/app";
|
||||
|
||||
// @ts-ignore
|
||||
|
|
@ -11,40 +10,38 @@ import { generateHostActionOptions } from "./helpers";
|
|||
const baseClass = "host-actions-dropdown";
|
||||
|
||||
interface IHostActionsDropdownProps {
|
||||
onSelect: (value: string) => void;
|
||||
teamId: number | null;
|
||||
hostStatus: string;
|
||||
hostMdmEnrollemntStatus: MdmEnrollmentStatus | null;
|
||||
doesStoreEncryptionKey?: boolean;
|
||||
onSelect: (value: string) => void;
|
||||
}
|
||||
|
||||
const HostActionsDropdown = ({
|
||||
onSelect,
|
||||
teamId,
|
||||
hostStatus,
|
||||
hostMdmEnrollemntStatus,
|
||||
doesStoreEncryptionKey,
|
||||
}: IHostActionsDropdownProps) => {
|
||||
const {
|
||||
currentUser,
|
||||
isPremiumTier = false,
|
||||
isGlobalAdmin = false,
|
||||
isGlobalMaintainer = false,
|
||||
isMdmFeatureFlagEnabled = false,
|
||||
isTeamAdmin = false,
|
||||
isTeamMaintainer = false,
|
||||
} = useContext(AppContext);
|
||||
|
||||
const options = generateHostActionOptions({
|
||||
isPremiumTier,
|
||||
isGlobalAdmin,
|
||||
isGlobalMaintainer,
|
||||
isTeamAdmin: permissionUtils.isTeamAdmin(currentUser, teamId ?? null),
|
||||
isTeamMaintainer: permissionUtils.isTeamMaintainer(
|
||||
currentUser,
|
||||
teamId ?? null
|
||||
),
|
||||
isTeamAdmin,
|
||||
isTeamMaintainer,
|
||||
isHostOnline: hostStatus === "online",
|
||||
isEnrolledInMdm: ["On (automatic)", "On (manual)"].includes(
|
||||
hostMdmEnrollemntStatus ?? ""
|
||||
),
|
||||
isMdmFeatureFlagEnabled,
|
||||
doesStoreEncryptionKey: doesStoreEncryptionKey ?? false,
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -68,10 +68,14 @@
|
|||
width: 188px;
|
||||
left: unset;
|
||||
top: unset;
|
||||
max-height: 220px;
|
||||
max-height: none;
|
||||
padding: $pad-small;
|
||||
position: absolute;
|
||||
left: -120px;
|
||||
|
||||
.Select-menu {
|
||||
max-height: none;
|
||||
}
|
||||
}
|
||||
|
||||
.Select-arrow {
|
||||
|
|
@ -94,4 +98,4 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ interface IHostActionConfigOptions {
|
|||
isTeamMaintainer: boolean;
|
||||
isHostOnline: boolean;
|
||||
isEnrolledInMdm: boolean;
|
||||
isMdmFeatureFlagEnabled: boolean; // TODO: remove when we release MDM
|
||||
doesStoreEncryptionKey: boolean;
|
||||
}
|
||||
|
||||
|
|
@ -53,8 +54,10 @@ const canEditMdm = (config: IHostActionConfigOptions) => {
|
|||
isTeamAdmin,
|
||||
isTeamMaintainer,
|
||||
isEnrolledInMdm,
|
||||
isMdmFeatureFlagEnabled,
|
||||
} = config;
|
||||
return (
|
||||
isMdmFeatureFlagEnabled &&
|
||||
isEnrolledInMdm &&
|
||||
(isGlobalAdmin || isGlobalMaintainer || isTeamAdmin || isTeamMaintainer)
|
||||
);
|
||||
|
|
|
|||
|
|
@ -540,7 +540,6 @@ const HostDetailsPage = ({
|
|||
return (
|
||||
<HostActionDropdown
|
||||
onSelect={onSelectHostAction}
|
||||
teamId={host.team_id}
|
||||
hostStatus={host.status}
|
||||
hostMdmEnrollemntStatus={host.mdm.enrollment_status}
|
||||
doesStoreEncryptionKey={host.mdm.encryption_key_available}
|
||||
|
|
|
|||
Loading…
Reference in a new issue