Update controls tabs to show mdm disabled UI state per tab (#13794)

relates to #9831

Update Controls page to individually show the mdm disabled UI state per
tab. Before this was done across the entire control page:


![image](https://github.com/fleetdm/fleet/assets/1153709/67a88cf4-c489-46aa-a802-58c4ef61ac5a)


Also, refactors the code to be less specific to mac OS.


- [x] Manual QA for all new/changed functionality
This commit is contained in:
Gabriel Hernandez
2023-09-11 12:52:24 +01:00
committed by GitHub
parent 22e75a2f9b
commit fa252e4977
81 changed files with 145 additions and 113 deletions
+2 -2
View File
@@ -112,9 +112,9 @@ const App = ({ children, location }: IAppProps): JSX.Element => {
// Override Controls page title if MDM not configured
if (
!config?.mdm.enabled_and_configured &&
curTitle?.path === "/controls/mac-os-updates"
curTitle?.path === "/controls/os-updates"
) {
curTitle.title = "Manage macOS hosts | Fleet for osquery";
curTitle.title = "Manage OS hosts | Fleet for osquery";
}
if (curTitle && curTitle.title) {
@@ -1 +0,0 @@
export { default } from "./MacOSSettings";
@@ -1 +0,0 @@
export { default } from "./MacOSSetup";
@@ -1 +0,0 @@
export { default } from "./MacOSUpdates";
@@ -9,8 +9,6 @@ import useTeamIdParam from "hooks/useTeamIdParam";
import TabsWrapper from "components/TabsWrapper";
import MainContent from "components/MainContent";
import TeamsDropdown from "components/TeamsDropdown";
import EmptyTable from "components/EmptyTable";
import Button from "components/buttons/Button";
interface IControlsSubNavItem {
name: string;
@@ -19,16 +17,16 @@ interface IControlsSubNavItem {
const controlsSubNav: IControlsSubNavItem[] = [
{
name: "macOS updates",
pathname: PATHS.CONTROLS_MAC_OS_UPDATES,
name: "OS updates",
pathname: PATHS.CONTROLS_OS_UPDATES,
},
{
name: "macOS settings",
pathname: PATHS.CONTROLS_MAC_SETTINGS,
name: "OS settings",
pathname: PATHS.CONTROLS_OS_SETTINGS,
},
{
name: "macOS setup",
pathname: PATHS.CONTROLS_MAC_SETUP,
name: "Setup experience",
pathname: PATHS.CONTROLS_SETUP_EXPERIENCE,
},
];
@@ -63,11 +61,9 @@ const ManageControlsPage = ({
router,
}: IManageControlsPageProps): JSX.Element => {
const {
config,
isFreeTier,
isOnGlobalTeam,
isPremiumTier,
isGlobalAdmin,
isSandboxMode,
} = useContext(AppContext);
@@ -99,34 +95,8 @@ const ManageControlsPage = ({
[location, router]
);
const onConnectClick = () => {
router.push(PATHS.ADMIN_INTEGRATIONS_MDM);
};
const renderConnectButton = () => {
if (isGlobalAdmin) {
return (
<Button
variant="brand"
onClick={onConnectClick}
className={`${baseClass}__connectAPC-button`}
>
Connect
</Button>
);
}
return <></>;
};
const getInfoText = () => {
if (isGlobalAdmin) {
return "Connect Fleet to the Apple Push Certificates Portal to get started.";
}
return "Your Fleet administrator must connect Fleet to the Apple Push Certificates Portal to get started.";
};
const renderBody = () => {
return config?.mdm.enabled_and_configured ? (
return (
<div>
<TabsWrapper>
<Tabs
@@ -146,12 +116,6 @@ const ManageControlsPage = ({
</TabsWrapper>
{React.cloneElement(children, { teamIdForApi })}
</div>
) : (
<EmptyTable
header="Manage your macOS hosts"
info={getInfoText()}
primaryButton={renderConnectButton()}
/>
);
};
@@ -1,31 +1,34 @@
import React, { useContext } from "react";
import { Params } from "react-router/lib/Router";
import { InjectedRouter, Params } from "react-router/lib/Router";
import { useQuery } from "react-query";
import { AppContext } from "context/app";
import SideNav from "pages/admin/components/SideNav";
import { useQuery } from "react-query";
import { ProfileSummaryResponse } from "interfaces/mdm";
import { API_NO_TEAM_ID, APP_CONTEXT_NO_TEAM_ID } from "interfaces/team";
import mdmAPI from "services/entities/mdm";
import MAC_OS_SETTINGS_NAV_ITEMS from "./MacOSSettingsNavItems";
import OS_SETTINGS_NAV_ITEMS from "./OSSettingsNavItems";
import AggregateMacSettingsIndicators from "./AggregateMacSettingsIndicators";
import TurnOnMdmMessage from "../components/TurnOnMdmMessage";
const baseClass = "mac-os-settings";
const baseClass = "os-settings";
interface IMacOSSettingsProps {
interface IOSSettingsProps {
params: Params;
router: InjectedRouter;
location: {
search: string;
};
}
const MacOSSettings = ({
const OSSettings = ({
router,
location: { search: queryString },
params,
}: IMacOSSettingsProps) => {
}: IOSSettingsProps) => {
const { section } = params;
const { currentTeam } = useContext(AppContext);
const { config, currentTeam } = useContext(AppContext);
// TODO: consider using useTeamIdParam hook here instead in the future
const teamId =
@@ -46,10 +49,15 @@ const MacOSSettings = ({
}
);
const DEFAULT_SETTINGS_SECTION = MAC_OS_SETTINGS_NAV_ITEMS[0];
// MDM is not on so show messaging for user to enable it.
if (!config?.mdm.enabled_and_configured) {
return <TurnOnMdmMessage router={router} />;
}
const DEFAULT_SETTINGS_SECTION = OS_SETTINGS_NAV_ITEMS[0];
const currentFormSection =
MAC_OS_SETTINGS_NAV_ITEMS.find((item) => item.urlSection === section) ??
OS_SETTINGS_NAV_ITEMS.find((item) => item.urlSection === section) ??
DEFAULT_SETTINGS_SECTION;
const CurrentCard = currentFormSection.Card;
@@ -66,7 +74,7 @@ const MacOSSettings = ({
/>
<SideNav
className={`${baseClass}__side-nav`}
navItems={MAC_OS_SETTINGS_NAV_ITEMS.map((navItem) => ({
navItems={OS_SETTINGS_NAV_ITEMS.map((navItem) => ({
...navItem,
path: navItem.path.concat(queryString),
}))}
@@ -83,4 +91,4 @@ const MacOSSettings = ({
);
};
export default MacOSSettings;
export default OSSettings;
@@ -5,7 +5,7 @@ import { IMdmProfile } from "interfaces/mdm";
import DiskEncryption from "./cards/DiskEncryption";
import CustomSettings from "./cards/CustomSettings";
interface IMacOSSettingsCardProps {
interface IOSSettingsCardProps {
currentTeamId?: number;
profiles?: IMdmProfile[];
onProfileUpload?: () => void;
@@ -13,9 +13,7 @@ interface IMacOSSettingsCardProps {
}
// TODO: types
const MAC_OS_SETTINGS_NAV_ITEMS: ISideNavItem<
IMacOSSettingsCardProps | any
>[] = [
const OS_SETTINGS_NAV_ITEMS: ISideNavItem<IOSSettingsCardProps | any>[] = [
{
title: "Disk encryption",
urlSection: "disk-encryption",
@@ -30,4 +28,4 @@ const MAC_OS_SETTINGS_NAV_ITEMS: ISideNavItem<
},
];
export default MAC_OS_SETTINGS_NAV_ITEMS;
export default OS_SETTINGS_NAV_ITEMS;
@@ -1,4 +1,4 @@
.mac-os-settings {
.os-settings {
font-size: $x-small;
margin-top: $pad-xxlarge;
display: flex;
@@ -0,0 +1 @@
export { default } from "./OSSettings";
@@ -1,4 +1,5 @@
import React, { useContext } from "react";
import { InjectedRouter } from "react-router";
import { AppContext } from "context/app";
@@ -9,15 +10,17 @@ import PremiumFeatureMessage from "components/PremiumFeatureMessage";
import OsMinVersionForm from "./components/OsMinVersionForm";
import NudgePreview from "./components/NudgePreview";
import TurnOnMdmMessage from "../components/TurnOnMdmMessage/TurnOnMdmMessage";
const baseClass = "mac-os-updates";
const baseClass = "os-updates";
interface IMacOSUpdates {
interface IOSUpdates {
router: InjectedRouter;
teamIdForApi: number;
}
const MacOSUpdates = ({ teamIdForApi }: IMacOSUpdates) => {
const { isPremiumTier } = useContext(AppContext);
const OSUpdates = ({ router, teamIdForApi }: IOSUpdates) => {
const { config, isPremiumTier } = useContext(AppContext);
const OperatingSystemCard = useInfoCard({
title: "macOS versions",
@@ -35,6 +38,10 @@ const MacOSUpdates = ({ teamIdForApi }: IMacOSUpdates) => {
),
});
if (!config?.mdm.enabled_and_configured) {
return <TurnOnMdmMessage router={router} />;
}
return isPremiumTier ? (
<div className={baseClass}>
<p className={`${baseClass}__description`}>
@@ -62,4 +69,4 @@ const MacOSUpdates = ({ teamIdForApi }: IMacOSUpdates) => {
);
};
export default MacOSUpdates;
export default OSUpdates;
@@ -1,4 +1,4 @@
.mac-os-updates {
.os-updates {
font-size: $x-small;
&__description {
@@ -0,0 +1 @@
export { default } from "./OSUpdates";
@@ -9,9 +9,10 @@ import Button from "components/buttons/Button/Button";
import PremiumFeatureMessage from "components/PremiumFeatureMessage";
import EmptyTable from "components/EmptyTable";
import MAC_OS_SETUP_NAV_ITEMS from "./MacOSSetupNavItems";
import SETUP_EXPERIENCE_NAV_ITEMS from "./SetupExperienceNavItems";
import TurnOnMdmMessage from "../components/TurnOnMdmMessage";
const baseClass = "macos-setup";
const baseClass = "setup-experience";
interface ISetupEmptyState {
router: InjectedRouter;
@@ -35,34 +36,39 @@ const SetupEmptyState = ({ router }: ISetupEmptyState) => {
);
};
interface IMacOSSetupProps {
interface ISetupExperienceProps {
params: Params;
location: { search: string };
router: any;
teamIdForApi: number;
}
const MacOSSetup = ({
const SetupExperience = ({
params,
location: { search: queryString },
router,
teamIdForApi,
}: IMacOSSetupProps) => {
}: ISetupExperienceProps) => {
const { section } = params;
const { isPremiumTier, config } = useContext(AppContext);
const DEFAULT_SETTINGS_SECTION = MAC_OS_SETUP_NAV_ITEMS[0];
const currentFormSection =
MAC_OS_SETUP_NAV_ITEMS.find((item) => item.urlSection === section) ??
DEFAULT_SETTINGS_SECTION;
const CurrentCard = currentFormSection.Card;
// MDM is not on so show messaging for user to enable it.
if (!config?.mdm.enabled_and_configured) {
return <TurnOnMdmMessage router={router} />;
}
// User has not set up Apple Business Manager.
if (isPremiumTier && !config?.mdm.apple_bm_enabled_and_configured) {
return <SetupEmptyState router={router} />;
}
const DEFAULT_SETTINGS_SECTION = SETUP_EXPERIENCE_NAV_ITEMS[0];
const currentFormSection =
SETUP_EXPERIENCE_NAV_ITEMS.find((item) => item.urlSection === section) ??
DEFAULT_SETTINGS_SECTION;
const CurrentCard = currentFormSection.Card;
return (
<div className={baseClass}>
<p>
@@ -74,7 +80,7 @@ const MacOSSetup = ({
) : (
<SideNav
className={`${baseClass}__side-nav`}
navItems={MAC_OS_SETUP_NAV_ITEMS.map((navItem) => ({
navItems={SETUP_EXPERIENCE_NAV_ITEMS.map((navItem) => ({
...navItem,
path: navItem.path.concat(queryString),
}))}
@@ -92,4 +98,4 @@ const MacOSSetup = ({
);
};
export default MacOSSetup;
export default SetupExperience;
@@ -5,12 +5,14 @@ import { ISideNavItem } from "pages/admin/components/SideNav/SideNav";
import EndUserAuthentication from "./cards/EndUserAuthentication/EndUserAuthentication";
import BootstrapPackage from "./cards/BootstrapPackage";
interface IMacOSSetupCardProps {
interface ISetupExperienceCardProps {
currentTeamId?: number;
}
// TODO: types
const MAC_OS_SETUP_NAV_ITEMS: ISideNavItem<IMacOSSetupCardProps | any>[] = [
const SETUP_EXPERIENCE_NAV_ITEMS: ISideNavItem<
ISetupExperienceCardProps | any
>[] = [
{
title: "End user authentication",
urlSection: "end-user-auth",
@@ -25,4 +27,4 @@ const MAC_OS_SETUP_NAV_ITEMS: ISideNavItem<IMacOSSetupCardProps | any>[] = [
},
];
export default MAC_OS_SETUP_NAV_ITEMS;
export default SETUP_EXPERIENCE_NAV_ITEMS;
@@ -1,4 +1,4 @@
.macos-setup {
.setup-experience {
> p {
font-size: $x-small;
margin: $pad-xxlarge 0;
@@ -0,0 +1 @@
export { default } from "./SetupExperience";
@@ -0,0 +1,40 @@
import React from "react";
import PATHS from "router/paths";
import EmptyTable from "components/EmptyTable";
import Button from "components/buttons/Button";
import { InjectedRouter } from "react-router";
const baseClass = "turn-on-mdm-message";
interface ITurnOnMdmMessageProps {
router: InjectedRouter;
}
const TurnOnMdmMessage = ({ router }: ITurnOnMdmMessageProps) => {
const onConnectClick = () => {
router.push(PATHS.ADMIN_INTEGRATIONS_MDM);
};
const renderConnectButton = () => {
return (
<Button
variant="brand"
onClick={onConnectClick}
className={`${baseClass}__connectAPC-button`}
>
Turn on
</Button>
);
};
return (
<EmptyTable
header="Manage your macOS hosts"
info={"Turn on MDM to change settings on your hosts."}
primaryButton={renderConnectButton()}
/>
);
};
export default TurnOnMdmMessage;
@@ -0,0 +1 @@
export { default } from "./TurnOnMdmMessage";
+12 -9
View File
@@ -50,9 +50,9 @@ import SettingsWrapper from "pages/admin/AdminWrapper";
import ManageControlsPage from "pages/ManageControlsPage/ManageControlsPage";
import MembersPage from "pages/admin/TeamManagementPage/TeamDetailsWrapper/MembersPage";
import AgentOptionsPage from "pages/admin/TeamManagementPage/TeamDetailsWrapper/AgentOptionsPage";
import MacOSUpdates from "pages/ManageControlsPage/MacOSUpdates";
import MacOSSettings from "pages/ManageControlsPage/MacOSSettings";
import MacOSSetup from "pages/ManageControlsPage/MacOSSetup/MacOSSetup";
import OSUpdates from "pages/ManageControlsPage/OSUpdates";
import OSSettings from "pages/ManageControlsPage/OSSettings";
import SetupExperience from "pages/ManageControlsPage/SetupExperience/SetupExperience";
import WindowsMdmPage from "pages/admin/IntegrationsPage/cards/MdmSettings/WindowsMdmPage";
import MacOSMdmPage from "pages/admin/IntegrationsPage/cards/MdmSettings/MacOSMdmPage";
import WindowsAutomaticEnrollmentPage from "pages/admin/IntegrationsPage/cards/AutomaticEnrollment/WindowsAutomaticEnrollmentPage";
@@ -186,13 +186,16 @@ const routes = (
<Route component={ExcludeInSandboxRoutes}>
<Route path="controls" component={AuthAnyMaintainerAnyAdminRoutes}>
<IndexRedirect to="mac-os-updates" />
<IndexRedirect to="os-updates" />
<Route component={ManageControlsPage}>
<Route path="mac-os-updates" component={MacOSUpdates} />
<Route path="mac-settings" component={MacOSSettings} />
<Route path="mac-settings/:section" component={MacOSSettings} />
<Route path="mac-setup" component={MacOSSetup} />
<Route path="mac-setup/:section" component={MacOSSetup} />
<Route path="os-updates" component={OSUpdates} />
<Route path="os-settings" component={OSSettings} />
<Route path="os-settings/:section" component={OSSettings} />
<Route path="setup-experience" component={SetupExperience} />
<Route
path="setup-experience/:section"
component={SetupExperience}
/>
</Route>
</Route>
</Route>
+6 -6
View File
@@ -4,16 +4,16 @@ export default [
{ path: "/dashboard", title: "Dashboard | Fleet for osquery" },
{ path: "/hosts/manage", title: "Manage hosts | Fleet for osquery" },
{
path: "/controls/mac-os-updates",
title: "Manage macOS updates | Fleet for osquery",
path: "/controls/os-updates",
title: "Manage OS updates | Fleet for osquery",
},
{
path: "/controls/mac-settings",
title: "Manage macOS settings | Fleet for osquery",
path: "/controls/os-settings",
title: "Manage OS settings | Fleet for osquery",
},
{
path: "/controls/mac-setup",
title: "Manage macOS MDM setup | Fleet for osquery",
path: "/controls/setup-experience",
title: "Manage setup experience | Fleet for osquery",
},
{ path: "/software/manage", title: "Manage software | Fleet for osquery" },
{ path: "/queries/manage", title: "Manage queries | Fleet for osquery" },
+10 -7
View File
@@ -4,15 +4,18 @@ import URL_PREFIX from "./url_prefix";
// Note: changes to paths.ts should change page_titles.ts respectively
export default {
ROOT: `${URL_PREFIX}/`,
// Controls pages
CONTROLS: `${URL_PREFIX}/controls`,
CONTROLS_MAC_OS_UPDATES: `${URL_PREFIX}/controls/mac-os-updates`,
CONTROLS_MAC_SETTINGS: `${URL_PREFIX}/controls/mac-settings`,
CONTROLS_CUSTOM_SETTINGS: `${URL_PREFIX}/controls/mac-settings/custom-settings`,
CONTROLS_DISK_ENCRYPTION: `${URL_PREFIX}/controls/mac-settings/disk-encryption`,
CONTROLS_MAC_SETUP: `${URL_PREFIX}/controls/mac-setup`,
CONTROLS_END_USER_AUTHENTICATION: `${URL_PREFIX}/controls/mac-setup/end-user-auth`,
CONTROLS_BOOTSTRAP_PACKAGE: `${URL_PREFIX}/controls/mac-setup/bootstrap-package`,
CONTROLS_OS_UPDATES: `${URL_PREFIX}/controls/os-updates`,
CONTROLS_OS_SETTINGS: `${URL_PREFIX}/controls/os-settings`,
CONTROLS_CUSTOM_SETTINGS: `${URL_PREFIX}/controls/os-settings/custom-settings`,
CONTROLS_DISK_ENCRYPTION: `${URL_PREFIX}/controls/os-settings/disk-encryption`,
CONTROLS_SETUP_EXPERIENCE: `${URL_PREFIX}/controls/setup-experience`,
CONTROLS_END_USER_AUTHENTICATION: `${URL_PREFIX}/controls/setup-experience/end-user-auth`,
CONTROLS_BOOTSTRAP_PACKAGE: `${URL_PREFIX}/controls/setup-experience/bootstrap-package`,
CONTROLS_MAC_SCRIPTS: `${URL_PREFIX}/controls/mac-scripts`,
DASHBOARD: `${URL_PREFIX}/dashboard`,
DASHBOARD_LINUX: `${URL_PREFIX}/dashboard/linux`,
DASHBOARD_MAC: `${URL_PREFIX}/dashboard/mac`,