From f9f219b92d922bbd4db8a2d30e3b6debd63cd360 Mon Sep 17 00:00:00 2001 From: Jacob Shandling Date: Thu, 9 Feb 2023 13:07:25 -0800 Subject: [PATCH 01/25] Create Pending icon; initial scaffold for macOS settings indicator in HostSummary --- frontend/components/Icon/Icon.tsx | 2 +- frontend/components/icons/Pending.tsx | 31 ++++++++++++++++++ frontend/components/icons/index.ts | 2 ++ .../details/DeviceUserPage/DeviceUserPage.tsx | 4 ++- .../hosts/details/DeviceUserPage/_styles.scss | 6 ++-- .../details/HostDetailsPage/_styles.scss | 6 ++-- .../details/cards/HostSummary/HostSummary.tsx | 32 ++++++++++++++++++- 7 files changed, 72 insertions(+), 11 deletions(-) create mode 100644 frontend/components/icons/Pending.tsx diff --git a/frontend/components/Icon/Icon.tsx b/frontend/components/Icon/Icon.tsx index 40c026f4a19..9e3371227be 100644 --- a/frontend/components/Icon/Icon.tsx +++ b/frontend/components/Icon/Icon.tsx @@ -3,7 +3,7 @@ import classnames from "classnames"; import { IconNames, ICON_MAP } from "components/icons"; import { Colors } from "styles/var/colors"; -import { ICON_SIZES, IconSizes } from "styles/var/icon_sizes"; +import { IconSizes } from "styles/var/icon_sizes"; interface IIconProps { name: IconNames; diff --git a/frontend/components/icons/Pending.tsx b/frontend/components/icons/Pending.tsx new file mode 100644 index 00000000000..bc4e1720c72 --- /dev/null +++ b/frontend/components/icons/Pending.tsx @@ -0,0 +1,31 @@ +import React from "react"; +import { COLORS, Colors } from "styles/var/colors"; +import { ICON_SIZES, IconSizes } from "styles/var/icon_sizes"; + +interface IPendingProps { + size?: IconSizes; + color?: Colors; +} + +const Pending = ({ + size = "medium", + color = "ui-fleet-black-50", +}: IPendingProps) => { + return ( + + + + ); +}; + +export default Pending; diff --git a/frontend/components/icons/index.ts b/frontend/components/icons/index.ts index 2bd0eb83a62..4d13b8df8e7 100644 --- a/frontend/components/icons/index.ts +++ b/frontend/components/icons/index.ts @@ -16,6 +16,7 @@ import EmptyTeams from "./EmptyTeams"; import ExternalLink from "./ExternalLink"; import Issue from "./Issue"; import Plus from "./Plus"; +import Pending from "./Pending"; import LowDiskSpaceHosts from "./LowDiskSpaceHosts"; import MissingHosts from "./MissingHosts"; @@ -65,6 +66,7 @@ export const ICON_MAP = { clipboard: Clipboard, eye: Eye, pencil: Pencil, + pending: Pending, trash: TrashCan, success: Success, error: Error, diff --git a/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx b/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx index edb321539cf..ba60de8efe9 100644 --- a/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx +++ b/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx @@ -199,6 +199,8 @@ const DeviceUserPage = ({ "percent_disk_space_available", "gigs_disk_space_available", "team_name", + "platform", + "mdm", ]) ); @@ -310,10 +312,10 @@ const DeviceUserPage = ({ statusClassName={statusClassName} titleData={titleData} diskEncryption={hostDiskEncryption} + isPremiumTier={isPremiumTier} showRefetchSpinner={showRefetchSpinner} onRefetchHost={onRefetchHost} renderActionButtons={renderActionButtons} - isPremiumTier={isPremiumTier} deviceUser /> diff --git a/frontend/pages/hosts/details/DeviceUserPage/_styles.scss b/frontend/pages/hosts/details/DeviceUserPage/_styles.scss index d7f31a8959f..3cd8630a6c9 100644 --- a/frontend/pages/hosts/details/DeviceUserPage/_styles.scss +++ b/frontend/pages/hosts/details/DeviceUserPage/_styles.scss @@ -94,16 +94,14 @@ white-space: nowrap; overflow: hidden; text-overflow: ellipsis; + display: flex; + gap: $pad-xsmall; img { width: 16px; height: 16px; vertical-align: sub; } - - .total-issues-count { - margin-left: $pad-small; - } } } diff --git a/frontend/pages/hosts/details/HostDetailsPage/_styles.scss b/frontend/pages/hosts/details/HostDetailsPage/_styles.scss index 7e936b4a927..64b9ccc898f 100644 --- a/frontend/pages/hosts/details/HostDetailsPage/_styles.scss +++ b/frontend/pages/hosts/details/HostDetailsPage/_styles.scss @@ -49,16 +49,14 @@ white-space: nowrap; overflow: hidden; text-overflow: ellipsis; + display: flex; + gap: $pad-xsmall; img { width: 16px; height: 16px; vertical-align: sub; } - - .total-issues-count { - margin-left: $pad-small; - } } } diff --git a/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx b/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx index d0fc99c864c..e2285d3b0a1 100644 --- a/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx +++ b/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx @@ -9,6 +9,8 @@ import HumanTimeDiffWithDateTip from "components/HumanTimeDiffWithDateTip"; import { humanHostMemory, wrapFleetHelper } from "utilities/helpers"; import getHostStatusTooltipText from "pages/hosts/helpers"; import StatusIndicator from "components/StatusIndicator"; +import Icon from "components/Icon"; +import { IconNames } from "components/icons"; import IssueIcon from "../../../../../../assets/images/icon-issue-fleet-black-50-16x16@2x.png"; const baseClass = "host-summary"; @@ -107,7 +109,7 @@ const HostSummary = ({ Failing policies ({titleData.issues.failing_policies_count}) - + {titleData.issues.total_issues_count} @@ -127,6 +129,28 @@ const HostSummary = ({ ); + const renderMacSettingsIndicator = () => { + // TODO: actually determine this status + const macSettingsStatus = "Failing"; + + // TODO: improve below typing + const iconName: IconNames = { + Latest: "success", + Pending: "pending", + Failing: "error", + }[macSettingsStatus] as IconNames; + + return ( +
+ macOS settings + + + {macSettingsStatus} + +
+ ); + }; + const renderSummary = () => { const { status, id } = titleData; return ( @@ -145,6 +169,12 @@ const HostSummary = ({ isPremiumTier && renderIssues()} {isPremiumTier && renderHostTeam()} + {/* TODO: confirm how to determine if 'macOS settings are enforced on the host' */} + {titleData.platform === "darwin" && + isPremiumTier && + // TODO: change below to use actual API return values when implemented for issue #9599 + // titleData.mdm.macsettingsenrolledstatus && + renderMacSettingsIndicator()}
Disk space Date: Thu, 9 Feb 2023 16:50:06 -0800 Subject: [PATCH 02/25] work on mac settings indicator and modal --- .../DiskSpaceGraph/DiskSpaceGraph.tsx | 4 +- .../StatusIndicator/StatusIndicator.tsx | 3 +- .../hosts/details/DeviceUserPage/_styles.scss | 6 +- .../details/HostDetailsPage/_styles.scss | 6 +- .../MacSettingsModal/MacSettingsModal.tsx | 29 ++++++++ .../hosts/details/MacSettingsModal/index.ts | 1 + .../details/cards/HostSummary/HostSummary.tsx | 69 ++++++++++++++++--- 7 files changed, 101 insertions(+), 17 deletions(-) create mode 100644 frontend/pages/hosts/details/MacSettingsModal/MacSettingsModal.tsx create mode 100644 frontend/pages/hosts/details/MacSettingsModal/index.ts diff --git a/frontend/components/DiskSpaceGraph/DiskSpaceGraph.tsx b/frontend/components/DiskSpaceGraph/DiskSpaceGraph.tsx index 8d55e54757c..19c81961e1a 100644 --- a/frontend/components/DiskSpaceGraph/DiskSpaceGraph.tsx +++ b/frontend/components/DiskSpaceGraph/DiskSpaceGraph.tsx @@ -8,6 +8,7 @@ interface IDiskSpaceGraphProps { percentDiskSpaceAvailable: number; id: string; platform: string; + tooltipPosition?: "top" | "bottom"; } const DiskSpaceGraph = ({ @@ -16,6 +17,7 @@ const DiskSpaceGraph = ({ percentDiskSpaceAvailable, id, platform, + tooltipPosition = "top", }: IDiskSpaceGraphProps): JSX.Element => { const getDiskSpaceIndicatorColor = (): string => { // return space-dependent graph colors for mac and windows hosts, green for linux @@ -65,7 +67,7 @@ const DiskSpaceGraph = ({ {diskSpaceTooltipText && ( void; +} + +const baseClass = "mac-settings-modal"; + +const MacSettingsModal = ({ + hostId, + hostMacSettings, + onClose, +}: IMacSettingsModalProps) => { + return ( + +
+ +
+
+ ); +}; + +export default MacSettingsModal; diff --git a/frontend/pages/hosts/details/MacSettingsModal/index.ts b/frontend/pages/hosts/details/MacSettingsModal/index.ts new file mode 100644 index 00000000000..c061f22f7a8 --- /dev/null +++ b/frontend/pages/hosts/details/MacSettingsModal/index.ts @@ -0,0 +1 @@ +export { default } from "./MacSettingsModal"; diff --git a/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx b/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx index e2285d3b0a1..53989d3153a 100644 --- a/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx +++ b/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx @@ -19,6 +19,9 @@ interface IHostDiskEncryptionProps { enabled?: boolean; tooltip?: string; } + +type MacSettingsStatus = "Failing" | "Latest" | "Pending"; + interface IHostSummaryProps { statusClassName: string; titleData: any; // TODO: create interfaces for this and use consistently across host pages and related helpers @@ -109,7 +112,7 @@ const HostSummary = ({ Failing policies ({titleData.issues.failing_policies_count})
- + {titleData.issues.total_issues_count} @@ -129,23 +132,57 @@ const HostSummary = ({
); + // const getIconNameAndTooltipText = ( + // macSettingsStatus: MacSettingsStatus + // ): [IconNames, string] => { + // const options: { [key: "Latest" | "Pending" | "Failing"] } = { + // Latest: ["success", "Host applied the latest settings"], + // Pending: [ + // "pending", + // "Host will apply the latest settings when it comes online", + // ], + // Failing: [ + // "error", + // "Host failed to apply the latest settings. Click to view error(s).", + // ], + // }; + // return options[macSettingsStatus]; + // }; + const renderMacSettingsIndicator = () => { // TODO: actually determine this status - const macSettingsStatus = "Failing"; + const macSettingsStatus: MacSettingsStatus = "Latest"; - // TODO: improve below typing - const iconName: IconNames = { - Latest: "success", - Pending: "pending", - Failing: "error", - }[macSettingsStatus] as IconNames; + // TODO: get this function to work + // const [iconName, tooltipText] = getIconNameAndTooltipText( + // macSettingsStatus + // ); + const iconName = "success"; + const tooltipText = "test tip text"; return (
macOS settings - - {macSettingsStatus} + + {/* TODO: fix alginment of this icon */} + + {macSettingsStatus} + + + {tooltipText} +
); @@ -162,19 +199,24 @@ const HostSummary = ({ tooltip={{ id, tooltipText: getHostStatusTooltipText(status), + position: "bottom", }} /> + {titleData.issues?.total_issues_count > 0 && isPremiumTier && renderIssues()} + {isPremiumTier && renderHostTeam()} + {/* TODO: confirm how to determine if 'macOS settings are enforced on the host' */} {titleData.platform === "darwin" && isPremiumTier && // TODO: change below to use actual API return values when implemented for issue #9599 // titleData.mdm.macsettingsenrolledstatus && renderMacSettingsIndicator()} +
Disk space
+ {typeof diskEncryption?.enabled === "boolean" && diskEncryption?.tooltip ? (
Disk encryption - + {diskEncryption.enabled ? "On" : "Off"}
From c282edf53199fcd7dc54a89bea1faa58d812f1d3 Mon Sep 17 00:00:00 2001 From: Jacob Shandling Date: Fri, 10 Feb 2023 16:00:02 -0800 Subject: [PATCH 03/25] build until mac settings table scaffold works in modal --- frontend/interfaces/mdm.ts | 6 ++ .../IntegrationsPage/IntegrationNavItems.tsx | 2 +- .../Mdm.tsx => MdmSettings/MdmSettings.tsx} | 2 +- .../cards/{Mdm => MdmSettings}/_styles.scss | 4 +- .../components/EditTeamModal.tsx | 0 .../RequestCSRModal/RequestCSRModal.tsx | 0 .../components/RequestCSRModal/_styles.scss | 0 .../components/RequestCSRModal/index.ts | 0 .../details/DeviceUserPage/DeviceUserPage.tsx | 15 ++++ .../HostDetailsPage/HostDetailsPage.tsx | 14 ++++ .../MacSettingsModal/MacSettingsModal.tsx | 19 +++-- .../MacSettingsTable/MacSettingsTable.tsx | 53 ++++++++++++ .../MacSettingsTableConfig.tsx | 81 +++++++++++++++++++ .../MacSettingsTable/_styles.scss | 0 .../MacSettingsTable/index.ts | 1 + .../details/cards/HostSummary/HostSummary.tsx | 46 ++++++++--- 16 files changed, 220 insertions(+), 23 deletions(-) rename frontend/pages/admin/IntegrationsPage/cards/{Mdm/Mdm.tsx => MdmSettings/MdmSettings.tsx} (99%) rename frontend/pages/admin/IntegrationsPage/cards/{Mdm => MdmSettings}/_styles.scss (93%) rename frontend/pages/admin/IntegrationsPage/cards/{Mdm => MdmSettings}/components/EditTeamModal.tsx (100%) rename frontend/pages/admin/IntegrationsPage/cards/{Mdm => MdmSettings}/components/RequestCSRModal/RequestCSRModal.tsx (100%) rename frontend/pages/admin/IntegrationsPage/cards/{Mdm => MdmSettings}/components/RequestCSRModal/_styles.scss (100%) rename frontend/pages/admin/IntegrationsPage/cards/{Mdm => MdmSettings}/components/RequestCSRModal/index.ts (100%) create mode 100644 frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTable.tsx create mode 100644 frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx create mode 100644 frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/_styles.scss create mode 100644 frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/index.ts diff --git a/frontend/interfaces/mdm.ts b/frontend/interfaces/mdm.ts index f79a21536c3..3d08e08900c 100644 --- a/frontend/interfaces/mdm.ts +++ b/frontend/interfaces/mdm.ts @@ -54,3 +54,9 @@ export interface IMdmSummaryResponse { mobile_device_management_enrollment_status: IMdmStatus; mobile_device_management_solution: IMdmSolution[] | null; } + +// TODO: define below according to the API structure in issue #9599 +export type IMacSettings = unknown; +export type IMacSetting = unknown; + +export type MacSettingsStatus = "Failing" | "Latest" | "Pending"; diff --git a/frontend/pages/admin/IntegrationsPage/IntegrationNavItems.tsx b/frontend/pages/admin/IntegrationsPage/IntegrationNavItems.tsx index ca2a69cc5bb..71f58793424 100644 --- a/frontend/pages/admin/IntegrationsPage/IntegrationNavItems.tsx +++ b/frontend/pages/admin/IntegrationsPage/IntegrationNavItems.tsx @@ -2,7 +2,7 @@ import PATHS from "router/paths"; import { ISideNavItem } from "../components/SideNav/SideNav"; import Integrations from "./cards/Integrations"; -import Mdm from "./cards/Mdm/Mdm"; +import Mdm from "./cards/MdmSettings/MdmSettings"; const INTEGRATION_SETTINGS_NAV_ITEMS: ISideNavItem[] = [ // TODO: types diff --git a/frontend/pages/admin/IntegrationsPage/cards/Mdm/Mdm.tsx b/frontend/pages/admin/IntegrationsPage/cards/MdmSettings/MdmSettings.tsx similarity index 99% rename from frontend/pages/admin/IntegrationsPage/cards/Mdm/Mdm.tsx rename to frontend/pages/admin/IntegrationsPage/cards/MdmSettings/MdmSettings.tsx index a9ddfdbf297..a73d8187f99 100644 --- a/frontend/pages/admin/IntegrationsPage/cards/Mdm/Mdm.tsx +++ b/frontend/pages/admin/IntegrationsPage/cards/MdmSettings/MdmSettings.tsx @@ -25,7 +25,7 @@ interface IABMKeys { decodedPrivate: string; } -const baseClass = "mdm-integrations"; +const baseClass = "mdm-settings"; const Mdm = (): JSX.Element => { const { isPremiumTier, config } = useContext(AppContext); diff --git a/frontend/pages/admin/IntegrationsPage/cards/Mdm/_styles.scss b/frontend/pages/admin/IntegrationsPage/cards/MdmSettings/_styles.scss similarity index 93% rename from frontend/pages/admin/IntegrationsPage/cards/Mdm/_styles.scss rename to frontend/pages/admin/IntegrationsPage/cards/MdmSettings/_styles.scss index 11170c653f5..474d8b2f3de 100644 --- a/frontend/pages/admin/IntegrationsPage/cards/Mdm/_styles.scss +++ b/frontend/pages/admin/IntegrationsPage/cards/MdmSettings/_styles.scss @@ -1,4 +1,4 @@ -.mdm-integrations { +.mdm-settings { display: flex; flex-direction: column; width: 65%; @@ -21,7 +21,7 @@ margin-bottom: 0; } - .mdm-integrations__edit-team-btn { + .mdm-settings-team-btn { margin-left: 12px; .children-wrapper { diff --git a/frontend/pages/admin/IntegrationsPage/cards/Mdm/components/EditTeamModal.tsx b/frontend/pages/admin/IntegrationsPage/cards/MdmSettings/components/EditTeamModal.tsx similarity index 100% rename from frontend/pages/admin/IntegrationsPage/cards/Mdm/components/EditTeamModal.tsx rename to frontend/pages/admin/IntegrationsPage/cards/MdmSettings/components/EditTeamModal.tsx diff --git a/frontend/pages/admin/IntegrationsPage/cards/Mdm/components/RequestCSRModal/RequestCSRModal.tsx b/frontend/pages/admin/IntegrationsPage/cards/MdmSettings/components/RequestCSRModal/RequestCSRModal.tsx similarity index 100% rename from frontend/pages/admin/IntegrationsPage/cards/Mdm/components/RequestCSRModal/RequestCSRModal.tsx rename to frontend/pages/admin/IntegrationsPage/cards/MdmSettings/components/RequestCSRModal/RequestCSRModal.tsx diff --git a/frontend/pages/admin/IntegrationsPage/cards/Mdm/components/RequestCSRModal/_styles.scss b/frontend/pages/admin/IntegrationsPage/cards/MdmSettings/components/RequestCSRModal/_styles.scss similarity index 100% rename from frontend/pages/admin/IntegrationsPage/cards/Mdm/components/RequestCSRModal/_styles.scss rename to frontend/pages/admin/IntegrationsPage/cards/MdmSettings/components/RequestCSRModal/_styles.scss diff --git a/frontend/pages/admin/IntegrationsPage/cards/Mdm/components/RequestCSRModal/index.ts b/frontend/pages/admin/IntegrationsPage/cards/MdmSettings/components/RequestCSRModal/index.ts similarity index 100% rename from frontend/pages/admin/IntegrationsPage/cards/Mdm/components/RequestCSRModal/index.ts rename to frontend/pages/admin/IntegrationsPage/cards/MdmSettings/components/RequestCSRModal/index.ts diff --git a/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx b/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx index ba60de8efe9..465b3fc80ca 100644 --- a/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx +++ b/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx @@ -41,6 +41,7 @@ import FleetIcon from "../../../../../assets/images/fleet-avatar-24x24@2x.png"; import PolicyDetailsModal from "../cards/Policies/HostPoliciesTable/PolicyDetailsModal"; import AutoEnrollMdmModal from "./AutoEnrollMdmModal"; import ManualEnrollMdmModal from "./ManualEnrollMdmModal"; +import MacSettingsModal from "../MacSettingsModal"; const baseClass = "device-user"; @@ -75,6 +76,7 @@ const DeviceUserPage = ({ null ); const [showPolicyDetailsModal, setShowPolicyDetailsModal] = useState(false); + const [showMacSettingsModal, setShowMacSettingsModal] = useState(false); const [globalConfig, setGlobalConfig] = useState( null ); @@ -234,6 +236,11 @@ const DeviceUserPage = ({ }, [showPolicyDetailsModal, setShowPolicyDetailsModal, setSelectedPolicy] ); + + const toggleMacSettingsModal = useCallback(() => { + setShowMacSettingsModal(!showMacSettingsModal); + }, [showMacSettingsModal, setShowMacSettingsModal]); + const onCancelPolicyDetailsModal = useCallback(() => { setShowPolicyDetailsModal(!showPolicyDetailsModal); setSelectedPolicy(null); @@ -313,6 +320,7 @@ const DeviceUserPage = ({ titleData={titleData} diskEncryption={hostDiskEncryption} isPremiumTier={isPremiumTier} + toggleMacSettingsModal={toggleMacSettingsModal} showRefetchSpinner={showRefetchSpinner} onRefetchHost={onRefetchHost} renderActionButtons={renderActionButtons} @@ -371,6 +379,13 @@ const DeviceUserPage = ({ policy={selectedPolicy} /> )} + {showMacSettingsModal && ( + + )} ); }; diff --git a/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx b/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx index ff193a70954..f4caa6040aa 100644 --- a/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx +++ b/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx @@ -62,6 +62,7 @@ import parseOsVersion from "./modals/OSPolicyModal/helpers"; import DiskEncryptionKeyModal from "./modals/DiskEncryptionKeyModal"; import HostActionDropdown from "./HostActionsDropdown/HostActionsDropdown"; +import MacSettingsModal from "../MacSettingsModal"; const baseClass = "host-details"; @@ -127,6 +128,7 @@ const HostDetailsPage = ({ const [showQueryHostModal, setShowQueryHostModal] = useState(false); const [showPolicyDetailsModal, setPolicyDetailsModal] = useState(false); const [showOSPolicyModal, setShowOSPolicyModal] = useState(false); + const [showMacSettingsModal, setShowMacSettingsModal] = useState(false); const [showUnenrollMdmModal, setShowUnenrollMdmModal] = useState(false); const [showDiskEncryptionModal, setShowDiskEncryptionModal] = useState(false); const [selectedPolicy, setSelectedPolicy] = useState( @@ -388,6 +390,10 @@ const HostDetailsPage = ({ setShowOSPolicyModal(!showOSPolicyModal); }, [showOSPolicyModal, setShowOSPolicyModal]); + const toggleMacSettingsModal = useCallback(() => { + setShowMacSettingsModal(!showMacSettingsModal); + }, [showMacSettingsModal, setShowMacSettingsModal]); + const onCancelPolicyDetailsModal = useCallback(() => { setPolicyDetailsModal(!showPolicyDetailsModal); setSelectedPolicy(null); @@ -620,6 +626,7 @@ const HostDetailsPage = ({ isPremiumTier={isPremiumTier} isOnlyObserver={isOnlyObserver} toggleOSPolicyModal={toggleOSPolicyModal} + toggleMacSettingsModal={toggleMacSettingsModal} showRefetchSpinner={showRefetchSpinner} onRefetchHost={onRefetchHost} renderActionButtons={renderActionButtons} @@ -737,6 +744,13 @@ const HostDetailsPage = ({ osPolicyLabel={osPolicyLabel} /> )} + {showMacSettingsModal && ( + + )} {showUnenrollMdmModal && !!host && ( void; } const baseClass = "mac-settings-modal"; const MacSettingsModal = ({ - hostId, hostMacSettings, onClose, }: IMacSettingsModalProps) => { return ( -
- -
+ <> + +
+ +
+
); }; diff --git a/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTable.tsx b/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTable.tsx new file mode 100644 index 00000000000..8421fe4f56d --- /dev/null +++ b/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTable.tsx @@ -0,0 +1,53 @@ +import React from "react"; +import Spinner from "components/Spinner"; +import TableContainer from "components/TableContainer"; +import EmptyTable from "components/EmptyTable"; +import { IMacSettings } from "interfaces/mdm"; + +import { + generateTableHeaders, + generateDataSet, +} from "./MacSettingsTableConfig"; + +const baseClass = "macsettings-table"; + +interface IMacSettingsTableProps { + isLoading: boolean; + hostMacSettings: IMacSettings; +} + +const MacSettingsTable = ({ + isLoading, + hostMacSettings, +}: IMacSettingsTableProps) => { + return ( +
+ {isLoading ? ( + + ) : ( + + // EmptyTable({ + // iconName: emptyState().iconName, + // header: emptyState().header, + // info: emptyState().info, + // additionalInfo: emptyState().additionalInfo, + // primaryButton: emptyState().primaryButton, + // }) + // } + showMarkAllPages={false} + isAllPagesSelected={false} + /> + )} +
+ ); +}; + +export default MacSettingsTable; diff --git a/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx b/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx new file mode 100644 index 00000000000..0af9cc56132 --- /dev/null +++ b/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx @@ -0,0 +1,81 @@ +import LinkCell from "components/TableContainer/DataTable/LinkCell"; +import TextCell from "components/TableContainer/DataTable/TextCell"; +import React from "react"; +import { IMacSetting, IMacSettings } from "interfaces/mdm"; + +interface IHeaderProps { + column: { + title: string; + isSortedDesc: boolean; + }; +} + +interface ICellProps { + cell: { + value: string; + }; + row: { + original: IMacSetting; + }; +} + +interface IDataColumn { + Header: ((props: IHeaderProps) => JSX.Element) | string; + Cell: (props: ICellProps) => JSX.Element; + id?: string; + title?: string; + accessor?: string; + disableHidden?: boolean; + disableSortBy?: boolean; + sortType?: string; +} + +const generateTableHeaders = (): IDataColumn[] => { + const tableHeaders: IDataColumn[] = [ + { + title: "Name", + Header: "Name", + disableSortBy: true, + accessor: "name", + Cell: (cellProps: ICellProps): JSX.Element => ( + + ), + }, + { + title: "Status", + Header: "Status", + disableSortBy: true, + accessor: "status", + Cell: (cellProps: ICellProps): JSX.Element => { + // TODO - logically generate mac setting status. + // define new component, like StatusIndicator but with more options and icons ? + return
Status of this mac setting
; + }, + }, + { + title: "Error", + Header: "Error", + disableSortBy: true, + accessor: "error", + Cell: (cellProps: ICellProps): JSX.Element => { + // TODO: logically generate settings error + return
Error
; + }, + }, + ]; + + return tableHeaders; +}; + +const generateDataSet = (hostMacSettings: IMacSettings) => { + // TODO - make this real + return [ + { + name: "setting name", + status: "setting status", + error: "setting error", + }, + ]; +}; + +export { generateTableHeaders, generateDataSet }; diff --git a/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/_styles.scss b/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/_styles.scss new file mode 100644 index 00000000000..e69de29bb2d diff --git a/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/index.ts b/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/index.ts new file mode 100644 index 00000000000..420c41a651e --- /dev/null +++ b/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/index.ts @@ -0,0 +1 @@ +export { default } from "./MacSettingsTable"; diff --git a/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx b/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx index 53989d3153a..ea1ab959edf 100644 --- a/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx +++ b/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx @@ -11,6 +11,7 @@ import getHostStatusTooltipText from "pages/hosts/helpers"; import StatusIndicator from "components/StatusIndicator"; import Icon from "components/Icon"; import { IconNames } from "components/icons"; +import { MacSettingsStatus } from "interfaces/mdm"; import IssueIcon from "../../../../../../assets/images/icon-issue-fleet-black-50-16x16@2x.png"; const baseClass = "host-summary"; @@ -20,8 +21,6 @@ interface IHostDiskEncryptionProps { tooltip?: string; } -type MacSettingsStatus = "Failing" | "Latest" | "Pending"; - interface IHostSummaryProps { statusClassName: string; titleData: any; // TODO: create interfaces for this and use consistently across host pages and related helpers @@ -29,6 +28,7 @@ interface IHostSummaryProps { isPremiumTier?: boolean; isOnlyObserver?: boolean; toggleOSPolicyModal?: () => void; + toggleMacSettingsModal?: () => void; showRefetchSpinner: boolean; onRefetchHost: ( evt: React.MouseEvent @@ -44,6 +44,7 @@ const HostSummary = ({ isPremiumTier, isOnlyObserver, toggleOSPolicyModal, + toggleMacSettingsModal, showRefetchSpinner, onRefetchHost, renderActionButtons, @@ -135,7 +136,8 @@ const HostSummary = ({ // const getIconNameAndTooltipText = ( // macSettingsStatus: MacSettingsStatus // ): [IconNames, string] => { - // const options: { [key: "Latest" | "Pending" | "Failing"] } = { + // const options: { [key: "Latest" | "Pending" | "Failing"] } = { + // // const options = { // Latest: ["success", "Host applied the latest settings"], // Pending: [ // "pending", @@ -151,13 +153,27 @@ const HostSummary = ({ const renderMacSettingsIndicator = () => { // TODO: actually determine this status - const macSettingsStatus: MacSettingsStatus = "Latest"; + const macSettingsStatus: MacSettingsStatus = "Pending"; - // TODO: get this function to work - // const [iconName, tooltipText] = getIconNameAndTooltipText( - // macSettingsStatus - // ); - const iconName = "success"; + // TODO: get below to work + // const statusDisplayOptions = { + // const statusDisplayOptions: { status: MacSettingsStatus: { iconName: IconNames, tooltipText: string } + // } = { + // Latest: { + // iconName: "success", + // tooltipText: "Host applied the latest settings", + // }, + // Pending: { + // iconName: "pending", + // tooltipText: "Host will apply the latest settings when it comes online", + // }, + // Failing: { + // iconName: "error", + // tooltipText: + // "Host failed to apply the latest settings. Click to view error(s).", + // }, + // }; + const iconName = "pending"; const tooltipText = "test tip text"; return ( @@ -171,8 +187,16 @@ const HostSummary = ({ data-tip-disable={false} > {/* TODO: fix alginment of this icon */} + {/* */} - {macSettingsStatus} + + {/* {macSettingsStatus} */} toggleOSPolicyModal && toggleOSPolicyModal()} + onClick={toggleOSPolicyModal} variant="text-link" className={`${baseClass}__os-policy-button`} > From 23ddc9f5e8cde471058bc54349ef6596b281f99d Mon Sep 17 00:00:00 2001 From: Jacob Shandling Date: Mon, 13 Feb 2023 10:24:01 -0800 Subject: [PATCH 04/25] Conditionally determine icon and tooltip text --- .../details/cards/HostSummary/HostSummary.tsx | 58 ++++++------------- 1 file changed, 19 insertions(+), 39 deletions(-) diff --git a/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx b/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx index ea1ab959edf..5a1c9d4462a 100644 --- a/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx +++ b/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx @@ -133,48 +133,28 @@ const HostSummary = ({ ); - // const getIconNameAndTooltipText = ( - // macSettingsStatus: MacSettingsStatus - // ): [IconNames, string] => { - // const options: { [key: "Latest" | "Pending" | "Failing"] } = { - // // const options = { - // Latest: ["success", "Host applied the latest settings"], - // Pending: [ - // "pending", - // "Host will apply the latest settings when it comes online", - // ], - // Failing: [ - // "error", - // "Host failed to apply the latest settings. Click to view error(s).", - // ], - // }; - // return options[macSettingsStatus]; - // }; - const renderMacSettingsIndicator = () => { // TODO: actually determine this status - const macSettingsStatus: MacSettingsStatus = "Pending"; + const macSettingsStatus: MacSettingsStatus = "Latest"; + + const statusDisplayOptions = { + Latest: { + iconName: "success", + tooltipText: "Host applied the latest settings", + }, + Pending: { + iconName: "pending", + tooltipText: "Host will apply the latest settings when it comes online", + }, + Failing: { + iconName: "error", + tooltipText: + "Host failed to apply the latest settings. Click to view error(s).", + }, + } as const; - // TODO: get below to work - // const statusDisplayOptions = { - // const statusDisplayOptions: { status: MacSettingsStatus: { iconName: IconNames, tooltipText: string } - // } = { - // Latest: { - // iconName: "success", - // tooltipText: "Host applied the latest settings", - // }, - // Pending: { - // iconName: "pending", - // tooltipText: "Host will apply the latest settings when it comes online", - // }, - // Failing: { - // iconName: "error", - // tooltipText: - // "Host failed to apply the latest settings. Click to view error(s).", - // }, - // }; - const iconName = "pending"; - const tooltipText = "test tip text"; + const iconName = statusDisplayOptions[macSettingsStatus].iconName; + const tooltipText = statusDisplayOptions[macSettingsStatus].tooltipText; return (
From 90cf2c93de234c00b7488c31b4ba2546e5d15f50 Mon Sep 17 00:00:00 2001 From: Jacob Shandling Date: Mon, 13 Feb 2023 12:08:04 -0800 Subject: [PATCH 05/25] Create settings indicator --- .../MacSettingsIndicator.tsx | 106 ++++++++++++++++++ .../details/MacSettingsIndicator/index.ts | 1 + 2 files changed, 107 insertions(+) create mode 100644 frontend/pages/hosts/details/MacSettingsIndicator/MacSettingsIndicator.tsx create mode 100644 frontend/pages/hosts/details/MacSettingsIndicator/index.ts diff --git a/frontend/pages/hosts/details/MacSettingsIndicator/MacSettingsIndicator.tsx b/frontend/pages/hosts/details/MacSettingsIndicator/MacSettingsIndicator.tsx new file mode 100644 index 00000000000..38af69d8023 --- /dev/null +++ b/frontend/pages/hosts/details/MacSettingsIndicator/MacSettingsIndicator.tsx @@ -0,0 +1,106 @@ +import React from "react"; +import ReactTooltip from "react-tooltip"; +import { IconNames } from "components/icons"; +import Icon from "components/Icon"; +import Button from "components/buttons/Button"; + +const baseClass = "settings-indicator"; + +interface IMacSettingsIndicator { + indicatorText: string; + iconName: IconNames; + onClick?: () => void; + tooltip?: { + tooltipText: string; + position?: "top" | "bottom"; + }; +} + +const MacSettingsIndicator = ({ + indicatorText, + iconName, + onClick, + tooltip, +}: IMacSettingsIndicator): JSX.Element => { + const getIndicatorTextWrapped = () => { + if (onClick && tooltip) { + return ( + <> + + + + + {tooltip.tooltipText} + + + ); + } + + // onclick without tooltip + if (onClick) { + return ( + + ); + } + + // tooltip without onclick + if (tooltip) { + return ( + <> + + {indicatorText} + + + {tooltip.tooltipText} + + + ); + } + + // no tooltip, no onclick + return indicatorText; + }; + + return ( + + + {getIndicatorTextWrapped()} + + ); +}; + +export default MacSettingsIndicator; diff --git a/frontend/pages/hosts/details/MacSettingsIndicator/index.ts b/frontend/pages/hosts/details/MacSettingsIndicator/index.ts new file mode 100644 index 00000000000..47e97520648 --- /dev/null +++ b/frontend/pages/hosts/details/MacSettingsIndicator/index.ts @@ -0,0 +1 @@ +export { default } from "./MacSettingsIndicator"; From 7b7cdb082de146b162a22c7b9791e685bc5d3b1d Mon Sep 17 00:00:00 2001 From: Jacob Shandling Date: Mon, 13 Feb 2023 14:25:47 -0800 Subject: [PATCH 06/25] mock mac setting data - will change to fit API --- frontend/interfaces/mdm.ts | 15 ++++- .../details/DeviceUserPage/DeviceUserPage.tsx | 10 +++- .../HostDetailsPage/HostDetailsPage.tsx | 22 +++++++- .../MacSettingsIndicator.tsx | 2 +- .../MacSettingsModal/MacSettingsModal.tsx | 9 ++- .../MacSettingsTableConfig.tsx | 56 ++++++++++++++----- 6 files changed, 92 insertions(+), 22 deletions(-) diff --git a/frontend/interfaces/mdm.ts b/frontend/interfaces/mdm.ts index 3d08e08900c..d7924326df4 100644 --- a/frontend/interfaces/mdm.ts +++ b/frontend/interfaces/mdm.ts @@ -56,7 +56,16 @@ export interface IMdmSummaryResponse { } // TODO: define below according to the API structure in issue #9599 -export type IMacSettings = unknown; -export type IMacSetting = unknown; - +export type MacSettingStatusOptions = + | "Action required (pending)" + | "Applied" + | "Enforcing (pending)" + | "Removing enforcement (pending)" + | "Failed"; +export type IMacSetting = { + name: string; + statusText: MacSettingStatusOptions; + errorText?: string; +}; +export type IMacSettings = IMacSetting[]; export type MacSettingsStatus = "Failing" | "Latest" | "Pending"; diff --git a/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx b/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx index 465b3fc80ca..102f912dc96 100644 --- a/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx +++ b/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx @@ -382,7 +382,15 @@ const DeviceUserPage = ({ {showMacSettingsModal && ( )} diff --git a/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx b/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx index f4caa6040aa..7b9eafb78bb 100644 --- a/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx +++ b/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx @@ -747,7 +747,27 @@ const HostDetailsPage = ({ {showMacSettingsModal && ( )} diff --git a/frontend/pages/hosts/details/MacSettingsIndicator/MacSettingsIndicator.tsx b/frontend/pages/hosts/details/MacSettingsIndicator/MacSettingsIndicator.tsx index 38af69d8023..60541b4da9d 100644 --- a/frontend/pages/hosts/details/MacSettingsIndicator/MacSettingsIndicator.tsx +++ b/frontend/pages/hosts/details/MacSettingsIndicator/MacSettingsIndicator.tsx @@ -11,7 +11,7 @@ interface IMacSettingsIndicator { iconName: IconNames; onClick?: () => void; tooltip?: { - tooltipText: string; + tooltipText: string | null; position?: "top" | "bottom"; }; } diff --git a/frontend/pages/hosts/details/MacSettingsModal/MacSettingsModal.tsx b/frontend/pages/hosts/details/MacSettingsModal/MacSettingsModal.tsx index 3e5898f930f..d2aede0e830 100644 --- a/frontend/pages/hosts/details/MacSettingsModal/MacSettingsModal.tsx +++ b/frontend/pages/hosts/details/MacSettingsModal/MacSettingsModal.tsx @@ -5,7 +5,8 @@ import { IMacSettings } from "interfaces/mdm"; import MacSettingsTable from "./MacSettingsTable"; interface IMacSettingsModalProps { - hostMacSettings?: IMacSettings; // TODO: define this type when API shape is determined + hostMacSettings: IMacSettings; // TODO: define this type when API shape is determined + isLoading: boolean; onClose: () => void; } @@ -13,12 +14,16 @@ const baseClass = "mac-settings-modal"; const MacSettingsModal = ({ hostMacSettings, + isLoading, onClose, }: IMacSettingsModalProps) => { return ( <> - +
diff --git a/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTable.tsx b/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTable.tsx index 8421fe4f56d..d34ba30a331 100644 --- a/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTable.tsx +++ b/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTable.tsx @@ -4,10 +4,7 @@ import TableContainer from "components/TableContainer"; import EmptyTable from "components/EmptyTable"; import { IMacSettings } from "interfaces/mdm"; -import { - generateTableHeaders, - generateDataSet, -} from "./MacSettingsTableConfig"; +import { tableHeaders, generateDataSet } from "./MacSettingsTableConfig"; const baseClass = "macsettings-table"; @@ -28,7 +25,7 @@ const MacSettingsTable = ({ { - const tableHeaders: IDataColumn[] = [ - { - title: "Name", - Header: "Name", - disableSortBy: true, - accessor: "name", - Cell: (cellProps: ICellProps): JSX.Element => ( - - ), - }, - { - title: "Status", - Header: "Status", - disableSortBy: true, - accessor: "statusText", - Cell: (cellProps: ICellProps) => { - // TODO: refine this logic according to API structure - const statusData = cellProps.row.original; - const statusText = statusData.statusText; - // const statusText = "Applied"; - const iconName = settingStatusOptions[statusText].iconName; - const tooltip = { - tooltipText: settingStatusOptions[statusText].tooltipText, - position: "bottom" as const, - }; - return ( - - ); - }, +const tableHeaders: IDataColumn[] = [ + { + title: "Name", + Header: "Name", + disableSortBy: true, + accessor: "name", + Cell: (cellProps: ICellProps): JSX.Element => ( + + ), + }, + { + title: "Status", + Header: "Status", + disableSortBy: true, + accessor: "statusText", + Cell: (cellProps: ICellProps) => { + // TODO: refine this logic according to API structure + const statusData = cellProps.row.original; + const statusText = statusData.statusText; + // const statusText = "Applied"; + const iconName = SETTING_STATUS_OPTIONS[statusText].iconName; + const tooltip = { + tooltipText: SETTING_STATUS_OPTIONS[statusText].tooltipText, + position: "bottom" as const, + }; + return ( + + ); }, - { - title: "Error", - Header: "Error", - disableSortBy: true, - accessor: "error", - Cell: (cellProps: ICellProps): JSX.Element => { - // TODO: logically generate settings error from API structure - return
Error
; - }, + }, + { + title: "Error", + Header: "Error", + disableSortBy: true, + accessor: "error", + Cell: (cellProps: ICellProps): JSX.Element => { + // TODO: logically generate settings error from API structure + return
Error
; }, - ]; - - return tableHeaders; -}; + }, +]; const generateDataSet = (hostMacSettings: IMacSettings): IMacSettings => { // TODO - make this real return hostMacSettings; }; -export { generateTableHeaders, generateDataSet }; +export { tableHeaders, generateDataSet }; diff --git a/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx b/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx index dd0bfc10fe8..a8bb225baca 100644 --- a/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx +++ b/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx @@ -13,6 +13,7 @@ import Icon from "components/Icon"; import { IconNames } from "components/icons"; import { MacSettingsStatus } from "interfaces/mdm"; import IssueIcon from "../../../../../../assets/images/icon-issue-fleet-black-50-16x16@2x.png"; +import MacSettingsIndicator from "../../MacSettingsIndicator"; const baseClass = "host-summary"; @@ -135,9 +136,9 @@ const HostSummary = ({ const renderMacSettingsIndicator = () => { // TODO: actually determine this status - const macSettingsStatus: MacSettingsStatus = "Pending"; + const macSettingsStatus: MacSettingsStatus = "Latest"; - const statusDisplayOptions = { + const STATUS_DISPLAY_OPTIONS = { Latest: { iconName: "success", tooltipText: "Host applied the latest settings", @@ -153,13 +154,19 @@ const HostSummary = ({ }, } as const; - const iconName = statusDisplayOptions[macSettingsStatus].iconName; - const tooltipText = statusDisplayOptions[macSettingsStatus].tooltipText; + const iconName = STATUS_DISPLAY_OPTIONS[macSettingsStatus].iconName; + const tooltipText = STATUS_DISPLAY_OPTIONS[macSettingsStatus].tooltipText; return (
macOS settings - + + {/* {macSettingsStatus} - {/* {macSettingsStatus} */} {tooltipText} - + */}
); }; @@ -262,7 +268,7 @@ const HostSummary = ({ `${titleData.os_version}` ) : (
diff --git a/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx b/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx index 0727e2fbd75..a4d2a974c79 100644 --- a/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx +++ b/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx @@ -1,7 +1,6 @@ -import LinkCell from "components/TableContainer/DataTable/LinkCell"; import TextCell from "components/TableContainer/DataTable/TextCell"; import React from "react"; -import { IMacSetting, IMacSettings } from "interfaces/mdm"; +import { IMacMdmProfile } from "interfaces/mdm"; import MacSettingsIndicator from "../../MacSettingsIndicator"; interface IHeaderProps { @@ -16,7 +15,7 @@ interface ICellProps { value: string; }; row: { - original: IMacSetting; + original: IMacMdmProfile; }; } @@ -31,25 +30,44 @@ interface IDataColumn { sortType?: string; } -const SETTING_STATUS_OPTIONS = { - "Action required (pending)": { - iconName: "pending", - tooltipText: "Follow Disk encryption instructions on your My device page.", - }, - Applied: { - iconName: "success", - tooltipText: "Disk encryption on and disk encryption key stored in Fleet.", - }, - "Enforcing (pending)": { - iconName: "pending", - tooltipText: "Setting will be enforced when the host comes online.", - }, - "Removing enforcement (pending)": { - iconName: "pending", - tooltipText: "Enforcement will be removed when the host comes online.", - }, - Failed: { iconName: "error", tooltipText: null }, -} as const; +const getStatusDisplayOptions = ( + profile: IMacMdmProfile +): { + statusText: string; + iconName: "pending" | "success" | "error"; + tooltipText: string | null; +} => { + const SETTING_STATUS_OPTIONS = { + pending: { + "Action required": + "Follow Disk encryption instructions on your My device page.", + Enforcing: "Setting will be enforced when the host comes online.", + "Removing enforcement": + "Enforcement will be removed when the host comes online.", + "": "", + }, + applied: { + iconName: "success", + tooltipText: + "Disk encryption on and disk encryption key stored in Fleet.", + }, + failed: { iconName: "error", tooltipText: null }, + } as const; + + if (profile.status === "pending") { + return { + statusText: `${profile.detail} (pending)`, + iconName: "pending", + tooltipText: SETTING_STATUS_OPTIONS.pending[profile.detail], + }; + } + return { + statusText: + profile.status.charAt(0).toUpperCase() + profile.status.slice(1), + iconName: SETTING_STATUS_OPTIONS[profile.status].iconName, + tooltipText: SETTING_STATUS_OPTIONS[profile.status].tooltipText, + }; +}; const tableHeaders: IDataColumn[] = [ { @@ -67,20 +85,14 @@ const tableHeaders: IDataColumn[] = [ disableSortBy: true, accessor: "statusText", Cell: (cellProps: ICellProps) => { - // TODO: refine this logic according to API structure - const statusData = cellProps.row.original; - const statusText = statusData.statusText; - // const statusText = "Applied"; - const iconName = SETTING_STATUS_OPTIONS[statusText].iconName; - const tooltip = { - tooltipText: SETTING_STATUS_OPTIONS[statusText].tooltipText, - position: "bottom" as const, - }; + const { statusText, iconName, tooltipText } = getStatusDisplayOptions( + cellProps.row.original + ); return ( ); }, @@ -90,16 +102,10 @@ const tableHeaders: IDataColumn[] = [ Header: "Error", disableSortBy: true, accessor: "error", - Cell: (cellProps: ICellProps): JSX.Element => { - // TODO: logically generate settings error from API structure - return
Error
; - }, + Cell: (cellProps: ICellProps): JSX.Element => ( + + ), }, ]; -const generateDataSet = (hostMacSettings: IMacSettings): IMacSettings => { - // TODO - make this real - return hostMacSettings; -}; - -export { tableHeaders, generateDataSet }; +export default tableHeaders; diff --git a/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx b/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx index a8bb225baca..9295c8ba70a 100644 --- a/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx +++ b/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx @@ -7,10 +7,8 @@ import Button from "components/buttons/Button"; import DiskSpaceGraph from "components/DiskSpaceGraph"; import HumanTimeDiffWithDateTip from "components/HumanTimeDiffWithDateTip"; import { humanHostMemory, wrapFleetHelper } from "utilities/helpers"; -import getHostStatusTooltipText from "pages/hosts/helpers"; +import { getHostStatusTooltipText } from "pages/hosts/helpers"; import StatusIndicator from "components/StatusIndicator"; -import Icon from "components/Icon"; -import { IconNames } from "components/icons"; import { MacSettingsStatus } from "interfaces/mdm"; import IssueIcon from "../../../../../../assets/images/icon-issue-fleet-black-50-16x16@2x.png"; import MacSettingsIndicator from "../../MacSettingsIndicator"; @@ -30,6 +28,7 @@ interface IHostSummaryProps { isOnlyObserver?: boolean; toggleOSPolicyModal?: () => void; toggleMacSettingsModal?: () => void; + macSettingsStatus: MacSettingsStatus; showRefetchSpinner: boolean; onRefetchHost: ( evt: React.MouseEvent @@ -46,6 +45,7 @@ const HostSummary = ({ isOnlyObserver, toggleOSPolicyModal, toggleMacSettingsModal, + macSettingsStatus, showRefetchSpinner, onRefetchHost, renderActionButtons, @@ -135,9 +135,7 @@ const HostSummary = ({ ); const renderMacSettingsIndicator = () => { - // TODO: actually determine this status - const macSettingsStatus: MacSettingsStatus = "Latest"; - + // const macSettingsStatus: MacSettingsStatus = "Latest"; const STATUS_DISPLAY_OPTIONS = { Latest: { iconName: "success", @@ -166,32 +164,6 @@ const HostSummary = ({ onClick={toggleMacSettingsModal} tooltip={{ tooltipText }} /> - {/* - - - - - - {tooltipText} - - */} ); }; diff --git a/frontend/pages/hosts/helpers.ts b/frontend/pages/hosts/helpers.ts index 3438313e867..eaee338ae58 100644 --- a/frontend/pages/hosts/helpers.ts +++ b/frontend/pages/hosts/helpers.ts @@ -1,6 +1,15 @@ -export default function getHostStatusTooltipText(status: string): string { +import { IMacSettings, MacSettingsStatus } from "interfaces/mdm"; + +export const getHostStatusTooltipText = (status: string): string => { if (status === "online") { return "Online hosts will respond to a live query."; } return "Offline hosts won’t respond to a live query because they may be shut down, asleep, or not connected to the internet."; -} +}; + +export const getMacSettingsStatus = ( + hostMacSettings: IMacSettings | undefined +): MacSettingsStatus => { + // TODO + return "Pending"; +}; From b539bd93b3bad1e5e8ea6764f1c397563c3b3dee Mon Sep 17 00:00:00 2001 From: Jacob Shandling Date: Tue, 14 Feb 2023 17:19:07 -0800 Subject: [PATCH 10/25] small style and copy changes --- .../MacSettingsTable/MacSettingsTableConfig.tsx | 7 ++++--- .../details/MacSettingsModal/MacSettingsTable/_styles.scss | 7 +++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx b/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx index a4d2a974c79..17370f2f4ff 100644 --- a/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx +++ b/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx @@ -102,9 +102,10 @@ const tableHeaders: IDataColumn[] = [ Header: "Error", disableSortBy: true, accessor: "error", - Cell: (cellProps: ICellProps): JSX.Element => ( - - ), + Cell: (cellProps: ICellProps): JSX.Element => { + const error = cellProps.row.original.error; + return ; + }, }, ]; diff --git a/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/_styles.scss b/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/_styles.scss index e69de29bb2d..53e57edea51 100644 --- a/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/_styles.scss +++ b/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/_styles.scss @@ -0,0 +1,7 @@ +.macsettings-table { + .statusText { + &__cell { + white-space: nowrap; + } + } +} From afece10eb2e2b2d65719815b53aed35c5acac110 Mon Sep 17 00:00:00 2001 From: Jacob Shandling Date: Wed, 15 Feb 2023 13:02:16 -0800 Subject: [PATCH 11/25] logic for macsettings status --- frontend/pages/hosts/helpers.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/frontend/pages/hosts/helpers.ts b/frontend/pages/hosts/helpers.ts index eaee338ae58..272036218d3 100644 --- a/frontend/pages/hosts/helpers.ts +++ b/frontend/pages/hosts/helpers.ts @@ -10,6 +10,12 @@ export const getHostStatusTooltipText = (status: string): string => { export const getMacSettingsStatus = ( hostMacSettings: IMacSettings | undefined ): MacSettingsStatus => { - // TODO - return "Pending"; + const statuses = hostMacSettings?.map((setting) => setting.status); + if (statuses?.includes("failed")) { + return "Failing"; + } + if (statuses?.includes("pending")) { + return "Pending"; + } + return "Latest"; }; From f26612834a68ad4abcad5165de851acf83a426b2 Mon Sep 17 00:00:00 2001 From: Jacob Shandling Date: Wed, 15 Feb 2023 13:03:04 -0800 Subject: [PATCH 12/25] correctly tie tooltips to unique ids --- .../details/MacSettingsIndicator/MacSettingsIndicator.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/pages/hosts/details/MacSettingsIndicator/MacSettingsIndicator.tsx b/frontend/pages/hosts/details/MacSettingsIndicator/MacSettingsIndicator.tsx index 51bf29d637a..1b861ba06bc 100644 --- a/frontend/pages/hosts/details/MacSettingsIndicator/MacSettingsIndicator.tsx +++ b/frontend/pages/hosts/details/MacSettingsIndicator/MacSettingsIndicator.tsx @@ -23,7 +23,7 @@ const MacSettingsIndicator = ({ tooltip, }: IMacSettingsIndicator): JSX.Element => { const getIndicatorTextWrapped = () => { - if (onClick && tooltip) { + if (onClick && tooltip?.tooltipText) { return ( <> {indicatorText} @@ -82,7 +82,7 @@ const MacSettingsIndicator = ({ place={tooltip.position ?? "bottom"} effect="solid" backgroundColor="#3e4771" - id="settings-indicator" + id={`${indicatorText}-tooltip`} data-html > {tooltip.tooltipText} From 561b4d47ae9c659c2dad3864da0e8f2931ebbf2f Mon Sep 17 00:00:00 2001 From: Jacob Shandling Date: Wed, 15 Feb 2023 13:57:40 -0800 Subject: [PATCH 13/25] style adjustments --- frontend/components/Modal/_styles.scss | 3 ++- .../pages/hosts/details/MacSettingsIndicator/_styles.scss | 4 ++++ .../MacSettingsTable/MacSettingsTableConfig.tsx | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/frontend/components/Modal/_styles.scss b/frontend/components/Modal/_styles.scss index 101eadd268f..9e72b8ea3c5 100644 --- a/frontend/components/Modal/_styles.scss +++ b/frontend/components/Modal/_styles.scss @@ -67,7 +67,8 @@ &__modal_container { @include position(absolute, 22px null null null); background-color: $core-white; - width: 570px; + // TODO: confirm modal width behavior + min-width: 570px; padding: $pad-xxlarge; border-radius: 8px; animation: scale-up 150ms ease-out; diff --git a/frontend/pages/hosts/details/MacSettingsIndicator/_styles.scss b/frontend/pages/hosts/details/MacSettingsIndicator/_styles.scss index 9b7a310a2f0..2be174c5389 100644 --- a/frontend/pages/hosts/details/MacSettingsIndicator/_styles.scss +++ b/frontend/pages/hosts/details/MacSettingsIndicator/_styles.scss @@ -2,6 +2,10 @@ display: flex; gap: 4px; + &__button { + font-weight: normal; + } + .icon { width: 16px; height: 16px; diff --git a/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx b/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx index 17370f2f4ff..9091d5e615b 100644 --- a/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx +++ b/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx @@ -92,7 +92,7 @@ const tableHeaders: IDataColumn[] = [ ); }, From b5613759610834ae53acbb47e9c638772c19b139 Mon Sep 17 00:00:00 2001 From: Jacob Shandling Date: Wed, 15 Feb 2023 15:36:30 -0800 Subject: [PATCH 14/25] style adjustments; error tooltip --- frontend/interfaces/mdm.ts | 2 +- .../hosts/details/MacSettingsIndicator/_styles.scss | 4 ++++ .../MacSettingsTable/MacSettingsTableConfig.tsx | 11 ++++++----- .../PolicyPage/components/PolicyForm/_styles.scss | 3 --- frontend/styles/global/_global.scss | 9 +++++++-- frontend/styles/var/colors.ts | 1 + 6 files changed, 19 insertions(+), 11 deletions(-) diff --git a/frontend/interfaces/mdm.ts b/frontend/interfaces/mdm.ts index 549bda93a4b..247ce1878d0 100644 --- a/frontend/interfaces/mdm.ts +++ b/frontend/interfaces/mdm.ts @@ -58,7 +58,7 @@ export interface IMdmSummaryResponse { export type IMacMdmProfile = { name: string; status: "failed" | "pending" | "applied"; - detail: "" | "Removing enforcement" | "Enforcing" | "Action required"; + detail: "" | "Removing enforcement" | "Enforcing"; error: string; }; export type IMacSettings = IMacMdmProfile[]; diff --git a/frontend/pages/hosts/details/MacSettingsIndicator/_styles.scss b/frontend/pages/hosts/details/MacSettingsIndicator/_styles.scss index 2be174c5389..fce8265c95e 100644 --- a/frontend/pages/hosts/details/MacSettingsIndicator/_styles.scss +++ b/frontend/pages/hosts/details/MacSettingsIndicator/_styles.scss @@ -11,4 +11,8 @@ height: 16px; align-self: center; } + + .__react_component_tooltip { + white-space: normal; + } } diff --git a/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx b/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx index 9091d5e615b..b7ba132915e 100644 --- a/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx +++ b/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx @@ -1,6 +1,10 @@ import TextCell from "components/TableContainer/DataTable/TextCell"; import React from "react"; import { IMacMdmProfile } from "interfaces/mdm"; +import { uniqueId } from "lodash"; +import ReactTooltip from "react-tooltip"; +import { COLORS } from "styles/var/colors"; +import TruncatedTextCell from "components/TableContainer/DataTable/TruncatedTextCell"; import MacSettingsIndicator from "../../MacSettingsIndicator"; interface IHeaderProps { @@ -39,8 +43,6 @@ const getStatusDisplayOptions = ( } => { const SETTING_STATUS_OPTIONS = { pending: { - "Action required": - "Follow Disk encryption instructions on your My device page.", Enforcing: "Setting will be enforced when the host comes online.", "Removing enforcement": "Enforcement will be removed when the host comes online.", @@ -48,8 +50,7 @@ const getStatusDisplayOptions = ( }, applied: { iconName: "success", - tooltipText: - "Disk encryption on and disk encryption key stored in Fleet.", + tooltipText: "Host applied the setting.", }, failed: { iconName: "error", tooltipText: null }, } as const; @@ -104,7 +105,7 @@ const tableHeaders: IDataColumn[] = [ accessor: "error", Cell: (cellProps: ICellProps): JSX.Element => { const error = cellProps.row.original.error; - return ; + return ; }, }, ]; diff --git a/frontend/pages/policies/PolicyPage/components/PolicyForm/_styles.scss b/frontend/pages/policies/PolicyPage/components/PolicyForm/_styles.scss index 376e3fa55e1..439b130ef30 100644 --- a/frontend/pages/policies/PolicyPage/components/PolicyForm/_styles.scss +++ b/frontend/pages/policies/PolicyPage/components/PolicyForm/_styles.scss @@ -186,9 +186,6 @@ .policy-form__run { min-width: 64px; } - .__react_component_tooltip { - text-align: center; - } } &__title { diff --git a/frontend/styles/global/_global.scss b/frontend/styles/global/_global.scss index 0c900164ac3..6f3db44bcfa 100644 --- a/frontend/styles/global/_global.scss +++ b/frontend/styles/global/_global.scss @@ -19,10 +19,15 @@ html, body { height: 100%; - .__react_component_tooltip.show { - opacity: 1; // Overrides 0.9 default opacity + .__react_component_tooltip { text-align: center; padding: 6px; + max-width: 320px; + height: auto; + + &.show { + opacity: 1; // Overrides 0.9 default opacity + } } } diff --git a/frontend/styles/var/colors.ts b/frontend/styles/var/colors.ts index 32c2281d795..4298ecca74d 100644 --- a/frontend/styles/var/colors.ts +++ b/frontend/styles/var/colors.ts @@ -20,6 +20,7 @@ export const COLORS = { "ui-blue-50": "#B4B2FE", "ui-blue-25": "#D9D9FE", "ui-blue-10": "#F1F0FF", + "tooltip-bg": "#3E4771", // Notifications & status "status-success": "#3DB67B", From 6980103d0cd2b88401abfb8746b357668fc52998 Mon Sep 17 00:00:00 2001 From: Jacob Shandling Date: Wed, 15 Feb 2023 15:42:41 -0800 Subject: [PATCH 15/25] change file --- changes/9413-macOS-settings-indicator | 1 + 1 file changed, 1 insertion(+) create mode 100644 changes/9413-macOS-settings-indicator diff --git a/changes/9413-macOS-settings-indicator b/changes/9413-macOS-settings-indicator new file mode 100644 index 00000000000..38994b7fb21 --- /dev/null +++ b/changes/9413-macOS-settings-indicator @@ -0,0 +1 @@ +- Create a macOS settings indicator and modal on the host details and device user pages. From de675a5d20791968acd6ff2dad63a20309974bd4 Mon Sep 17 00:00:00 2001 From: Jacob Shandling Date: Thu, 16 Feb 2023 13:49:38 -0800 Subject: [PATCH 16/25] Add conditions for displaying macOS settings indicator; misc cleanup --- .../details/DeviceUserPage/DeviceUserPage.tsx | 8 +++---- .../HostDetailsPage/HostDetailsPage.tsx | 14 +++---------- .../UnenrollMdmModal/UnenrollMdmModal.tsx | 8 +------ .../details/cards/HostSummary/HostSummary.tsx | 21 ++++++++++++------- tools/mdm/apple/toggle-mdm-dev | 2 +- 5 files changed, 22 insertions(+), 31 deletions(-) diff --git a/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx b/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx index c1364044ae8..9927bf54301 100644 --- a/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx +++ b/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx @@ -29,7 +29,6 @@ import { wrapFleetHelper, humanHostDiskEncryptionEnabled, } from "utilities/helpers"; -import { getMacSettingsStatus } from "pages/hosts/helpers"; import HostSummaryCard from "../cards/HostSummary"; import AboutCard from "../cards/About"; @@ -96,7 +95,7 @@ const DeviceUserPage = ({ } ); - const { data: macadmins, refetch: refetchMacadmins } = useQuery( + const { data: deviceMacAdminsData, refetch: refetchMacadmins } = useQuery( ["macadmins", deviceAuthToken], () => deviceUserAPI.loadHostDetailsExtension(deviceAuthToken, "macadmins"), { @@ -352,7 +351,8 @@ const DeviceUserPage = ({ diskEncryption={hostDiskEncryption} isPremiumTier={isPremiumTier} toggleMacSettingsModal={toggleMacSettingsModal} - macSettingsStatus={getMacSettingsStatus(host?.mdm.profiles)} + hostMacSettings={host?.mdm.profiles} + mdmName={deviceMacAdminsData?.mobile_device_management?.name} showRefetchSpinner={showRefetchSpinner} onRefetchHost={onRefetchHost} renderActionButtons={renderActionButtons} @@ -378,7 +378,7 @@ const DeviceUserPage = ({ diff --git a/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx b/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx index ed1d682b4ce..d708e782b67 100644 --- a/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx +++ b/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx @@ -28,7 +28,6 @@ import { IQuery, IFleetQueriesResponse } from "interfaces/query"; import { IQueryStats } from "interfaces/query_stats"; import { ISoftware } from "interfaces/software"; import { ITeam } from "interfaces/team"; -import { IMacSettings, MacSettingsStatus } from "interfaces/mdm"; import Spinner from "components/Spinner"; import TabsWrapper from "components/TabsWrapper"; @@ -41,7 +40,6 @@ import { humanHostDiskEncryptionEnabled, wrapFleetHelper, } from "utilities/helpers"; -import { getMacSettingsStatus } from "pages/hosts/helpers"; import HostSummaryCard from "../cards/HostSummary"; import AboutCard from "../cards/About"; @@ -149,7 +147,6 @@ const HostDetailsPage = ({ ] = useState({}); const [usersState, setUsersState] = useState<{ username: string }[]>([]); const [usersSearchString, setUsersSearchString] = useState(""); - const [hideEditMdm, setHideEditMdm] = useState(false); const { data: fleetQueries, error: fleetQueriesError } = useQuery< IFleetQueriesResponse, @@ -659,7 +656,8 @@ const HostDetailsPage = ({ isOnlyObserver={isOnlyObserver} toggleOSPolicyModal={toggleOSPolicyModal} toggleMacSettingsModal={toggleMacSettingsModal} - macSettingsStatus={getMacSettingsStatus(host?.mdm.profiles)} + hostMacSettings={host?.mdm.profiles} + mdmName={mdm?.name} showRefetchSpinner={showRefetchSpinner} onRefetchHost={onRefetchHost} renderActionButtons={renderActionButtons} @@ -785,13 +783,7 @@ const HostDetailsPage = ({ /> )} {showUnenrollMdmModal && !!host && ( - { - setHideEditMdm(true); - }} - /> + )} {showDiskEncryptionModal && host && ( void; - onSuccess: () => void; } const baseClass = "unenroll-mdm-modal"; -const UnenrollMdmModal = ({ - hostId, - onClose, - onSuccess, -}: IUnenrollMdmModalProps) => { +const UnenrollMdmModal = ({ hostId, onClose }: IUnenrollMdmModalProps) => { const [requestState, setRequestState] = useState< undefined | "unenrolling" | "error" >(undefined); @@ -31,7 +26,6 @@ const UnenrollMdmModal = ({ try { await mdmAPI.unenrollHostFromMdm(hostId, 5000); renderFlash("success", "Successfully turned off MDM."); - onSuccess(); onClose(); } catch (unenrollMdmError: unknown) { console.log(unenrollMdmError); diff --git a/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx b/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx index 9295c8ba70a..8fd3af4ca51 100644 --- a/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx +++ b/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx @@ -7,9 +7,12 @@ import Button from "components/buttons/Button"; import DiskSpaceGraph from "components/DiskSpaceGraph"; import HumanTimeDiffWithDateTip from "components/HumanTimeDiffWithDateTip"; import { humanHostMemory, wrapFleetHelper } from "utilities/helpers"; -import { getHostStatusTooltipText } from "pages/hosts/helpers"; +import { + getHostStatusTooltipText, + getMacSettingsStatus, +} from "pages/hosts/helpers"; import StatusIndicator from "components/StatusIndicator"; -import { MacSettingsStatus } from "interfaces/mdm"; +import { IMacSettings, MacSettingsStatus } from "interfaces/mdm"; import IssueIcon from "../../../../../../assets/images/icon-issue-fleet-black-50-16x16@2x.png"; import MacSettingsIndicator from "../../MacSettingsIndicator"; @@ -28,7 +31,8 @@ interface IHostSummaryProps { isOnlyObserver?: boolean; toggleOSPolicyModal?: () => void; toggleMacSettingsModal?: () => void; - macSettingsStatus: MacSettingsStatus; + hostMacSettings?: IMacSettings; + mdmName?: string; showRefetchSpinner: boolean; onRefetchHost: ( evt: React.MouseEvent @@ -45,7 +49,8 @@ const HostSummary = ({ isOnlyObserver, toggleOSPolicyModal, toggleMacSettingsModal, - macSettingsStatus, + hostMacSettings, + mdmName, showRefetchSpinner, onRefetchHost, renderActionButtons, @@ -135,7 +140,6 @@ const HostSummary = ({ ); const renderMacSettingsIndicator = () => { - // const macSettingsStatus: MacSettingsStatus = "Latest"; const STATUS_DISPLAY_OPTIONS = { Latest: { iconName: "success", @@ -152,6 +156,8 @@ const HostSummary = ({ }, } as const; + const macSettingsStatus = getMacSettingsStatus(hostMacSettings); + const iconName = STATUS_DISPLAY_OPTIONS[macSettingsStatus].iconName; const tooltipText = STATUS_DISPLAY_OPTIONS[macSettingsStatus].tooltipText; @@ -190,11 +196,10 @@ const HostSummary = ({ {isPremiumTier && renderHostTeam()} - {/* TODO: confirm how to determine if 'macOS settings are enforced on the host' */} {titleData.platform === "darwin" && isPremiumTier && - // TODO: change below to use actual API return values when implemented for issue #9599 - // titleData.mdm.macsettingsenrolledstatus && + mdmName === "Fleet" && // show if 1 - host is enrolled in Fleet MDM, and + hostMacSettings && // 2 - host has at least one setting (profile) enforced renderMacSettingsIndicator()}
diff --git a/tools/mdm/apple/toggle-mdm-dev b/tools/mdm/apple/toggle-mdm-dev index 43c655bddc5..302c7d8d403 100755 --- a/tools/mdm/apple/toggle-mdm-dev +++ b/tools/mdm/apple/toggle-mdm-dev @@ -1,6 +1,6 @@ #!/bin/bash -if [[$USE_MDM == "1"]]; then +if [[ $USE_MDM == "1" ]]; then export USE_MDM=0 else export USE_MDM=1 From 26965727b59fa6e701dd7c484fcf68ce8a67e7b0 Mon Sep 17 00:00:00 2001 From: Jacob Shandling Date: Fri, 17 Feb 2023 13:02:46 -0800 Subject: [PATCH 17/25] update MacSettingsTable to use DEFAULT_EMPTY_CELL_VALUE --- .../MacSettingsTable/MacSettingsTableConfig.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx b/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx index b7ba132915e..fb1e23e4462 100644 --- a/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx +++ b/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx @@ -6,6 +6,7 @@ import ReactTooltip from "react-tooltip"; import { COLORS } from "styles/var/colors"; import TruncatedTextCell from "components/TableContainer/DataTable/TruncatedTextCell"; import MacSettingsIndicator from "../../MacSettingsIndicator"; +import { DEFAULT_EMPTY_CELL_VALUE } from "utilities/constants"; interface IHeaderProps { column: { @@ -105,7 +106,7 @@ const tableHeaders: IDataColumn[] = [ accessor: "error", Cell: (cellProps: ICellProps): JSX.Element => { const error = cellProps.row.original.error; - return ; + return ; }, }, ]; From 5ca43c37b8443fbcb21460b831003555bd80338c Mon Sep 17 00:00:00 2001 From: Jacob Shandling Date: Mon, 20 Feb 2023 16:33:57 -0800 Subject: [PATCH 18/25] Retool for new API; gracefully handle unexpected profiles --- .../TruncatedTextCell/TruncatedTextCell.tsx | 7 +- .../DataTable/TruncatedTextCell/_styles.scss | 3 + frontend/interfaces/mdm.ts | 10 +- .../details/DeviceUserPage/DeviceUserPage.tsx | 39 ++++-- .../HostDetailsPage/HostDetailsPage.tsx | 39 ++++-- .../MacSettingsIndicator.tsx | 2 +- .../MacSettingsTableConfig.tsx | 116 +++++++++++------- 7 files changed, 144 insertions(+), 72 deletions(-) diff --git a/frontend/components/TableContainer/DataTable/TruncatedTextCell/TruncatedTextCell.tsx b/frontend/components/TableContainer/DataTable/TruncatedTextCell/TruncatedTextCell.tsx index 0fb0e943ccb..3d1abae71a3 100644 --- a/frontend/components/TableContainer/DataTable/TruncatedTextCell/TruncatedTextCell.tsx +++ b/frontend/components/TableContainer/DataTable/TruncatedTextCell/TruncatedTextCell.tsx @@ -2,6 +2,7 @@ import React, { useState, useRef, useLayoutEffect } from "react"; import { uniqueId } from "lodash"; import ReactTooltip from "react-tooltip"; +import { DEFAULT_EMPTY_CELL_VALUE } from "utilities/constants"; interface ITruncatedTextCellProps { value: string | number | boolean; @@ -28,7 +29,7 @@ const TruncatedTextCell = ({ const tooltipId = uniqueId(); const tooltipDisabled = offsetWidth === scrollWidth; - + const isDefaultValue = value === DEFAULT_EMPTY_CELL_VALUE; return (
{value} diff --git a/frontend/components/TableContainer/DataTable/TruncatedTextCell/_styles.scss b/frontend/components/TableContainer/DataTable/TruncatedTextCell/_styles.scss index 6386b9cf48d..9d9a8655e60 100644 --- a/frontend/components/TableContainer/DataTable/TruncatedTextCell/_styles.scss +++ b/frontend/components/TableContainer/DataTable/TruncatedTextCell/_styles.scss @@ -1,4 +1,7 @@ .truncated-cell { + .text-muted { + color: $ui-fleet-black-50; + } .data-table__truncated-text { &--cell { display: inline-block; diff --git a/frontend/interfaces/mdm.ts b/frontend/interfaces/mdm.ts index 247ce1878d0..8f0150ab797 100644 --- a/frontend/interfaces/mdm.ts +++ b/frontend/interfaces/mdm.ts @@ -55,11 +55,15 @@ export interface IMdmSummaryResponse { mobile_device_management_solution: IMdmSolution[] | null; } +export type MacMdmProfileStatus = "success" | "pending" | "failed"; +export type MacMdmProfileOperationType = "remove" | "install"; + export type IMacMdmProfile = { + profile_id: number; name: string; - status: "failed" | "pending" | "applied"; - detail: "" | "Removing enforcement" | "Enforcing"; - error: string; + operation_type: MacMdmProfileOperationType; + status: MacMdmProfileStatus; + detail: string; }; export type IMacSettings = IMacMdmProfile[]; export type MacSettingsStatus = "Failing" | "Latest" | "Pending"; diff --git a/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx b/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx index 9927bf54301..2c3379ee1e9 100644 --- a/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx +++ b/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx @@ -191,28 +191,49 @@ const DeviceUserPage = ({ if (host) { host.mdm.profiles = [ { + profile_id: 42, + name: "Users", + status: "success", + operation_type: "install", + detail: "", + }, + { + profile_id: 1, name: "Restrictions", + operation_type: "install", status: "failed", - detail: "", - error: "The “Restrictions” payload couldn’t be installed.", + detail: "The “Restrictions” payload couldn’t be installed.", }, { + profile_id: 2, name: "Password", + operation_type: "install", status: "pending", detail: "Removing enforcement", - error: "", }, { - name: "Wifi", + profile_id: 3, + name: "Restrictions", + operation_type: "remove", + status: "failed", + detail: "The profile could not be removed.", + }, + + { + profile_id: 4, + name: "Password", status: "pending", - detail: "Enforcing", - error: "", + operation_type: "remove", + detail: "", }, + + // below case should never be returned { - name: "Users", - status: "applied", + profile_id: 5, + name: "secret sauce", + status: "success", + operation_type: "remove", detail: "", - error: "", }, ]; } diff --git a/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx b/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx index d708e782b67..6be7ef707bd 100644 --- a/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx +++ b/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx @@ -321,28 +321,49 @@ const HostDetailsPage = ({ if (host) { host.mdm.profiles = [ { + profile_id: 42, + name: "Users", + status: "success", + operation_type: "install", + detail: "", + }, + { + profile_id: 1, name: "Restrictions", + operation_type: "install", status: "failed", - detail: "", - error: "The “Restrictions” payload couldn’t be installed.", + detail: "The “Restrictions” payload couldn’t be installed.", }, { + profile_id: 2, name: "Password", + operation_type: "install", status: "pending", detail: "Removing enforcement", - error: "", }, { - name: "Wifi", + profile_id: 3, + name: "Restrictions", + operation_type: "remove", + status: "failed", + detail: "The profile could not be removed.", + }, + + { + profile_id: 4, + name: "Password", status: "pending", - detail: "Enforcing", - error: "", + operation_type: "remove", + detail: "", }, + + // below case should never be returned { - name: "Users", - status: "applied", + profile_id: 5, + name: "secret sauce", + status: "success", + operation_type: "remove", detail: "", - error: "", }, ]; } diff --git a/frontend/pages/hosts/details/MacSettingsIndicator/MacSettingsIndicator.tsx b/frontend/pages/hosts/details/MacSettingsIndicator/MacSettingsIndicator.tsx index 1b861ba06bc..473745ee334 100644 --- a/frontend/pages/hosts/details/MacSettingsIndicator/MacSettingsIndicator.tsx +++ b/frontend/pages/hosts/details/MacSettingsIndicator/MacSettingsIndicator.tsx @@ -6,7 +6,7 @@ import Button from "components/buttons/Button"; const baseClass = "settings-indicator"; -interface IMacSettingsIndicator { +export interface IMacSettingsIndicator { indicatorText: string; iconName: IconNames; onClick?: () => void; diff --git a/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx b/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx index fb1e23e4462..f64885d9738 100644 --- a/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx +++ b/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx @@ -1,12 +1,14 @@ import TextCell from "components/TableContainer/DataTable/TextCell"; import React from "react"; -import { IMacMdmProfile } from "interfaces/mdm"; -import { uniqueId } from "lodash"; -import ReactTooltip from "react-tooltip"; -import { COLORS } from "styles/var/colors"; +import { + IMacMdmProfile, + MacMdmProfileOperationType, + MacMdmProfileStatus, +} from "interfaces/mdm"; +import { DEFAULT_EMPTY_CELL_VALUE } from "utilities/constants"; import TruncatedTextCell from "components/TableContainer/DataTable/TruncatedTextCell"; import MacSettingsIndicator from "../../MacSettingsIndicator"; -import { DEFAULT_EMPTY_CELL_VALUE } from "utilities/constants"; +import { IMacSettingsIndicator } from "../../MacSettingsIndicator/MacSettingsIndicator"; interface IHeaderProps { column: { @@ -35,40 +37,44 @@ interface IDataColumn { sortType?: string; } -const getStatusDisplayOptions = ( - profile: IMacMdmProfile -): { - statusText: string; - iconName: "pending" | "success" | "error"; - tooltipText: string | null; -} => { - const SETTING_STATUS_OPTIONS = { +const PROFILE_DISPLAY_CONFIG: Record< + MacMdmProfileOperationType, + Record +> = { + install: { pending: { - Enforcing: "Setting will be enforced when the host comes online.", - "Removing enforcement": - "Enforcement will be removed when the host comes online.", - "": "", + indicatorText: "Enforcing (pending)", + iconName: "pending", + tooltip: { + tooltipText: "Setting will be enforced when the host comes online.", + }, }, - applied: { + success: { + indicatorText: "Applied", iconName: "success", - tooltipText: "Host applied the setting.", + tooltip: { tooltipText: "Host applied the setting." }, }, - failed: { iconName: "error", tooltipText: null }, - } as const; - - if (profile.status === "pending") { - return { - statusText: `${profile.detail} (pending)`, + failed: { + indicatorText: "Failed", + iconName: "error", + tooltip: undefined, + }, + }, + remove: { + pending: { + indicatorText: "Removing enforcement (pending)", iconName: "pending", - tooltipText: SETTING_STATUS_OPTIONS.pending[profile.detail], - }; - } - return { - statusText: - profile.status.charAt(0).toUpperCase() + profile.status.slice(1), - iconName: SETTING_STATUS_OPTIONS[profile.status].iconName, - tooltipText: SETTING_STATUS_OPTIONS[profile.status].tooltipText, - }; + tooltip: { + tooltipText: "Enforcement will be removed when the host comes online.", + }, + }, + success: null, // should not be reached + failed: { + indicatorText: "Failed", + iconName: "error", + tooltip: undefined, + }, + }, }; const tableHeaders: IDataColumn[] = [ @@ -87,26 +93,42 @@ const tableHeaders: IDataColumn[] = [ disableSortBy: true, accessor: "statusText", Cell: (cellProps: ICellProps) => { - const { statusText, iconName, tooltipText } = getStatusDisplayOptions( - cellProps.row.original - ); - return ( - - ); + const { status, operation_type } = cellProps.row.original; + const options = PROFILE_DISPLAY_CONFIG[operation_type]?.[status]; + if (options) { + const { indicatorText, iconName } = options; + const tooltip = { + tooltipText: options.tooltip?.tooltipText ?? null, + position: "top" as const, + }; + return ( + + ); + } + + // graceful error - this state should not be reached based on the API spec + return ; }, }, { title: "Error", Header: "Error", disableSortBy: true, - accessor: "error", + accessor: "detail", Cell: (cellProps: ICellProps): JSX.Element => { - const error = cellProps.row.original.error; - return ; + const profile = cellProps.row.original; + return ( + + ); }, }, ]; From 270d269a60cdfdb557bdf95f872e82d098fcdf69 Mon Sep 17 00:00:00 2001 From: Jacob Shandling Date: Mon, 20 Feb 2023 17:06:10 -0800 Subject: [PATCH 19/25] tests --- .../MacSettingsIndicator.tests.tsx | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 frontend/pages/hosts/details/MacSettingsIndicator/MacSettingsIndicator.tests.tsx diff --git a/frontend/pages/hosts/details/MacSettingsIndicator/MacSettingsIndicator.tests.tsx b/frontend/pages/hosts/details/MacSettingsIndicator/MacSettingsIndicator.tests.tsx new file mode 100644 index 00000000000..1b2e99b3949 --- /dev/null +++ b/frontend/pages/hosts/details/MacSettingsIndicator/MacSettingsIndicator.tests.tsx @@ -0,0 +1,98 @@ +import React from "react"; +import { fireEvent, render, screen } from "@testing-library/react"; +import MacSettingsIndicator from "./MacSettingsIndicator"; + +describe("MacSettingsIndicator", () => { + it("Renders the text and icon", () => { + const indicatorText = "test text"; + render( + + ); + const renderedIndicatorText = screen.getByText(indicatorText); + const renderedIcon = screen.getByTestId("icon"); + + expect(renderedIndicatorText).toBeInTheDocument(); + expect(renderedIcon).toBeInTheDocument(); + }); + + it("Renders text, icon, and tooltip", () => { + const indicatorText = "test text"; + const tooltipText = "test tooltip text"; + render( + + ); + const renderedIndicatorText = screen.getByText(indicatorText); + const renderedIcon = screen.getByTestId("icon"); + const renderedTooltipText = screen.getByText(tooltipText); + + expect(renderedIndicatorText).toBeInTheDocument(); + expect(renderedIcon).toBeInTheDocument(); + expect(renderedTooltipText).toBeInTheDocument(); + }); + + it("Renders text, icon, and onClick", () => { + const indicatorText = "test text"; + const onClick = () => { + const newDiv = document.createElement("div"); + newDiv.appendChild(document.createTextNode("onClick called")); + document.body.appendChild(newDiv); + }; + render( + { + onClick(); + }} + /> + ); + + const renderedIndicatorText = screen.getByText(indicatorText); + const renderedIcon = screen.getByTestId("icon"); + const renderedButton = screen.getByRole("button"); + + expect(renderedIndicatorText).toBeInTheDocument(); + expect(renderedIcon).toBeInTheDocument(); + expect(renderedButton).toBeInTheDocument(); + + fireEvent.click(renderedButton); + expect(screen.getByText("onClick called")).toBeInTheDocument(); + }); + + it("Renders text, icon, tooltip and onClick", () => { + const indicatorText = "test text"; + const tooltipText = "test tooltip text"; + const onClick = () => { + const newDiv = document.createElement("div"); + newDiv.appendChild(document.createTextNode("onClick called")); + document.body.appendChild(newDiv); + }; + render( + { + onClick(); + }} + tooltip={{ tooltipText }} + /> + ); + + const renderedIndicatorText = screen.getByText(indicatorText); + const renderedIcon = screen.getByTestId("icon"); + const renderedButton = screen.getByRole("button"); + const renderedTooltipText = screen.getByText(tooltipText); + + expect(renderedIndicatorText).toBeInTheDocument(); + expect(renderedIcon).toBeInTheDocument(); + expect(renderedButton).toBeInTheDocument(); + expect(renderedTooltipText).toBeInTheDocument(); + + fireEvent.click(renderedButton); + expect(screen.getByText("onClick called")).toBeInTheDocument(); + }); +}); From c6eb53c05dc53fadb11dccb8ad68a9c1e181999c Mon Sep 17 00:00:00 2001 From: Jacob Shandling Date: Mon, 20 Feb 2023 17:06:45 -0800 Subject: [PATCH 20/25] remove faulty test --- .../MacSettingsIndicator.tests.tsx | 33 ------------------- 1 file changed, 33 deletions(-) diff --git a/frontend/pages/hosts/details/MacSettingsIndicator/MacSettingsIndicator.tests.tsx b/frontend/pages/hosts/details/MacSettingsIndicator/MacSettingsIndicator.tests.tsx index 1b2e99b3949..115e6406f11 100644 --- a/frontend/pages/hosts/details/MacSettingsIndicator/MacSettingsIndicator.tests.tsx +++ b/frontend/pages/hosts/details/MacSettingsIndicator/MacSettingsIndicator.tests.tsx @@ -62,37 +62,4 @@ describe("MacSettingsIndicator", () => { fireEvent.click(renderedButton); expect(screen.getByText("onClick called")).toBeInTheDocument(); }); - - it("Renders text, icon, tooltip and onClick", () => { - const indicatorText = "test text"; - const tooltipText = "test tooltip text"; - const onClick = () => { - const newDiv = document.createElement("div"); - newDiv.appendChild(document.createTextNode("onClick called")); - document.body.appendChild(newDiv); - }; - render( - { - onClick(); - }} - tooltip={{ tooltipText }} - /> - ); - - const renderedIndicatorText = screen.getByText(indicatorText); - const renderedIcon = screen.getByTestId("icon"); - const renderedButton = screen.getByRole("button"); - const renderedTooltipText = screen.getByText(tooltipText); - - expect(renderedIndicatorText).toBeInTheDocument(); - expect(renderedIcon).toBeInTheDocument(); - expect(renderedButton).toBeInTheDocument(); - expect(renderedTooltipText).toBeInTheDocument(); - - fireEvent.click(renderedButton); - expect(screen.getByText("onClick called")).toBeInTheDocument(); - }); }); From e5e80924bc9e112f90c4acd0a320a2604b747e18 Mon Sep 17 00:00:00 2001 From: Jacob Shandling Date: Tue, 21 Feb 2023 09:42:34 -0800 Subject: [PATCH 21/25] specify type name --- frontend/interfaces/mdm.ts | 4 ++-- .../MacSettingsTable/MacSettingsTableConfig.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/interfaces/mdm.ts b/frontend/interfaces/mdm.ts index a4ada027a2a..1d5e01bf58c 100644 --- a/frontend/interfaces/mdm.ts +++ b/frontend/interfaces/mdm.ts @@ -71,12 +71,12 @@ export interface IMdmProfilesResponse { export type MacMdmProfileStatus = "success" | "pending" | "failed"; export type MacMdmProfileOperationType = "remove" | "install"; -export type IMacMdmProfile = { +export type IHostMacMdmProfile = { profile_id: number; name: string; operation_type: MacMdmProfileOperationType; status: MacMdmProfileStatus; detail: string; }; -export type IMacSettings = IMacMdmProfile[]; +export type IMacSettings = IHostMacMdmProfile[]; export type MacSettingsStatus = "Failing" | "Latest" | "Pending"; diff --git a/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx b/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx index f64885d9738..3a789712955 100644 --- a/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx +++ b/frontend/pages/hosts/details/MacSettingsModal/MacSettingsTable/MacSettingsTableConfig.tsx @@ -1,7 +1,7 @@ import TextCell from "components/TableContainer/DataTable/TextCell"; import React from "react"; import { - IMacMdmProfile, + IHostMacMdmProfile, MacMdmProfileOperationType, MacMdmProfileStatus, } from "interfaces/mdm"; @@ -22,7 +22,7 @@ interface ICellProps { value: string; }; row: { - original: IMacMdmProfile; + original: IHostMacMdmProfile; }; } From 06277bf7396324665207a929dfe2f0040fdd5def Mon Sep 17 00:00:00 2001 From: Jacob Shandling Date: Tue, 21 Feb 2023 15:55:12 -0800 Subject: [PATCH 22/25] remove mock host profiles data --- .../details/DeviceUserPage/DeviceUserPage.tsx | 51 ------------------- .../HostDetailsPage/HostDetailsPage.tsx | 51 ------------------- 2 files changed, 102 deletions(-) diff --git a/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx b/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx index 2c3379ee1e9..753700daa04 100644 --- a/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx +++ b/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx @@ -187,57 +187,6 @@ const DeviceUserPage = ({ } ); - // TODO: remove this mock data once API is returning real data - if (host) { - host.mdm.profiles = [ - { - profile_id: 42, - name: "Users", - status: "success", - operation_type: "install", - detail: "", - }, - { - profile_id: 1, - name: "Restrictions", - operation_type: "install", - status: "failed", - detail: "The “Restrictions” payload couldn’t be installed.", - }, - { - profile_id: 2, - name: "Password", - operation_type: "install", - status: "pending", - detail: "Removing enforcement", - }, - { - profile_id: 3, - name: "Restrictions", - operation_type: "remove", - status: "failed", - detail: "The profile could not be removed.", - }, - - { - profile_id: 4, - name: "Password", - status: "pending", - operation_type: "remove", - detail: "", - }, - - // below case should never be returned - { - profile_id: 5, - name: "secret sauce", - status: "success", - operation_type: "remove", - detail: "", - }, - ]; - } - const titleData = normalizeEmptyValues( pick(host, [ "id", diff --git a/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx b/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx index 6be7ef707bd..02d7e4055cc 100644 --- a/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx +++ b/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx @@ -317,57 +317,6 @@ const HostDetailsPage = ({ } ); - // TODO: remove this mock data once API is returning real data - if (host) { - host.mdm.profiles = [ - { - profile_id: 42, - name: "Users", - status: "success", - operation_type: "install", - detail: "", - }, - { - profile_id: 1, - name: "Restrictions", - operation_type: "install", - status: "failed", - detail: "The “Restrictions” payload couldn’t be installed.", - }, - { - profile_id: 2, - name: "Password", - operation_type: "install", - status: "pending", - detail: "Removing enforcement", - }, - { - profile_id: 3, - name: "Restrictions", - operation_type: "remove", - status: "failed", - detail: "The profile could not be removed.", - }, - - { - profile_id: 4, - name: "Password", - status: "pending", - operation_type: "remove", - detail: "", - }, - - // below case should never be returned - { - profile_id: 5, - name: "secret sauce", - status: "success", - operation_type: "remove", - detail: "", - }, - ]; - } - const featuresConfig = host?.team_id ? teams?.find((t) => t.id === host.team_id)?.features : config?.features; From d03de47f486fb94e322e3d5f5f5a3e069e0147f6 Mon Sep 17 00:00:00 2001 From: Jacob Shandling Date: Tue, 21 Feb 2023 16:09:07 -0800 Subject: [PATCH 23/25] remove unnecessary isLoading props and EmptyTable todo --- .../details/DeviceUserPage/DeviceUserPage.tsx | 2 - .../HostDetailsPage/HostDetailsPage.tsx | 1 - .../MacSettingsModal/MacSettingsModal.tsx | 7 +-- .../MacSettingsTable/MacSettingsTable.tsx | 52 ++++++++----------- .../details/cards/HostSummary/HostSummary.tsx | 2 +- 5 files changed, 24 insertions(+), 40 deletions(-) diff --git a/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx b/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx index 753700daa04..d439e7e540e 100644 --- a/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx +++ b/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx @@ -383,9 +383,7 @@ const DeviceUserPage = ({ )} {showMacSettingsModal && ( )} diff --git a/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx b/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx index 02d7e4055cc..4273011c188 100644 --- a/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx +++ b/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx @@ -748,7 +748,6 @@ const HostDetailsPage = ({ {showMacSettingsModal && ( )} diff --git a/frontend/pages/hosts/details/MacSettingsModal/MacSettingsModal.tsx b/frontend/pages/hosts/details/MacSettingsModal/MacSettingsModal.tsx index ddc97fa8f62..2f0c18551d7 100644 --- a/frontend/pages/hosts/details/MacSettingsModal/MacSettingsModal.tsx +++ b/frontend/pages/hosts/details/MacSettingsModal/MacSettingsModal.tsx @@ -6,7 +6,6 @@ import MacSettingsTable from "./MacSettingsTable"; interface IMacSettingsModalProps { hostMacSettings?: IMacSettings; - isLoading: boolean; onClose: () => void; } @@ -14,16 +13,12 @@ const baseClass = "mac-settings-modal"; const MacSettingsModal = ({ hostMacSettings, - isLoading, onClose, }: IMacSettingsModalProps) => { return ( <> - +