Update device user UI with improved instructions to turn on MDM (#26193)

This commit is contained in:
Sarah Gillespie
2025-02-11 12:22:18 -06:00
committed by GitHub
parent 2b0be3771d
commit 2dce287704
7 changed files with 366 additions and 41 deletions
+1
View File
@@ -0,0 +1 @@
- Updated UI for device user page with improved instructions for turning on MDM.
@@ -1,5 +1,8 @@
import React from "react";
// @ts-ignore
import InputField from "components/forms/fields/InputField";
import Button from "components/buttons/Button";
import Modal from "components/Modal";
import { IDeviceUserResponse } from "interfaces/host";
@@ -37,13 +40,29 @@ const AutoEnrollMdmModal = ({
<li>
Select the <b>Device Enrollment</b> notification. This will open{" "}
<b>System Settings</b>. Select <b>Allow</b>.
<div className={`${baseClass}__profiles-renew`}>
<div className={`${baseClass}__profiles-renew--instructions`}>
If you don&apos;t see <b>Enroll in Remote Management</b>, open
your <b>Terminal</b> app (<b>Finder</b> {">"} <b>Applications</b>{" "}
{">"} <b>Utilities</b> folder), copy and paste the below command,
press enter, enter your password, and press enter again.
</div>
<InputField
enableCopy
copyButtonPosition="inside"
readOnly
inputWrapperClass
name="profiles-renew-command"
value={"sudo profiles renew -type enrollment"}
/>
</div>
</li>
<li>
Enter your password, and select <b>Enroll</b>.
</li>
<li>
Select <b>Done</b> to close this window and select Refetch on your My
device page to tell your organization that MDM is on.
Select <b>Done</b> to close this window and select <b>Refetch</b> on
your My device page to tell your organization that MDM is on.
</li>
</ol>
</>
@@ -52,23 +71,39 @@ const AutoEnrollMdmModal = ({
const sonomaAndAboveBody = (
<>
<p className={`${baseClass}__description`}>
To turn on MDM, Apple Inc. requires that you install a profile.
To turn on MDM, Apple Inc. requires that you follow the steps below.
</p>
<ol>
<li>
From the Apple menu in the top left corner of your screen, select{" "}
<b>System Settings</b> or <b>System Preferences</b>.
<b>System Settings</b>.
</li>
<li>
In the sidebar menu, select <b>Enroll in Remote Management</b>, and
select <b>Enroll</b>.
<div className={`${baseClass}__profiles-renew`}>
<div className={`${baseClass}__profiles-renew--instructions`}>
If you don&apos;t see <b>Enroll in Remote Management</b>, open
your <b>Terminal</b> app (<b>Finder</b> {">"} <b>Applications</b>{" "}
{">"} <b>Utilities</b> folder), copy and paste the below command,
press enter, enter your password, and press enter again.
</div>
<InputField
enableCopy
copyButtonPosition="inside"
readOnly
inputWrapperClass
name="profiles-renew-command"
value={"sudo profiles renew -type enrollment"}
/>
</div>
</li>
<li>
Enter your password, and select <b>Enroll</b>.
</li>
<li>
Close this window and select <b>Refetch</b> on your My device page to
tell your organization that MDM is on.
Select <b>Done</b> to close this window and select <b>Refetch</b> on
your My device page to tell your organization that MDM is on.
</li>
</ol>
</>
@@ -1,3 +1,13 @@
.auto-enroll-mdm-modal {
@include enroll-mdm-modal;
&__profiles-renew {
margin: 0 0 0 $pad-medium;
&--instructions {
color: $ui-fleet-black-75;
margin-top: $pad-small;
margin-bottom: $pad-small;
}
}
}
@@ -148,4 +148,269 @@ describe("Device User Page", () => {
expect(btn).toBeNull();
});
});
// // FIXME: revisit these tests when we have a better way to test modals
// describe("AutoEnrollMDMModal", () => {
// it("shows the pre-Sonoma body when the host is pre-Sonoma", async () => {
// const host = createMockHost() as IHostDevice;
// host.platform = "darwin";
// host.os_version = "macOS 13.1.1";
// host.dep_assigned_to_fleet = true;
// mockServer.use(
// customDeviceHandler({
// host,
// global_config: {
// mdm: { enabled_and_configured: true },
// features: { enable_software_inventory: false },
// },
// })
// );
// const render = createCustomRenderer({
// withBackendMock: true,
// });
// const { user } = render(
// <DeviceUserPage
// router={mockRouter}
// params={{ device_auth_token: "testToken" }}
// location={mockLocation}
// />
// );
// // waiting for the device data to render
// await screen.findByText("About");
// // open the modal
// await user.click(screen.getByRole("button", { name: "Turn on MDM" }));
// // waiting for the modal to render
// await screen.findByText("To turn on MDM,");
// // autoenroll-specific copy
// expect(
// screen.getByText("sudo profiles renew -type enrollment")
// ).toBeInTheDocument();
// // version-specific copy
// expect(screen.getByText("notification center")).toBeInTheDocument();
// });
// it("shows the Sonoma-and-above body when the host is Sonoma", async () => {
// const host = createMockHost() as IHostDevice;
// host.platform = "darwin";
// host.os_version = "macOS 14.7";
// host.dep_assigned_to_fleet = true;
// mockServer.use(
// customDeviceHandler({
// host,
// global_config: {
// mdm: { enabled_and_configured: true },
// features: { enable_software_inventory: false },
// },
// })
// );
// const render = createCustomRenderer({
// withBackendMock: true,
// });
// const { user } = render(
// <DeviceUserPage
// router={mockRouter}
// params={{ device_auth_token: "testToken" }}
// location={mockLocation}
// />
// );
// // waiting for the device data to render
// await screen.findByText("About");
// // open the modal
// await user.click(screen.getByRole("button", { name: "Turn on MDM" }));
// // waiting for the modal to render
// await screen.findByText("To turn on MDM,");
// // autoenroll-specific copy
// expect(
// screen.getByText("sudo profiles renew -type enrollment")
// ).toBeInTheDocument();
// // version-specific copy
// expect(screen.getByText("System Settings")).toBeInTheDocument();
// });
// it("shows the Sonoma-and-above body when the host is post-Sonoma", async () => {
// const host = createMockHost() as IHostDevice;
// host.platform = "darwin";
// host.os_version = "macOS 15.3";
// host.dep_assigned_to_fleet = true;
// mockServer.use(
// customDeviceHandler({
// host,
// global_config: {
// mdm: { enabled_and_configured: true },
// features: { enable_software_inventory: false },
// },
// })
// );
// const render = createCustomRenderer({
// withBackendMock: true,
// });
// const { user } = render(
// <DeviceUserPage
// router={mockRouter}
// params={{ device_auth_token: "testToken" }}
// location={mockLocation}
// />
// );
// // waiting for the device data to render
// await screen.findByText("About");
// // open the modal
// await user.click(screen.getByRole("button", { name: "Turn on MDM" }));
// // waiting for the modal to render
// await screen.findByText("To turn on MDM,");
// // autoenroll-specific copy
// expect(
// screen.getByText("sudo profiles renew -type enrollment")
// ).toBeInTheDocument();
// // version-specific copy
// expect(screen.getByText("System Settings")).toBeInTheDocument();
// });
// });
// // FIXME: revisit these tests when we have a better way to test modals
// describe("ManualEnrollMDMModal", () => {
// it("shows the pre-Seqouia body when the host is pre-Seqouia", async () => {
// const host = createMockHost() as IHostDevice;
// host.platform = "darwin";
// host.os_version = "macOS 14.1.1";
// mockServer.use(
// customDeviceHandler({
// host,
// global_config: {
// mdm: { enabled_and_configured: false },
// features: { enable_software_inventory: true },
// },
// })
// );
// const render = createCustomRenderer({
// withBackendMock: true,
// });
// const { user } = render(
// <DeviceUserPage
// router={mockRouter}
// params={{ device_auth_token: "testToken" }}
// location={mockLocation}
// />
// );
// // waiting for the device data to render
// await screen.findByText("About");
// // open the modal
// await user.click(screen.getByRole("button", { name: "Turn on MDM" }));
// // waiting for the modal to render
// await screen.findByText("To turn on MDM,");
// // manualenroll-specific copy
// expect(screen.getByText("Download your profile.")).toBeInTheDocument();
// // version-specific copy
// expect(screen.getByText("In the search bar")).toBeInTheDocument();
// });
// it("shows the Sequoia-and-above body when the host is Sequoia", async () => {
// const host = createMockHost() as IHostDevice;
// host.platform = "darwin";
// host.os_version = "macOS 15.3";
// mockServer.use(
// customDeviceHandler({
// host,
// global_config: {
// mdm: { enabled_and_configured: false },
// features: { enable_software_inventory: true },
// },
// })
// );
// const render = createCustomRenderer({
// withBackendMock: true,
// });
// const { user } = render(
// <DeviceUserPage
// router={mockRouter}
// params={{ device_auth_token: "testToken" }}
// location={mockLocation}
// />
// );
// // waiting for the device data to render
// await screen.findByText("About");
// // open the modal
// await user.click(screen.getByRole("button", { name: "Turn on MDM" }));
// // waiting for the modal to render
// await screen.findByText("To turn on MDM,");
// // manualenroll-specific copy
// expect(screen.getByText("Download your profile.")).toBeInTheDocument();
// // version-specific copy
// expect(screen.getByText("In the sidebar menu")).toBeInTheDocument();
// });
// it("shows the Sequoia-and-above body when the host is post-Sequoia", async () => {
// const host = createMockHost() as IHostDevice;
// host.platform = "darwin";
// host.os_version = "macOS 16.0";
// mockServer.use(
// customDeviceHandler({
// host,
// global_config: {
// mdm: { enabled_and_configured: false },
// features: { enable_software_inventory: true },
// },
// })
// );
// const render = createCustomRenderer({
// withBackendMock: true,
// });
// const { user } = render(
// <DeviceUserPage
// router={mockRouter}
// params={{ device_auth_token: "testToken" }}
// location={mockLocation}
// />
// );
// // waiting for the device data to render
// await screen.findByText("About");
// // open the modal
// await user.click(screen.getByRole("button", { name: "Turn on MDM" }));
// // waiting for the modal to render
// await screen.findByText("To turn on MDM,");
// // manual-specific copy
// expect(screen.getByText("Download your profile.")).toBeInTheDocument();
// // version-specific copy
// expect(screen.getByText("In the sidebar menu")).toBeInTheDocument();
// });
// });
});
@@ -311,17 +311,6 @@ const DeviceUserPage = ({
);
};
const renderEnrollMdmModal = () => {
return host?.dep_assigned_to_fleet ? (
<AutoEnrollMdmModal host={host} onCancel={toggleEnrollMdmModal} />
) : (
<ManualEnrollMdmModal
onCancel={toggleEnrollMdmModal}
token={deviceAuthToken}
/>
);
};
const onTriggerEscrowLinuxKey = async () => {
setIsTriggeringCreateLinuxKey(true);
// modal opens in loading state
@@ -474,7 +463,19 @@ const DeviceUserPage = ({
</Tabs>
</TabsWrapper>
{showInfoModal && <InfoModal onCancel={toggleInfoModal} />}
{showEnrollMdmModal && renderEnrollMdmModal()}
{showEnrollMdmModal &&
(host.dep_assigned_to_fleet ? (
<AutoEnrollMdmModal
host={host}
onCancel={toggleEnrollMdmModal}
/>
) : (
<ManualEnrollMdmModal
host={host}
onCancel={toggleEnrollMdmModal}
token={deviceAuthToken}
/>
))}
</div>
)}
{!!host && showPolicyDetailsModal && (
@@ -6,8 +6,10 @@ import mdmAPI from "services/entities/mdm";
import Button from "components/buttons/Button";
import Modal from "components/Modal";
import { NotificationContext } from "context/notification";
import { IDeviceUserResponse } from "interfaces/host";
interface IManualEnrollMdmModalProps {
host: IDeviceUserResponse["host"];
onCancel: () => void;
token?: string;
}
@@ -15,6 +17,7 @@ interface IManualEnrollMdmModalProps {
const baseClass = "manual-enroll-mdm-modal";
const ManualEnrollMdmModal = ({
host: { platform, os_version },
onCancel,
token = "",
}: IManualEnrollMdmModalProps): JSX.Element => {
@@ -35,8 +38,23 @@ const ManualEnrollMdmModal = ({
}
};
const renderModalBody = () => {
return (
let isMacOsSequoiaOrLater = false;
if (platform === "darwin" && os_version.startsWith("macOS ")) {
const [major] = os_version
.replace("macOS ", "")
.split(".")
.map((s) => parseInt(s, 10));
isMacOsSequoiaOrLater = major >= 15;
}
return (
<Modal
title="Turn on MDM"
onExit={onCancel}
onEnter={onCancel}
className={baseClass}
width="xlarge"
>
<div>
<p className={`${baseClass}__description`}>
To turn on MDM, Apple Inc. requires that you download and install a
@@ -60,17 +78,25 @@ const ManualEnrollMdmModal = ({
<b>System Settings</b>.
</li>
<li>
In the search bar, type Profiles. Select <b>Profiles</b>, find and
double click the <br /> <b>[Organization name] enrollment</b>{" "}
profile.
{isMacOsSequoiaOrLater ? (
<>
In the sidebar menu, select <b>Profile Downloaded</b>, find and
double-click the <b>[Organization name] enrollment</b> profile.
</>
) : (
<>
In the search bar, type Profiles. Select <b>Profiles</b>, find
and double click the <b>[Organization name] enrollment</b>{" "}
profile.
</>
)}
</li>
<li>
Select <b>Install...</b> then confirm again clicking <b>Install</b>.
Select <b>Enroll</b> then enter your password.
</li>
<li>Enter your password when you get a prompt.</li>
<li>
Select <b>Done</b> to close this window and select <b>Refetch</b> on
your My device page to tell <br /> your organization that MDM is on.
your My device page to tell your organization that MDM is on.
</li>
</ol>
<div className="modal-cta-wrap">
@@ -79,18 +105,6 @@ const ManualEnrollMdmModal = ({
</Button>
</div>
</div>
);
};
return (
<Modal
title="Turn on MDM"
onExit={onCancel}
onEnter={onCancel}
className={baseClass}
width="xlarge"
>
{renderModalBody()}
</Modal>
);
};
@@ -54,9 +54,8 @@ const DeviceUserBanners = ({
return (
<InfoBanner color="yellow" cta={turnOnMdmButton}>
Mobile device management (MDM) is off. MDM allows your organization to
enforce settings, OS updates, disk encryption, and more. This lets
your organization keep your device up to date so you don&apos;t have
to.
change settings and install software. This lets your organization keep
your device up to date so you don&apos;t have to.
</InfoBanner>
);
}