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:**   **Off UI:**   - [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:
@@ -0,0 +1 @@
|
||||
- add ability to turn windows mdm on and off from the fleet UI
|
||||
@@ -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,
|
||||
|
||||
@@ -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} />
|
||||
|
||||
+130
@@ -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'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";
|
||||
+70
@@ -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;
|
||||
+33
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export { default } from "./WindowsMdmSection";
|
||||
@@ -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} />
|
||||
|
||||
@@ -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`,
|
||||
|
||||
Reference in New Issue
Block a user