turn on/off windows mdm from the fleet UI (#12497)

relates to #12258

Implements turning on and off windows MDM from the Fleet UI.

**On UI:**


![image](https://github.com/fleetdm/fleet/assets/1153709/2cb0e1b4-1b87-421e-b9c0-899d12e0f463)


![image](https://github.com/fleetdm/fleet/assets/1153709/e26453cc-0467-446e-975c-dbb2293b7199)

**Off UI:**


![image](https://github.com/fleetdm/fleet/assets/1153709/cd4c9b8f-571b-4b01-9be4-322154a5c954)


![image](https://github.com/fleetdm/fleet/assets/1153709/757d0b23-9e1b-45bf-b84b-82b079dd0ccc)

- [x] Changes file added for user-visible changes in `changes/` or
`orbit/changes/`.
See [Changes
files](https://fleetdm.com/docs/contributing/committing-changes#changes-files)
for more information.
- [x] Manual QA for all new/changed functionality
This commit is contained in:
Gabriel Hernandez
2023-06-26 17:54:34 +01:00
committed by GitHub
parent ca02abb660
commit 792e9c7cd1
12 changed files with 278 additions and 5 deletions
@@ -0,0 +1 @@
- add ability to turn windows mdm on and off from the fleet UI
+1
View File
@@ -124,6 +124,7 @@ const DEFAULT_CONFIG_MOCK: IConfig = {
},
fleet_desktop: { transparency_url: "https://fleetdm.com/transparency" },
mdm: {
windows_enabled_and_configured: true,
apple_bm_default_team: "Apples",
apple_bm_enabled_and_configured: true,
apple_bm_terms_expired: false,
+3
View File
@@ -47,6 +47,7 @@ export default PropTypes.shape({
enabled_and_configured: PropTypes.bool,
apple_bm_terms_expired: PropTypes.bool,
apple_bm_enabled_and_configured: PropTypes.bool,
windows_enabled_and_configured: PropTypes.bool,
macos_updates: PropTypes.shape({
minimum_version: PropTypes.string,
deadline: PropTypes.string,
@@ -116,6 +117,7 @@ export interface IMdmConfig {
apple_bm_default_team?: string;
apple_bm_terms_expired: boolean;
apple_bm_enabled_and_configured: boolean;
windows_enabled_and_configured: boolean;
end_user_authentication: IEndUserAuthentication;
macos_updates: {
minimum_version: string;
@@ -282,6 +284,7 @@ export interface IConfig {
};
};
mdm: IMdmConfig;
mdm_enabled?: boolean; // TODO: remove when windows MDM is released. Only used for windows MDM dev currently.
}
export interface IWebhookSettings {
@@ -8,14 +8,16 @@ import { AppContext } from "context/app";
import mdmAppleAPI from "services/entities/mdm_apple";
import { IMdmApple } from "interfaces/mdm";
import { readableDate } from "utilities/helpers";
import PATHS from "router/paths";
import Button from "components/buttons/Button";
import CustomLink from "components/CustomLink";
import Spinner from "components/Spinner";
import DataError from "components/DataError";
import { readableDate } from "utilities/helpers";
import RequestCSRModal from "./components/RequestCSRModal";
import EndUserMigrationSection from "./components/EndUserMigrationSection/EndUserMigrationSection";
import WindowsMdmSection from "./components/WindowsMdmSection/WindowsMdmSection";
const baseClass = "mdm-settings";
@@ -46,6 +48,10 @@ const MdmSettings = ({ router }: IMdmSettingsProps) => {
setShowRequestCSRModal(!showRequestCSRModal);
};
const navigateToWindowsMdm = () => {
router.push(PATHS.ADMIN_INTEGRATIONS_MDM_WINDOWS);
};
// The API returns a 404 error if APNs is not configured yet, in that case we
// want to prompt the user to download the certs and keys to configure the
// server instead of the default error message.
@@ -127,10 +133,19 @@ const MdmSettings = ({ router }: IMdmSettingsProps) => {
<h2>Apple Push Certificates Portal</h2>
{isLoadingMdmApple ? <Spinner /> : renderMdmAppleSection()}
</div>
{/* TODO: remove conditional rendering when windows MDM is released. */}
{config?.mdm_enabled && (
<WindowsMdmSection
turnOnWindowsMdm={navigateToWindowsMdm}
editWindowsMdm={navigateToWindowsMdm}
/>
)}
{isPremiumTier && (
<div className={`${baseClass}__section`}>
<EndUserMigrationSection router={router} />
</div>
<>
<div className={`${baseClass}__section`}>
<EndUserMigrationSection router={router} />
</div>
</>
)}
{showRequestCSRModal && (
<RequestCSRModal onCancel={toggleRequestCSRModal} />
@@ -0,0 +1,130 @@
import React, { useContext } from "react";
import { InjectedRouter } from "react-router";
import PATHS from "router/paths";
import configAPI from "services/entities/config";
import { NotificationContext } from "context/notification";
import { AppContext } from "context/app";
import MainContent from "components/MainContent/MainContent";
import Button from "components/buttons/Button";
import BackLink from "components/BackLink/BackLink";
const baseClass = "windows-mdm-page";
interface ISetWindowsMdmOptions {
enable: boolean;
successMessage: string;
errorMessage: string;
router: InjectedRouter;
}
const useSetWindowsMdm = ({
enable,
successMessage,
errorMessage,
router,
}: ISetWindowsMdmOptions) => {
const { setConfig } = useContext(AppContext);
const { renderFlash } = useContext(NotificationContext);
const turnOnWindowsMdm = async () => {
try {
const updatedConfig = await configAPI.update({
mdm: {
windows_enabled_and_configured: enable,
},
});
setConfig(updatedConfig);
renderFlash("success", successMessage);
} catch {
renderFlash("error", errorMessage);
} finally {
router.push(PATHS.ADMIN_INTEGRATIONS_MDM);
}
};
return turnOnWindowsMdm;
};
interface IWindowsMdmOnContentProps {
router: InjectedRouter;
}
const WindowsMdmOnContent = ({ router }: IWindowsMdmOnContentProps) => {
const turnOnWindowsMdm = useSetWindowsMdm({
enable: true,
successMessage: "Windows MDM turned on (servers excluded).",
errorMessage: "Unable to turn on Windows MDM. Please try again.",
router,
});
return (
<>
<h1>Turn on Windows MDM</h1>
<p>
This will turn MDM on for Windows hosts with fleetd, overriding existing
MDM solutions.
</p>
<p>MDM won&apos;t be turned on for Windows servers</p>
<Button onClick={turnOnWindowsMdm}>Turn on</Button>
</>
);
};
interface IWindowsMdmOffContentProps {
router: InjectedRouter;
}
const WindowsMdmOffContent = ({ router }: IWindowsMdmOffContentProps) => {
const turnOffWindowsMdm = useSetWindowsMdm({
enable: false,
successMessage: "Windows MDM turned off.",
errorMessage: "Unable to turn off Windows MDM. Please try again.",
router,
});
return (
<>
<h1>Turn off Windows MDM</h1>
<p>This will turn off MDM on each Windows host.</p>
<Button onClick={turnOffWindowsMdm}>Turn off MDM</Button>
</>
);
};
interface IWindowsMdmPageProps {
router: InjectedRouter;
}
const WindowsMdmPage = ({ router }: IWindowsMdmPageProps) => {
const { config } = useContext(AppContext);
// TODO: remove when windows MDM is fully released. This is a temporary redirect
// when the feature is not enabled.
if (!config?.mdm_enabled) {
router.replace(PATHS.ADMIN_INTEGRATIONS_MDM);
}
const isWindowsMdmEnabled =
config?.mdm?.windows_enabled_and_configured ?? false;
return (
<MainContent className={baseClass}>
<>
<BackLink
text="Back to MDM"
path={PATHS.ADMIN_INTEGRATIONS_MDM}
className={`${baseClass}__back-to-mdm`}
/>
{isWindowsMdmEnabled ? (
<WindowsMdmOffContent router={router} />
) : (
<WindowsMdmOnContent router={router} />
)}
</>
</MainContent>
);
};
export default WindowsMdmPage;
@@ -0,0 +1,15 @@
.windows-mdm-page {
&__back-to-mdm {
margin-bottom: $pad-xlarge;
}
h1 {
margin-bottom: $pad-xxlarge;
}
p {
font-size: $x-small;
margin: 0 0 $pad-large;
}
}
@@ -0,0 +1 @@
export { default } from "./WindowsMdmPage";
@@ -0,0 +1,70 @@
import React, { useContext } from "react";
import { AppContext } from "context/app";
import Card from "components/Card/Card";
import Button from "components/buttons/Button";
import Icon from "components/Icon";
const baseClass = "windows-mdm-section";
interface ITurnOnWindowsMdmProps {
onClickTurnOn: () => void;
}
const TurnOnWindowsMdm = ({ onClickTurnOn }: ITurnOnWindowsMdmProps) => {
return (
<div className={`${baseClass}__turn-on-windows`}>
<div className={`${baseClass}__`}>
<h3>Turn on Windows MDM</h3>
<p>Turn MDM on for Windows hosts with fleetd.</p>
</div>
<Button onClick={onClickTurnOn}>Turn on</Button>
</div>
);
};
interface ITurnOffWindowsMdmProps {
onClickEdit: () => void;
}
const TurnOffWindowsMdm = ({ onClickEdit }: ITurnOffWindowsMdmProps) => {
return (
<div className={`${baseClass}__turn-off-windows`}>
<div>
<Icon name="success" />
<p>Windows MDM turned on (servers excluded).</p>
</div>
<Button onClick={onClickEdit} variant="text-icon">
<Icon name="pencil" />
Edit
</Button>
</div>
);
};
interface IWindowsMdmSectionProps {
turnOnWindowsMdm: () => void;
editWindowsMdm: () => void;
}
const WindowsMdmSection = ({
turnOnWindowsMdm,
editWindowsMdm,
}: IWindowsMdmSectionProps) => {
const { config } = useContext(AppContext);
const isWindowsMdmEnabled =
config?.mdm?.windows_enabled_and_configured ?? false;
return (
<Card className={baseClass} color="gray">
{isWindowsMdmEnabled ? (
<TurnOffWindowsMdm onClickEdit={editWindowsMdm} />
) : (
<TurnOnWindowsMdm onClickTurnOn={turnOnWindowsMdm} />
)}
</Card>
);
};
export default WindowsMdmSection;
@@ -0,0 +1,33 @@
.windows-mdm-section {
font-size: $x-small;
p {
margin: 0;
}
&__turn-on-windows, &__turn-off-windows {
display: flex;
justify-content: space-between;
align-items: center;
}
&__turn-on-windows {
h3 {
font-size: $x-small;
font-weight: $bold;
margin: 0 0 $pad-xsmall;
}
}
&__turn-off-windows {
> div {
display: flex;
align-items: center;
}
p {
margin-left: $pad-small;
}
}
}
@@ -0,0 +1 @@
export { default } from "./WindowsMdmSection";
+2
View File
@@ -53,6 +53,7 @@ import AgentOptionsPage from "pages/admin/TeamManagementPage/TeamDetailsWrapper/
import MacOSUpdates from "pages/ManageControlsPage/MacOSUpdates";
import MacOSSettings from "pages/ManageControlsPage/MacOSSettings";
import MacOSSetup from "pages/ManageControlsPage/MacOSSetup/MacOSSetup";
import WindowsMdmPage from "pages/admin/IntegrationsPage/cards/MdmSettings/WindowsMdmPage/WindowsMdmPage";
import PATHS from "router/paths";
@@ -136,6 +137,7 @@ const routes = (
</Route>
</Route>
</Route>
<Route path="integrations/mdm/windows" component={WindowsMdmPage} />
<Route path="teams" component={TeamDetailsWrapper}>
<Route path="members" component={MembersPage} />
<Route path="options" component={AgentOptionsPage} />
+1
View File
@@ -22,6 +22,7 @@ export default {
ADMIN_INTEGRATIONS: `${URL_PREFIX}/settings/integrations`,
ADMIN_INTEGRATIONS_TICKET_DESTINATIONS: `${URL_PREFIX}/settings/integrations/ticket-destinations`,
ADMIN_INTEGRATIONS_MDM: `${URL_PREFIX}/settings/integrations/mdm`,
ADMIN_INTEGRATIONS_MDM_WINDOWS: `${URL_PREFIX}/settings/integrations/mdm/windows`,
ADMIN_INTEGRATIONS_AUTOMATIC_ENROLLMENT: `${URL_PREFIX}/settings/integrations/automatic-enrollment`,
ADMIN_TEAMS: `${URL_PREFIX}/settings/teams`,
ADMIN_SETTINGS: `${URL_PREFIX}/settings`,