diff --git a/frontend/pages/hosts/details/HostDetailsPage/HostActionsDropdown/HostActionsDropdown.tests.tsx b/frontend/pages/hosts/details/HostDetailsPage/HostActionsDropdown/HostActionsDropdown.tests.tsx new file mode 100644 index 0000000000..60e24eb160 --- /dev/null +++ b/frontend/pages/hosts/details/HostDetailsPage/HostActionsDropdown/HostActionsDropdown.tests.tsx @@ -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( + + ); + + 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( + + ); + + 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( + + ); + + 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( + + ); + + 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( + + ); + + 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( + + ); + + 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( + + ); + + 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( + + ); + + 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( + + ); + + 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( + + ); + + 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( + + ); + + 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( + + ); + + 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( + + ); + + await user.click(screen.getByText("Actions")); + + expect(screen.getByText("Delete")).toBeInTheDocument(); + }); + }); +}); diff --git a/frontend/pages/hosts/details/HostDetailsPage/HostActionsDropdown/HostActionsDropdown.tsx b/frontend/pages/hosts/details/HostDetailsPage/HostActionsDropdown/HostActionsDropdown.tsx index 005a24012d..8e589ccb90 100644 --- a/frontend/pages/hosts/details/HostDetailsPage/HostActionsDropdown/HostActionsDropdown.tsx +++ b/frontend/pages/hosts/details/HostDetailsPage/HostActionsDropdown/HostActionsDropdown.tsx @@ -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, }); diff --git a/frontend/pages/hosts/details/HostDetailsPage/HostActionsDropdown/_styles.scss b/frontend/pages/hosts/details/HostDetailsPage/HostActionsDropdown/_styles.scss index 2cf8f38146..d17ab557e7 100644 --- a/frontend/pages/hosts/details/HostDetailsPage/HostActionsDropdown/_styles.scss +++ b/frontend/pages/hosts/details/HostDetailsPage/HostActionsDropdown/_styles.scss @@ -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 @@ } } } -} \ No newline at end of file +} diff --git a/frontend/pages/hosts/details/HostDetailsPage/HostActionsDropdown/helpers.ts b/frontend/pages/hosts/details/HostDetailsPage/HostActionsDropdown/helpers.ts index 5ebcdd0f23..fce1f7a5d6 100644 --- a/frontend/pages/hosts/details/HostDetailsPage/HostActionsDropdown/helpers.ts +++ b/frontend/pages/hosts/details/HostDetailsPage/HostActionsDropdown/helpers.ts @@ -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) ); diff --git a/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx b/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx index 4273011c18..0b6a9420bb 100644 --- a/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx +++ b/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx @@ -540,7 +540,6 @@ const HostDetailsPage = ({ return (