From a6fb8eed0db77ab245770bcc5e6e495e2392490d Mon Sep 17 00:00:00 2001 From: RachelElysia Date: Mon, 1 Jul 2024 17:23:05 -0400 Subject: [PATCH 01/13] Fleet UI: Add iOS and iPadOS support, part 1 --- .../PlatformCompatibility.tsx | 9 ++- frontend/components/icons/Ipad.tsx | 38 ++++++++++ frontend/components/icons/Iphone.tsx | 45 +++++++++++ frontend/components/icons/index.ts | 4 + frontend/interfaces/mdm.ts | 2 +- frontend/interfaces/platform.ts | 5 ++ .../pages/DashboardPage/DashboardPage.tsx | 50 ++++++++++-- .../cards/HostsSummary/HostsSummary.tsx | 76 ++++++++++++++++--- .../SummaryTile/SummaryTile.tests.tsx | 8 +- .../HostsSummary/SummaryTile/SummaryTile.tsx | 30 ++------ .../HostsSummary/SummaryTile/_styles.scss | 18 ++--- .../cards/HostsSummary/_styles.scss | 17 +++++ .../LowDiskSpaceHosts/LowDiskSpaceHosts.tsx | 4 - .../cards/MissingHosts/MissingHosts.tsx | 4 - .../OperatingSystems/OperatingSystems.tsx | 6 +- .../OSSettings/OSSettings.tsx | 12 +-- .../cards/CustomSettings/CustomSettings.tsx | 28 ++++++- .../components/AddProfileGraphic.tsx | 11 +-- .../components/ProfileUploader/helpers.tsx | 4 +- .../hosts/ManageHostsPage/ManageHostsPage.tsx | 2 +- frontend/router/index.tsx | 2 + frontend/router/paths.ts | 2 + frontend/services/entities/hosts.ts | 6 +- .../services/entities/operating_systems.ts | 4 +- frontend/utilities/constants.tsx | 52 +++++++++---- 25 files changed, 324 insertions(+), 115 deletions(-) create mode 100644 frontend/components/icons/Ipad.tsx create mode 100644 frontend/components/icons/Iphone.tsx diff --git a/frontend/components/PlatformCompatibility/PlatformCompatibility.tsx b/frontend/components/PlatformCompatibility/PlatformCompatibility.tsx index 973647315a1e..a48f973d41ba 100644 --- a/frontend/components/PlatformCompatibility/PlatformCompatibility.tsx +++ b/frontend/components/PlatformCompatibility/PlatformCompatibility.tsx @@ -1,6 +1,6 @@ import React from "react"; -import { OsqueryPlatform } from "interfaces/platform"; +import { DashboardOsqueryPlatform, OsqueryPlatform } from "interfaces/platform"; import { PLATFORM_DISPLAY_NAMES } from "utilities/constants"; import TooltipWrapper from "components/TooltipWrapper"; @@ -24,7 +24,7 @@ const ERROR_NO_COMPATIBLE_TABLES = Error("no tables in query"); const formatPlatformsForDisplay = ( compatiblePlatforms: OsqueryPlatform[] -): OsqueryPlatform[] => { +): DashboardOsqueryPlatform[] => { return compatiblePlatforms.map((str) => PLATFORM_DISPLAY_NAMES[str] || str); }; @@ -83,8 +83,9 @@ const PlatformCompatibility = ({ - Estimated compatiblity based on
the tables used in the - query. + Estimated compatibility based on the
+ tables used in the query. Querying
+ iPhones & iPads is not supported. } > diff --git a/frontend/components/icons/Ipad.tsx b/frontend/components/icons/Ipad.tsx new file mode 100644 index 000000000000..f2ee6930f0fa --- /dev/null +++ b/frontend/components/icons/Ipad.tsx @@ -0,0 +1,38 @@ +import React from "react"; +import { COLORS, Colors } from "styles/var/colors"; +import { ICON_SIZES, IconSizes } from "styles/var/icon_sizes"; + +interface IIpadProps { + size: IconSizes; + color?: Colors; +} + +const Ipad = ({ size = "medium", color = "ui-fleet-black-75" }: IIpadProps) => { + return ( + + + + + ); +}; + +export default Ipad; diff --git a/frontend/components/icons/Iphone.tsx b/frontend/components/icons/Iphone.tsx new file mode 100644 index 000000000000..305c801df3a9 --- /dev/null +++ b/frontend/components/icons/Iphone.tsx @@ -0,0 +1,45 @@ +import React from "react"; +import { COLORS, Colors } from "styles/var/colors"; +import { ICON_SIZES, IconSizes } from "styles/var/icon_sizes"; + +interface IIphoneProps { + size: IconSizes; + color?: Colors; +} + +const Iphone = ({ + size = "medium", + color = "ui-fleet-black-75", +}: IIphoneProps) => { + return ( + + + + + + ); +}; + +export default Iphone; diff --git a/frontend/components/icons/index.ts b/frontend/components/icons/index.ts index 3b573cf9ac48..0d1e47adc47e 100644 --- a/frontend/components/icons/index.ts +++ b/frontend/components/icons/index.ts @@ -34,6 +34,8 @@ import M1 from "./M1"; import Centos from "./Centos"; import Ubuntu from "./Ubuntu"; import Chrome from "./Chrome"; +import Iphone from "./Iphone"; +import Ipad from "./Ipad"; // Status Icons import Success from "./Success"; @@ -114,6 +116,8 @@ export const ICON_MAP = { ubuntu: Ubuntu, chrome: Chrome, ChromeOS: Chrome, + ipad: Ipad, + iphone: Iphone, "premium-feature": PremiumFeature, profile: Profile, download: Download, diff --git a/frontend/interfaces/mdm.ts b/frontend/interfaces/mdm.ts index a911f0c9e78b..3a75fc825866 100644 --- a/frontend/interfaces/mdm.ts +++ b/frontend/interfaces/mdm.ts @@ -67,7 +67,7 @@ export interface IMdmSummaryResponse { mobile_device_management_solution: IMdmSummaryMdmSolution[] | null; } -export type ProfilePlatform = "darwin" | "windows"; +export type ProfilePlatform = "darwin" | "windows" | "ios" | "ipados"; export interface IProfileLabel { name: string; diff --git a/frontend/interfaces/platform.ts b/frontend/interfaces/platform.ts index ec2e11efd3a4..32d7114c5f9a 100644 --- a/frontend/interfaces/platform.ts +++ b/frontend/interfaces/platform.ts @@ -8,6 +8,8 @@ export type OsqueryPlatform = | "chrome" | "ChromeOS"; +export type DashboardOsqueryPlatform = OsqueryPlatform | "iOS" | "iPadOS"; + export type SupportedPlatform = "darwin" | "windows" | "linux" | "chrome"; export const SUPPORTED_PLATFORMS: SupportedPlatform[] = [ @@ -16,6 +18,7 @@ export const SUPPORTED_PLATFORMS: SupportedPlatform[] = [ "linux", "chrome", ]; + export type SelectedPlatform = SupportedPlatform | "all"; export type SelectedPlatformString = @@ -25,6 +28,8 @@ export type SelectedPlatformString = | `${SupportedPlatform},${SupportedPlatform},${SupportedPlatform}` | `${SupportedPlatform},${SupportedPlatform},${SupportedPlatform},${SupportedPlatform}`; +export type DashboardPlatform = SelectedPlatform | "ios" | "ipados"; + // TODO: revisit this approach pending resolution of https://github.com/fleetdm/fleet/issues/3555. export const MACADMINS_EXTENSION_TABLES: Record = { file_lines: ["darwin", "linux", "windows"], diff --git a/frontend/pages/DashboardPage/DashboardPage.tsx b/frontend/pages/DashboardPage/DashboardPage.tsx index 8a38f7a68757..91e9c50331e3 100644 --- a/frontend/pages/DashboardPage/DashboardPage.tsx +++ b/frontend/pages/DashboardPage/DashboardPage.tsx @@ -29,7 +29,7 @@ import { IMdmSummaryResponse, IMdmSummaryMdmSolution, } from "interfaces/mdm"; -import { SelectedPlatform } from "interfaces/platform"; +import { DashboardPlatform, SelectedPlatform } from "interfaces/platform"; import { ISoftwareResponse, ISoftwareCountResponse } from "interfaces/software"; import { API_ALL_TEAMS_ID, ITeam } from "interfaces/team"; import { IConfig } from "interfaces/config"; @@ -124,7 +124,7 @@ const DashboardPage = ({ router, location }: IDashboardProps): JSX.Element => { includeNoTeam: false, }); - const [selectedPlatform, setSelectedPlatform] = useState( + const [selectedPlatform, setSelectedPlatform] = useState( "all" ); const [ @@ -136,6 +136,8 @@ const DashboardPage = ({ router, location }: IDashboardProps): JSX.Element => { const [windowsCount, setWindowsCount] = useState(0); const [linuxCount, setLinuxCount] = useState(0); const [chromeCount, setChromeCount] = useState(0); + const [iosCount, setIosCount] = useState(0); + const [ipadosCount, setIpadosCount] = useState(0); const [missingCount, setMissingCount] = useState(0); const [lowDiskSpaceCount, setLowDiskSpaceCount] = useState(0); const [showActivityFeedTitle, setShowActivityFeedTitle] = useState(false); @@ -243,10 +245,20 @@ const DashboardPage = ({ router, location }: IDashboardProps): JSX.Element => { (platform: IHostSummaryPlatforms) => platform.platform === "chrome" ) || { platform: "chrome", hosts_count: 0 }; + const iphones = data.platforms?.find( + (platform: IHostSummaryPlatforms) => platform.platform === "ios" + ) || { platform: "ios", hosts_count: 0 }; + + const ipads = data.platforms?.find( + (platform: IHostSummaryPlatforms) => platform.platform === "ipados" + ) || { platform: "ipados", hosts_count: 0 }; + setMacCount(macHosts.hosts_count); setWindowsCount(windowsHosts.hosts_count); setLinuxCount(data.all_linux_count); setChromeCount(chromebooks.hosts_count); + setIosCount(iphones.hosts_count); + setIpadosCount(ipads.hosts_count); setShowHostsUI(true); }, } @@ -551,6 +563,8 @@ const DashboardPage = ({ router, location }: IDashboardProps): JSX.Element => { windowsCount={windowsCount} linuxCount={linuxCount} chromeCount={chromeCount} + iosCount={iosCount} + ipadosCount={ipadosCount} isLoadingHostsSummary={isHostSummaryFetching} builtInLabels={labels} showHostsUI={showHostsUI} @@ -756,6 +770,20 @@ const DashboardPage = ({ router, location }: IDashboardProps): JSX.Element => { ); + const iosLayout = () => ( + <> +
{OperatingSystemsCard}
+ {showMdmCard &&
{MDMCard}
} + + ); + + const ipadosLayout = () => ( + <> +
{OperatingSystemsCard}
+ {showMdmCard &&
{MDMCard}
} + + ); + const renderCards = () => { switch (selectedPlatform) { case "darwin": @@ -766,6 +794,10 @@ const DashboardPage = ({ router, location }: IDashboardProps): JSX.Element => { return linuxLayout(); case "chrome": return chromeLayout(); + case "ios": + return iosLayout(); + case "ipados": + return ipadosLayout(); default: return allLayout(); } @@ -870,12 +902,14 @@ const DashboardPage = ({ router, location }: IDashboardProps): JSX.Element => { )}
{HostsSummaryCard}
- {isPremiumTier && ( -
- {MissingHostsCard} - {LowDiskSpaceHostsCard} -
- )} + {isPremiumTier && + selectedPlatform !== "ios" && + selectedPlatform !== "ipados" && ( +
+ {MissingHostsCard} + {LowDiskSpaceHostsCard} +
+ )} {renderCards()} diff --git a/frontend/pages/DashboardPage/cards/HostsSummary/HostsSummary.tsx b/frontend/pages/DashboardPage/cards/HostsSummary/HostsSummary.tsx index e7115b0f1831..3d279172d280 100644 --- a/frontend/pages/DashboardPage/cards/HostsSummary/HostsSummary.tsx +++ b/frontend/pages/DashboardPage/cards/HostsSummary/HostsSummary.tsx @@ -3,7 +3,7 @@ import PATHS from "router/paths"; import { PLATFORM_NAME_TO_LABEL_NAME } from "utilities/constants"; import DataError from "components/DataError"; -import { SelectedPlatform } from "interfaces/platform"; +import { DashboardPlatform } from "interfaces/platform"; import { IHostSummary } from "interfaces/host_summary"; import SummaryTile from "./SummaryTile"; @@ -16,11 +16,13 @@ interface IHostSummaryProps { windowsCount: number; linuxCount: number; chromeCount: number; + iosCount: number; + ipadosCount: number; isLoadingHostsSummary: boolean; builtInLabels?: IHostSummary["builtin_labels"]; showHostsUI: boolean; errorHosts: boolean; - selectedPlatform?: SelectedPlatform; + selectedPlatform?: DashboardPlatform; } const HostsSummary = ({ @@ -29,6 +31,8 @@ const HostsSummary = ({ windowsCount, linuxCount, chromeCount, + iosCount, + ipadosCount, isLoadingHostsSummary, builtInLabels, showHostsUI, @@ -53,7 +57,6 @@ const HostsSummary = ({ return ( { + const iosLabelId = builtInLabels?.find( + (builtin) => builtin.name === PLATFORM_NAME_TO_LABEL_NAME.chrome // TODO: change to ios + )?.id; + + if (isLoadingHostsSummary || iosLabelId === undefined) { + return <>; + } + + return ( + + ); + }; + + const renderIpadosCount = (teamId?: number) => { + const ipadosLabelId = builtInLabels?.find( + (builtin) => builtin.name === PLATFORM_NAME_TO_LABEL_NAME.chrome // TODO: change to ipados + )?.id; + + if (isLoadingHostsSummary || ipadosLabelId === undefined) { + return <>; + } + + return ( + + ); + }; + const renderCounts = (teamId?: number) => { switch (selectedPlatform) { case "darwin": @@ -145,13 +191,23 @@ const HostsSummary = ({ return renderLinuxCount(teamId); case "chrome": return renderChromeCount(teamId); + case "ios": + return renderIosCount(teamId); + case "ipados": + return renderIpadosCount(teamId); default: return ( <> - {renderMacCount(teamId)} - {renderWindowsCount(teamId)} - {renderLinuxCount(teamId)} - {renderChromeCount(teamId)} +
+ {renderMacCount(teamId)} + {renderWindowsCount(teamId)} + {renderLinuxCount(teamId)} +
+
+ {renderChromeCount(teamId)} + {renderIosCount(teamId)} + {renderIpadosCount(teamId)} +
); } diff --git a/frontend/pages/DashboardPage/cards/HostsSummary/SummaryTile/SummaryTile.tests.tsx b/frontend/pages/DashboardPage/cards/HostsSummary/SummaryTile/SummaryTile.tests.tsx index bb2689d948c7..cbbae35b2814 100644 --- a/frontend/pages/DashboardPage/cards/HostsSummary/SummaryTile/SummaryTile.tests.tsx +++ b/frontend/pages/DashboardPage/cards/HostsSummary/SummaryTile/SummaryTile.tests.tsx @@ -1,7 +1,6 @@ import React from "react"; import { fireEvent, render, screen } from "@testing-library/react"; -import { renderWithSetup } from "test/test-utils"; import paths from "router/paths"; import SummaryTile from "./SummaryTile"; @@ -16,7 +15,6 @@ describe("SummaryTile - component", () => { showUI={false} // tested title="Windows hosts" iconName="windows" - circledIcon tooltip="Hosts on any Windows device" path={paths.MANAGE_HOSTS_LABEL(10)} /> @@ -35,7 +33,6 @@ describe("SummaryTile - component", () => { showUI title="Windows hosts" iconName="windows" - circledIcon tooltip="Hosts on any Windows device" path={paths.MANAGE_HOSTS_LABEL(10)} /> @@ -55,7 +52,6 @@ describe("SummaryTile - component", () => { showUI title="Windows hosts" // tested iconName="windows" // tested - circledIcon tooltip="Hosts on any Windows device" path={paths.MANAGE_HOSTS_LABEL(10)} /> @@ -78,7 +74,6 @@ describe("SummaryTile - component", () => { showUI title="Windows hosts" iconName="windows" - circledIcon path={paths.MANAGE_HOSTS_LABEL(10)} /> ); @@ -89,14 +84,13 @@ describe("SummaryTile - component", () => { }); it("renders tooltip on title hover", async () => { - const { user } = renderWithSetup( + render( diff --git a/frontend/pages/DashboardPage/cards/HostsSummary/SummaryTile/SummaryTile.tsx b/frontend/pages/DashboardPage/cards/HostsSummary/SummaryTile/SummaryTile.tsx index 55e5954ab3a7..697d542fb89e 100644 --- a/frontend/pages/DashboardPage/cards/HostsSummary/SummaryTile/SummaryTile.tsx +++ b/frontend/pages/DashboardPage/cards/HostsSummary/SummaryTile/SummaryTile.tsx @@ -4,7 +4,6 @@ import { kebabCase } from "lodash"; import Icon from "components/Icon"; import { IconNames } from "components/icons"; -import PremiumFeatureIconWithTooltip from "components/PremiumFeatureIconWithTooltip"; import classnames from "classnames"; import { Colors } from "styles/var/colors"; import TooltipWrapper from "components/TooltipWrapper"; @@ -15,12 +14,9 @@ interface ISummaryTileProps { showUI: boolean; title: string; iconName: IconNames; - circledIcon?: boolean; iconColor?: Colors; path: string; tooltip?: string; - isSandboxMode?: boolean; - sandboxPremiumOnlyIcon?: boolean; notSupported?: boolean; } @@ -32,12 +28,9 @@ const SummaryTile = ({ showUI, // false on first load only title, iconName, - circledIcon, iconColor, path, tooltip, - isSandboxMode = false, - sandboxPremiumOnlyIcon = false, notSupported = false, }: ISummaryTileProps): JSX.Element => { const numberWithCommas = (x: number): string => { @@ -54,15 +47,13 @@ const SummaryTile = ({ }); const tile = ( <> -
+
-
-
{notSupported ? (
Not supported @@ -76,18 +67,13 @@ const SummaryTile = ({ {numberWithCommas(count)}
)} -
- {tooltip ? ( - {title} - ) : ( - title - )} - {isSandboxMode && sandboxPremiumOnlyIcon && ( - - )} -
+
+
+ {tooltip ? ( + {title} + ) : ( + title + )}
); diff --git a/frontend/pages/DashboardPage/cards/HostsSummary/SummaryTile/_styles.scss b/frontend/pages/DashboardPage/cards/HostsSummary/SummaryTile/_styles.scss index 6ab2f665963e..e5cef444a638 100644 --- a/frontend/pages/DashboardPage/cards/HostsSummary/SummaryTile/_styles.scss +++ b/frontend/pages/DashboardPage/cards/HostsSummary/SummaryTile/_styles.scss @@ -12,6 +12,7 @@ &__tile { display: flex; + flex-direction: column; align-items: center; gap: px-to-rem(12); text-align: left; @@ -27,20 +28,11 @@ white-space: nowrap; } - &__circled-icon { + &__icon-count { display: flex; - justify-content: center; + flex-direction: row; align-items: center; - background-color: $core-vibrant-blue; - width: px-to-rem(48); - height: px-to-rem(48); - border-radius: 100%; - background: $ui-vibrant-blue-10; - - .icon { - margin-left: 0 !important; - margin-right: 0; - } + gap: 12px; } &__count { @@ -57,7 +49,7 @@ } &__description { - white-space: nowrap; + color: $ui-fleet-black-75; .component__tooltip-wrapper__element { font-size: $x-small; diff --git a/frontend/pages/DashboardPage/cards/HostsSummary/_styles.scss b/frontend/pages/DashboardPage/cards/HostsSummary/_styles.scss index 896e7e3131ba..8c3a729a44ac 100644 --- a/frontend/pages/DashboardPage/cards/HostsSummary/_styles.scss +++ b/frontend/pages/DashboardPage/cards/HostsSummary/_styles.scss @@ -2,8 +2,25 @@ margin-top: $pad-large; width: 100%; display: flex; + flex-direction: column; justify-content: space-around; font-size: $x-small; + gap: $pad-medium; + + &__row { + display: flex; + justify-content: space-around; + } + + // Create a single row + @media (min-width: $break-md) { + flex-direction: row; + gap: initial; + + &__row { + flex: 1 100%; + } + } &__tile { flex-grow: 1; diff --git a/frontend/pages/DashboardPage/cards/LowDiskSpaceHosts/LowDiskSpaceHosts.tsx b/frontend/pages/DashboardPage/cards/LowDiskSpaceHosts/LowDiskSpaceHosts.tsx index dadd27be467e..1ac6ebe4cd0e 100644 --- a/frontend/pages/DashboardPage/cards/LowDiskSpaceHosts/LowDiskSpaceHosts.tsx +++ b/frontend/pages/DashboardPage/cards/LowDiskSpaceHosts/LowDiskSpaceHosts.tsx @@ -14,7 +14,6 @@ interface IHostSummaryProps { showHostsUI: boolean; selectedPlatformLabelId?: number; currentTeamId?: number; - isSandboxMode?: boolean; notSupported: boolean; } @@ -25,7 +24,6 @@ const LowDiskSpaceHosts = ({ showHostsUI, selectedPlatformLabelId, currentTeamId, - isSandboxMode = false, notSupported = false, // default to supporting this feature }: IHostSummaryProps): JSX.Element => { // build the manage hosts URL filtered by low disk space only @@ -54,8 +52,6 @@ const LowDiskSpaceHosts = ({ title="Low disk space hosts" tooltip={tooltipText} path={path} - isSandboxMode={isSandboxMode} - sandboxPremiumOnlyIcon notSupported={notSupported} />
diff --git a/frontend/pages/DashboardPage/cards/MissingHosts/MissingHosts.tsx b/frontend/pages/DashboardPage/cards/MissingHosts/MissingHosts.tsx index 956b8a14fc48..2bb0e4201d1e 100644 --- a/frontend/pages/DashboardPage/cards/MissingHosts/MissingHosts.tsx +++ b/frontend/pages/DashboardPage/cards/MissingHosts/MissingHosts.tsx @@ -13,7 +13,6 @@ interface IHostSummaryProps { showHostsUI: boolean; selectedPlatformLabelId?: number; currentTeamId?: number; - isSandboxMode?: boolean; } const MissingHosts = ({ @@ -22,7 +21,6 @@ const MissingHosts = ({ showHostsUI, selectedPlatformLabelId, currentTeamId, - isSandboxMode = false, }: IHostSummaryProps): JSX.Element => { // build the manage hosts URL filtered by missing and platform const queryParams = { @@ -45,8 +43,6 @@ const MissingHosts = ({ title="Missing hosts" tooltip="Hosts that have not been online in 30 days or more." path={path} - isSandboxMode={isSandboxMode} - sandboxPremiumOnlyIcon /> ); diff --git a/frontend/pages/DashboardPage/cards/OperatingSystems/OperatingSystems.tsx b/frontend/pages/DashboardPage/cards/OperatingSystems/OperatingSystems.tsx index 86dbf573eb45..afe3999a496d 100644 --- a/frontend/pages/DashboardPage/cards/OperatingSystems/OperatingSystems.tsx +++ b/frontend/pages/DashboardPage/cards/OperatingSystems/OperatingSystems.tsx @@ -5,7 +5,7 @@ import { OS_END_OF_LIFE_LINK_BY_PLATFORM, OS_VENDOR_BY_PLATFORM, } from "interfaces/operating_system"; -import { SelectedPlatform } from "interfaces/platform"; +import { DashboardPlatform } from "interfaces/platform"; import { getOSVersions, IGetOSVersionsQueryKey, @@ -26,7 +26,7 @@ import generateTableHeaders from "./OperatingSystemsTableConfig"; interface IOperatingSystemsCardProps { currentTeamId: number | undefined; - selectedPlatform: SelectedPlatform; + selectedPlatform: DashboardPlatform; showTitle: boolean; /** controls the displaying of description text under the title. Defaults to `true` */ showDescription?: boolean; @@ -42,7 +42,7 @@ const DEFAULT_SORT_HEADER = "hosts_count"; const PAGE_SIZE = 8; const baseClass = "operating-systems"; -const EmptyOperatingSystems = (platform: SelectedPlatform): JSX.Element => ( +const EmptyOperatingSystems = (platform: DashboardPlatform): JSX.Element => ( ; - } + // if ( + // !config?.mdm.enabled_and_configured && + // !config?.mdm.windows_enabled_and_configured + // ) { + // return ; + // } const DEFAULT_SETTINGS_SECTION = OS_SETTINGS_NAV_ITEMS[0]; diff --git a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/CustomSettings.tsx b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/CustomSettings.tsx index 89887e9b838f..820a32dca9ed 100644 --- a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/CustomSettings.tsx +++ b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/CustomSettings.tsx @@ -57,8 +57,28 @@ const CustomSettings = ({ const selectedProfile = useRef(null); + const profilesData: IMdmProfilesResponse = { + profiles: [ + { + profile_uuid: "12345", + team_id: 1, + name: "Profile name", + platform: "ios", + identifier: "1234", // null for windows profiles + created_at: "2024-03-07T14:40:00Z", + updated_at: "2024-03-07T14:40:00Z", + checksum: "1234", // null for windows profiles + labels: [{ name: "string", broken: false }], + }, + ], + meta: { + has_next_results: true, + has_previous_results: false, + }, + }; + const { - data: profilesData, + data: profilesData2, isLoading: isLoadingProfiles, isError: isErrorProfiles, refetch: refetchProfiles, @@ -131,9 +151,9 @@ const CustomSettings = ({ return ; } - if (isErrorProfiles) { - return ; - } + // if (isErrorProfiles) { + // return ; + // } if (!profiles?.length) { return null; diff --git a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileUploader/components/AddProfileGraphic.tsx b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileUploader/components/AddProfileGraphic.tsx index c75193dcb6cd..027bf94f46b6 100644 --- a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileUploader/components/AddProfileGraphic.tsx +++ b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileUploader/components/AddProfileGraphic.tsx @@ -2,9 +2,6 @@ import React from "react"; import Graphic from "components/Graphic"; -const ALLOWED_FILE_TYPES_MESSAGE = - "Configuration profile (.mobileconfig and .json for macOS or .xml for Windows)"; - const ProfileGraphic = ({ baseClass, showMessage, @@ -14,13 +11,17 @@ const ProfileGraphic = ({ }) => (
{showMessage && ( - {ALLOWED_FILE_TYPES_MESSAGE} + Upload configuration profile +
+ .mobileconfig and .json for macOS, iOS, and iPadOS. +
+ .xml for Windows.
)}
diff --git a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileUploader/helpers.tsx b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileUploader/helpers.tsx index 62727c9b2f84..4132a49a042a 100644 --- a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileUploader/helpers.tsx +++ b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileUploader/helpers.tsx @@ -13,10 +13,10 @@ export const parseFile = async (file: File): Promise<[string, string]> => { return [name, "Windows"]; } case "mobileconfig": { - return [name, "macOS"]; + return [name, "macOS, iOS, iPadOS"]; } case "json": { - return [name, "macOS"]; + return [name, "macOS, iOS, iPadOS"]; } default: { throw new Error(`Invalid file type: ${ext}`); diff --git a/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx b/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx index 0c794a7cea83..e24d185cd1ac 100644 --- a/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx +++ b/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx @@ -54,7 +54,7 @@ import { isValidSoftwareInstallStatus, SoftwareInstallStatus, } from "interfaces/software"; -import { API_NO_TEAM_ID, ITeam } from "interfaces/team"; +import { ITeam } from "interfaces/team"; import { IEmptyTableProps } from "interfaces/empty_table"; import { DiskEncryptionStatus, diff --git a/frontend/router/index.tsx b/frontend/router/index.tsx index ae9931afb6e5..2d3c83a8d833 100644 --- a/frontend/router/index.tsx +++ b/frontend/router/index.tsx @@ -133,6 +133,8 @@ const routes = ( + + diff --git a/frontend/router/paths.ts b/frontend/router/paths.ts index ae2b39b2fd67..0aedc5ee3029 100644 --- a/frontend/router/paths.ts +++ b/frontend/router/paths.ts @@ -23,6 +23,8 @@ export default { DASHBOARD_MAC: `${URL_PREFIX}/dashboard/mac`, DASHBOARD_WINDOWS: `${URL_PREFIX}/dashboard/windows`, DASHBOARD_CHROME: `${URL_PREFIX}/dashboard/chrome`, + DASHBOARD_IOS: `${URL_PREFIX}/dashboard/ios`, + DASHBOARD_IPADOS: `${URL_PREFIX}/dashboard/ipados`, // Admin pages ADMIN_SETTINGS: `${URL_PREFIX}/settings`, diff --git a/frontend/services/entities/hosts.ts b/frontend/services/entities/hosts.ts index 259d9ae9a217..45477726a13b 100644 --- a/frontend/services/entities/hosts.ts +++ b/frontend/services/entities/hosts.ts @@ -9,7 +9,7 @@ import { reconcileMutuallyExclusiveHostParams, reconcileMutuallyInclusiveHostParams, } from "utilities/url"; -import { SelectedPlatform } from "interfaces/platform"; +import { DashboardPlatform, SelectedPlatform } from "interfaces/platform"; import { IHostSoftware, ISoftware, @@ -206,7 +206,7 @@ const getSortParams = (sortOptions?: ISortOption[]) => { }; }; -const createMdmParams = (platform?: SelectedPlatform, teamId?: number) => { +const createMdmParams = (platform?: DashboardPlatform, teamId?: number) => { if (platform === "all") { return buildQueryStringFromParams({ team_id: teamId }); } @@ -535,7 +535,7 @@ export default { return sendRequest("GET", HOST_MDM(id)); }, - getMdmSummary: (platform?: SelectedPlatform, teamId?: number) => { + getMdmSummary: (platform?: DashboardPlatform, teamId?: number) => { const { MDM_SUMMARY } = endpoints; if (!platform || platform === "linux") { diff --git a/frontend/services/entities/operating_systems.ts b/frontend/services/entities/operating_systems.ts index 29ba06b14103..3f5bffd74db7 100644 --- a/frontend/services/entities/operating_systems.ts +++ b/frontend/services/entities/operating_systems.ts @@ -2,7 +2,7 @@ import sendRequest from "services"; import endpoints from "utilities/endpoints"; import { IOperatingSystemVersion } from "interfaces/operating_system"; -import { OsqueryPlatform } from "interfaces/platform"; +import { DashboardPlatform } from "interfaces/platform"; import { buildQueryStringFromParams } from "utilities/url"; import { API_NO_TEAM_ID } from "interfaces/team"; @@ -14,7 +14,7 @@ export const OS_VERSIONS_API_SUPPORTED_PLATFORMS = [ ]; export interface IGetOSVersionsQueryParams { - platform?: OsqueryPlatform; + platform?: DashboardPlatform; teamId?: number; os_name?: string; os_version?: string; diff --git a/frontend/utilities/constants.tsx b/frontend/utilities/constants.tsx index f8c484e9b980..05ae2bef61a4 100644 --- a/frontend/utilities/constants.tsx +++ b/frontend/utilities/constants.tsx @@ -1,5 +1,9 @@ import URL_PREFIX from "router/url_prefix"; -import { OsqueryPlatform } from "interfaces/platform"; +import { + DashboardOsqueryPlatform, + DashboardPlatform, + OsqueryPlatform, +} from "interfaces/platform"; import paths from "router/paths"; import { ISchedulableQuery } from "interfaces/schedulable_query"; import React from "react"; @@ -200,6 +204,8 @@ const PLATFORM_LABEL_NAMES_FROM_API = [ "Red Hat Linux", "Ubuntu Linux", "chrome", + "ios", + "ipados", ] as const; type PlatformLabelNameFromAPI = typeof PLATFORM_LABEL_NAMES_FROM_API[number]; @@ -210,7 +216,10 @@ export const isPlatformLabelNameFromAPI = ( return PLATFORM_LABEL_NAMES_FROM_API.includes(s as PlatformLabelNameFromAPI); }; -export const PLATFORM_DISPLAY_NAMES: Record = { +export const PLATFORM_DISPLAY_NAMES: Record< + string, + DashboardOsqueryPlatform +> = { darwin: "macOS", macOS: "macOS", windows: "Windows", @@ -219,6 +228,8 @@ export const PLATFORM_DISPLAY_NAMES: Record = { Linux: "Linux", chrome: "ChromeOS", ChromeOS: "ChromeOS", + ios: "iOS", + ipados: "iPadOS", } as const; // as returned by the TARGETS API; based on display_text @@ -234,17 +245,10 @@ export const PLATFORM_LABEL_DISPLAY_NAMES: Record< "Red Hat Linux": "Red Hat Linux", "Ubuntu Linux": "Ubuntu Linux", chrome: "ChromeOS", + ios: "iOS", + ipados: "iPadOS", } as const; -export const PLATFORM_LABEL_DISPLAY_ORDER = [ - "macOS", - "All Linux", - "CentOS Linux", - "Red Hat Linux", - "Ubuntu Linux", - "MS Windows", -] as const; - export const PLATFORM_LABEL_DISPLAY_TYPES: Record< PlatformLabelNameFromAPI, string @@ -257,12 +261,14 @@ export const PLATFORM_LABEL_DISPLAY_TYPES: Record< "Red Hat Linux": "platform", "Ubuntu Linux": "platform", chrome: "platform", + ios: "platform", + ipados: "platform", } as const; export const PLATFORM_TYPE_ICONS: Record< Extract< PlatformLabelNameFromAPI, - "All Linux" | "macOS" | "MS Windows" | "chrome" + "All Linux" | "macOS" | "MS Windows" | "chrome" | "ios" | "ipados" >, IconNames > = { @@ -270,20 +276,30 @@ export const PLATFORM_TYPE_ICONS: Record< macOS: "darwin", "MS Windows": "windows", chrome: "chrome", + ios: "iphone", + ipados: "ipad", } as const; export const hasPlatformTypeIcon = ( s: string ): s is Extract< PlatformLabelNameFromAPI, - "All Linux" | "macOS" | "MS Windows" | "chrome" + "All Linux" | "macOS" | "MS Windows" | "chrome" | "ios" | "ipados" > => { return !!PLATFORM_TYPE_ICONS[s as keyof typeof PLATFORM_TYPE_ICONS]; }; interface IPlatformDropdownOptions { - label: "All" | "Windows" | "Linux" | "macOS" | "ChromeOS"; - value: "all" | "windows" | "linux" | "darwin" | "chrome" | ""; + label: "All" | "Windows" | "Linux" | "macOS" | "ChromeOS" | "iOS" | "iPadOS"; + value: + | "all" + | "windows" + | "linux" + | "darwin" + | "chrome" + | "ios" + | "ipados" + | ""; path?: string; } export const PLATFORM_DROPDOWN_OPTIONS: IPlatformDropdownOptions[] = [ @@ -292,9 +308,11 @@ export const PLATFORM_DROPDOWN_OPTIONS: IPlatformDropdownOptions[] = [ { label: "Windows", value: "windows", path: paths.DASHBOARD_WINDOWS }, { label: "Linux", value: "linux", path: paths.DASHBOARD_LINUX }, { label: "ChromeOS", value: "chrome", path: paths.DASHBOARD_CHROME }, + { label: "iOS", value: "ios", path: paths.DASHBOARD_IOS }, + { label: "iPadOS", value: "ipados", path: paths.DASHBOARD_IPADOS }, ]; -// Schedules does not support ChromeOS +// Scheduling queries do not support ChromeOS, iOS, or iPadOS export const SCHEDULE_PLATFORM_DROPDOWN_OPTIONS: IPlatformDropdownOptions[] = [ { label: "All", value: "" }, // API empty string runs on all platforms { label: "macOS", value: "darwin" }, @@ -309,6 +327,8 @@ export const PLATFORM_NAME_TO_LABEL_NAME = { windows: "MS Windows", linux: "All Linux", chrome: "chrome", + ios: "iPhones", + ipados: "iPads", }; export const HOSTS_SEARCH_BOX_PLACEHOLDER = From bef66df838f8b492b7514957c0617702aa8a19f0 Mon Sep 17 00:00:00 2001 From: RachelElysia Date: Tue, 2 Jul 2024 10:11:35 -0400 Subject: [PATCH 02/13] Custom settings updates, including styling --- frontend/components/buttons/Button/Button.tsx | 2 +- .../cards/CustomSettings/_styles.scss | 77 +++++++++++++++++++ .../ProfileListHeading/_styles.scss | 7 ++ .../ProfileListItem/ProfileListItem.tsx | 4 +- .../components/ProfileListItem/_styles.scss | 1 + .../components/UploadList/_styles.scss | 8 ++ 6 files changed, 96 insertions(+), 3 deletions(-) diff --git a/frontend/components/buttons/Button/Button.tsx b/frontend/components/buttons/Button/Button.tsx index 03749d419b2a..3e05fda3fecf 100644 --- a/frontend/components/buttons/Button/Button.tsx +++ b/frontend/components/buttons/Button/Button.tsx @@ -13,7 +13,7 @@ export type ButtonVariant = | "warning" | "link" | "label" - | "text-link" + | "text-link" // Underlines on hover | "text-icon" | "icon" // Buttons without text | "small-icon" // Buttons without text diff --git a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/_styles.scss b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/_styles.scss index 4e56c438b771..cb9b50f1f0ff 100644 --- a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/_styles.scss +++ b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/_styles.scss @@ -100,5 +100,82 @@ align-items: center; gap: $pad-small; } + + &__profile-graphic--message { + text-align: center; + } + + &__button-wrap { + display: flex; + justify-content: flex-end; + padding-top: $pad-medium; + } + + &__target { + margin: $pad-large 0 $pad-small 0; + } + + &__description { + margin: $pad-medium 0; + } + + &__no-labels { + display: flex; + height: 187px; + flex-direction: column; + align-items: center; + gap: $pad-small; + justify-content: center; + + span { + color: $ui-fleet-black-75; + } + } + + &__checkboxes { + display: flex; + max-height: 187px; + flex-direction: column; + border-radius: $border-radius; + border: 1px solid $ui-fleet-black-10; + overflow-y: auto; + + .loading-spinner { + margin: 69.5px auto; + } + } + + &__label { + width: 100%; + padding: $pad-small $pad-medium; + box-sizing: border-box; + display: flex; + align-items: center; + + &:not(:last-child) { + border-bottom: 1px solid $ui-fleet-black-10; + } + + .form-field--checkbox { + width: auto; + } + } + + &__label-name { + padding-left: $pad-large; + } + + .fleet-checkbox { + height: 20px; + display: flex; + align-items: center; + + &__label { + width: 490px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + } } } diff --git a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileListHeading/_styles.scss b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileListHeading/_styles.scss index 3a8e68c913ad..be519109dfb4 100644 --- a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileListHeading/_styles.scss +++ b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileListHeading/_styles.scss @@ -14,4 +14,11 @@ align-items: center; gap: $pad-small; } + + &__actions-heading { + margin: -$pad-medium 0; // Remove vertical padding of button increasing container height + } + &__add-button { + vertical-align: middle; + } } diff --git a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileListItem/ProfileListItem.tsx b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileListItem/ProfileListItem.tsx index ea83ddfd5a66..bdc046ed7dea 100644 --- a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileListItem/ProfileListItem.tsx +++ b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileListItem/ProfileListItem.tsx @@ -39,7 +39,7 @@ const ProfileDetails = ({ }: IProfileDetailsProps) => { const getPlatformName = () => { if (platform === "windows") return "Windows"; - return isDDM ? "macOS (declaration)" : "macOS"; + return isDDM ? "macOS (declaration)" : "macOS, iOS, iPadOS"; // TODO: Confirm this is correct logic and copy text }; return ( @@ -95,7 +95,7 @@ const ProfileListItem = ({ const onClickDownload = async () => { const fileContent = await createFileContent(profile); const formatDate = format(new Date(), "yyyy-MM-dd"); - const extension = createProfileExtension(profile); + const extension = createProfileExtension(profile); // TODO: How does createProfileExtension work with iOS/iPadOS profiles const filename = `${formatDate}_${name}.${extension}`; const file = new File([fileContent], filename); FileSaver.saveAs(file); diff --git a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileListItem/_styles.scss b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileListItem/_styles.scss index 550e2a9daedc..95436510d152 100644 --- a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileListItem/_styles.scss +++ b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileListItem/_styles.scss @@ -3,6 +3,7 @@ display: flex; flex-direction: row; gap: $pad-xsmall; + color: $ui-fleet-black-75; } &__list-item-details { diff --git a/frontend/pages/ManageControlsPage/components/UploadList/_styles.scss b/frontend/pages/ManageControlsPage/components/UploadList/_styles.scss index 0f5017b10260..6a7cb20cd9ed 100644 --- a/frontend/pages/ManageControlsPage/components/UploadList/_styles.scss +++ b/frontend/pages/ManageControlsPage/components/UploadList/_styles.scss @@ -1,8 +1,12 @@ .upload-list { + border: 1px solid $ui-fleet-black-10; + border-radius: 4px; + &__header { padding: $pad-medium $pad-large; font-size: $x-small; border-bottom: 1px solid $ui-fleet-black-10; + background-color: $ui-off-white; } &__list { @@ -14,5 +18,9 @@ &__list-item { padding: $pad-medium $pad-large; border-bottom: 1px solid $ui-fleet-black-10; + + &:last-child { + border-bottom: initial; + } } } From 78e18403a80fe311d7df0f3070a64e97098abb9b Mon Sep 17 00:00:00 2001 From: RachelElysia Date: Tue, 2 Jul 2024 11:17:12 -0400 Subject: [PATCH 03/13] Everything but add host / manage host and testing --- .../components/icons/{Iphone.tsx => iOS.tsx} | 9 ++--- .../components/icons/{Ipad.tsx => iPadOS.tsx} | 9 +++-- frontend/components/icons/index.ts | 8 ++-- .../cards/HostsSummary/HostsSummary.tsx | 4 +- .../cards/OperatingSystems/_styles.scss | 3 +- .../OSSettings/OSSettings.tsx | 2 + .../ProfileStatusAggregateOptions.ts | 4 +- .../OSUpdates/OSUpdates.tsx | 26 +++++++++---- .../CurrentVersionSection.tsx | 7 +++- .../EmptyTargetForm/EmptyTargetForm.tsx | 39 +++++++++++++++++++ .../components/EmptyTargetForm/index.ts | 1 + .../OSVersionTable/OSVersionTable.tsx | 2 +- .../components/PlatformTabs/PlatformTabs.tsx | 23 ++++++++++- .../TargetSection/TargetSection.tsx | 3 +- .../hosts/ManageHostsPage/ManageHostsPage.tsx | 1 - .../components/FilterPill/FilterPill.tsx | 12 ------ .../HostsFilterBlock/HostsFilterBlock.tsx | 5 --- .../details/cards/HostSummary/HostSummary.tsx | 5 ++- .../OSSettingsIndicator.tsx | 4 +- frontend/utilities/constants.tsx | 24 ++++++------ 20 files changed, 125 insertions(+), 66 deletions(-) rename frontend/components/icons/{Iphone.tsx => iOS.tsx} (91%) rename frontend/components/icons/{Ipad.tsx => iPadOS.tsx} (91%) create mode 100644 frontend/pages/ManageControlsPage/OSUpdates/components/EmptyTargetForm/EmptyTargetForm.tsx create mode 100644 frontend/pages/ManageControlsPage/OSUpdates/components/EmptyTargetForm/index.ts diff --git a/frontend/components/icons/Iphone.tsx b/frontend/components/icons/iOS.tsx similarity index 91% rename from frontend/components/icons/Iphone.tsx rename to frontend/components/icons/iOS.tsx index 305c801df3a9..a6fa41354a02 100644 --- a/frontend/components/icons/Iphone.tsx +++ b/frontend/components/icons/iOS.tsx @@ -2,15 +2,12 @@ import React from "react"; import { COLORS, Colors } from "styles/var/colors"; import { ICON_SIZES, IconSizes } from "styles/var/icon_sizes"; -interface IIphoneProps { +interface IiOSProps { size: IconSizes; color?: Colors; } -const Iphone = ({ - size = "medium", - color = "ui-fleet-black-75", -}: IIphoneProps) => { +const iOS = ({ size = "medium", color = "ui-fleet-black-75" }: IiOSProps) => { return ( { +const iPadOS = ({ + size = "medium", + color = "ui-fleet-black-75", +}: IiPadOSProps) => { return ( { ); }; -export default Ipad; +export default iPadOS; diff --git a/frontend/components/icons/index.ts b/frontend/components/icons/index.ts index 0d1e47adc47e..ef7cf59b50c3 100644 --- a/frontend/components/icons/index.ts +++ b/frontend/components/icons/index.ts @@ -34,8 +34,8 @@ import M1 from "./M1"; import Centos from "./Centos"; import Ubuntu from "./Ubuntu"; import Chrome from "./Chrome"; -import Iphone from "./Iphone"; -import Ipad from "./Ipad"; +import iPadOS from "./iPadOS"; +import iOS from "./iOS"; // Status Icons import Success from "./Success"; @@ -116,8 +116,8 @@ export const ICON_MAP = { ubuntu: Ubuntu, chrome: Chrome, ChromeOS: Chrome, - ipad: Ipad, - iphone: Iphone, + iPadOS, + iOS, "premium-feature": PremiumFeature, profile: Profile, download: Download, diff --git a/frontend/pages/DashboardPage/cards/HostsSummary/HostsSummary.tsx b/frontend/pages/DashboardPage/cards/HostsSummary/HostsSummary.tsx index 3d279172d280..6cd39c361e58 100644 --- a/frontend/pages/DashboardPage/cards/HostsSummary/HostsSummary.tsx +++ b/frontend/pages/DashboardPage/cards/HostsSummary/HostsSummary.tsx @@ -146,7 +146,7 @@ const HostsSummary = ({ return ( ; // } + // END TODO const DEFAULT_SETTINGS_SECTION = OS_SETTINGS_NAV_ITEMS[0]; diff --git a/frontend/pages/ManageControlsPage/OSSettings/ProfileStatusAggregate/ProfileStatusAggregateOptions.ts b/frontend/pages/ManageControlsPage/OSSettings/ProfileStatusAggregate/ProfileStatusAggregateOptions.ts index c2a917fb59ff..22c941ff0bad 100644 --- a/frontend/pages/ManageControlsPage/OSSettings/ProfileStatusAggregate/ProfileStatusAggregateOptions.ts +++ b/frontend/pages/ManageControlsPage/OSSettings/ProfileStatusAggregate/ProfileStatusAggregateOptions.ts @@ -13,9 +13,7 @@ const AGGREGATE_STATUS_DISPLAY_OPTIONS: IAggregateDisplayOption[] = [ value: "verified", text: "Verified", iconName: "success", - tooltipText: - "These hosts applied all OS settings. Fleet verified with osquery. " + - "Declaration profiles are verified with DDM.", + tooltipText: "These hosts applied all OS settings. Fleet verified.", }, { value: "verifying", diff --git a/frontend/pages/ManageControlsPage/OSUpdates/OSUpdates.tsx b/frontend/pages/ManageControlsPage/OSUpdates/OSUpdates.tsx index 4e6d7ae31199..59d4afa5eafc 100644 --- a/frontend/pages/ManageControlsPage/OSUpdates/OSUpdates.tsx +++ b/frontend/pages/ManageControlsPage/OSUpdates/OSUpdates.tsx @@ -18,7 +18,11 @@ import TurnOnMdmMessage from "../components/TurnOnMdmMessage/TurnOnMdmMessage"; import CurrentVersionSection from "./components/CurrentVersionSection"; import TargetSection from "./components/TargetSection"; -export type OSUpdatesSupportedPlatform = "darwin" | "windows"; +export type OSUpdatesSupportedPlatform = + | "darwin" + | "windows" + | "iOS" + | "iPadOS"; const baseClass = "os-updates"; @@ -89,17 +93,25 @@ const OSUpdates = ({ router, teamIdForApi }: IOSUpdates) => { // FIXME: Handle error states for app config and team config (need specifications for this). // mdm is not enabled for mac or windows. - if ( - !config?.mdm.enabled_and_configured && - !config?.mdm.windows_enabled_and_configured - ) { - return ; - } + // TODO: Reinstate when ready + // if ( + // !config?.mdm.enabled_and_configured && + // !config?.mdm.windows_enabled_and_configured + // ) { + // return ; + // } + // END TODO // If the user has not selected a platform yet, we default to the platform that // is enabled and configured. const selectedPlatform = selectedPlatformTab || getSelectedPlatform(config); + // TODO: Remove when ready + if (!config) { + return null; + } + // END TODO + return (

diff --git a/frontend/pages/ManageControlsPage/OSUpdates/components/CurrentVersionSection/CurrentVersionSection.tsx b/frontend/pages/ManageControlsPage/OSUpdates/components/CurrentVersionSection/CurrentVersionSection.tsx index f0c62ddc09bb..98ce7349ab73 100644 --- a/frontend/pages/ManageControlsPage/OSUpdates/components/CurrentVersionSection/CurrentVersionSection.tsx +++ b/frontend/pages/ManageControlsPage/OSUpdates/components/CurrentVersionSection/CurrentVersionSection.tsx @@ -79,10 +79,13 @@ const CurrentVersionSection = ({ return ; } - // We only want to show windows and mac versions atm. + // We only want to show windows mac, ios, ipados versions atm. const filteredOSVersionData = data.os_versions.filter((osVersion) => { return ( - osVersion.platform === "windows" || osVersion.platform === "darwin" + osVersion.platform === "windows" || + osVersion.platform === "darwin" || + osVersion.platform === "ios" || + osVersion.platform === "ipados" ); }) as IFilteredOperatingSystemVersion[]; diff --git a/frontend/pages/ManageControlsPage/OSUpdates/components/EmptyTargetForm/EmptyTargetForm.tsx b/frontend/pages/ManageControlsPage/OSUpdates/components/EmptyTargetForm/EmptyTargetForm.tsx new file mode 100644 index 000000000000..2db6c843c256 --- /dev/null +++ b/frontend/pages/ManageControlsPage/OSUpdates/components/EmptyTargetForm/EmptyTargetForm.tsx @@ -0,0 +1,39 @@ +import React, { useContext, useState } from "react"; +import { isEmpty } from "lodash"; + +import { APP_CONTEXT_NO_TEAM_ID } from "interfaces/team"; +import { NotificationContext } from "context/notification"; +import configAPI from "services/entities/config"; +import teamsAPI from "services/entities/teams"; + +// @ts-ignore +import InputField from "components/forms/fields/InputField"; +import Button from "components/buttons/Button"; +import validatePresence from "components/forms/validators/validate_presence"; +import CustomLink from "components/CustomLink"; + +const baseClass = "empty-target-form"; + +interface IEmptyTargetFormProps { + targetPlatform: string; +} + +const EmptyTargetForm = ({ targetPlatform }: IEmptyTargetFormProps) => { + return ( + <> +

+ {targetPlatform} updates are coming soon. +

+

+ Need to remotely encourage installation of {targetPlatform} updates?{" "} + +

+ + ); +}; + +export default EmptyTargetForm; diff --git a/frontend/pages/ManageControlsPage/OSUpdates/components/EmptyTargetForm/index.ts b/frontend/pages/ManageControlsPage/OSUpdates/components/EmptyTargetForm/index.ts new file mode 100644 index 000000000000..284c5dbd3a0a --- /dev/null +++ b/frontend/pages/ManageControlsPage/OSUpdates/components/EmptyTargetForm/index.ts @@ -0,0 +1 @@ +export { default } from "./EmptyTargetForm"; diff --git a/frontend/pages/ManageControlsPage/OSUpdates/components/OSVersionTable/OSVersionTable.tsx b/frontend/pages/ManageControlsPage/OSUpdates/components/OSVersionTable/OSVersionTable.tsx index a0b3ef06b465..86322f80604d 100644 --- a/frontend/pages/ManageControlsPage/OSUpdates/components/OSVersionTable/OSVersionTable.tsx +++ b/frontend/pages/ManageControlsPage/OSUpdates/components/OSVersionTable/OSVersionTable.tsx @@ -39,7 +39,7 @@ const OSVersionTable = ({ defaultSortDirection={DEFAULT_SORT_DIRECTION} disableTableHeader disableCount - disablePagination + pageSize={8} />
); diff --git a/frontend/pages/ManageControlsPage/OSUpdates/components/PlatformTabs/PlatformTabs.tsx b/frontend/pages/ManageControlsPage/OSUpdates/components/PlatformTabs/PlatformTabs.tsx index af5432a941f7..78e784849e6a 100644 --- a/frontend/pages/ManageControlsPage/OSUpdates/components/PlatformTabs/PlatformTabs.tsx +++ b/frontend/pages/ManageControlsPage/OSUpdates/components/PlatformTabs/PlatformTabs.tsx @@ -5,6 +5,7 @@ import TabsWrapper from "components/TabsWrapper"; import MacOSTargetForm from "../MacOSTargetForm"; import WindowsTargetForm from "../WindowsTargetForm"; import { OSUpdatesSupportedPlatform } from "../../OSUpdates"; +import EmptyTargetForm from "../EmptyTargetForm"; const baseClass = "platform-tabs"; @@ -43,8 +44,20 @@ const PlatformTabs = ({ } > - macOS - Windows + {/* Bolding text when the tab is active causes a layout shift so + we add a hidden pseudo element with the same text string */} + + macOS + + + Windows + + + iOS + + + iPadOS + + + + + + + diff --git a/frontend/pages/ManageControlsPage/OSUpdates/components/TargetSection/TargetSection.tsx b/frontend/pages/ManageControlsPage/OSUpdates/components/TargetSection/TargetSection.tsx index e9af3e926e59..2214f3688670 100644 --- a/frontend/pages/ManageControlsPage/OSUpdates/components/TargetSection/TargetSection.tsx +++ b/frontend/pages/ManageControlsPage/OSUpdates/components/TargetSection/TargetSection.tsx @@ -109,7 +109,8 @@ const TargetSection = ({ }); const renderTargetForms = () => { - if (isMacMdmEnabled && isWindowsMdmEnabled) { + if (!isMacMdmEnabled && !isWindowsMdmEnabled) { + // if (isMacMdmEnabled && isWindowsMdmEnabled) { return ( {renderNoEnrollSecretBanner()} {renderTable()} diff --git a/frontend/pages/hosts/ManageHostsPage/components/FilterPill/FilterPill.tsx b/frontend/pages/hosts/ManageHostsPage/components/FilterPill/FilterPill.tsx index f44e71b6ca68..a47e88ec991b 100644 --- a/frontend/pages/hosts/ManageHostsPage/components/FilterPill/FilterPill.tsx +++ b/frontend/pages/hosts/ManageHostsPage/components/FilterPill/FilterPill.tsx @@ -14,10 +14,7 @@ interface IFilterPillProps { onClear: () => void; icon?: IconNames; tooltipDescription?: string | ReactNode; - premiumFeatureTooltipDelayHide?: number; className?: string; - isSandboxMode?: boolean; - sandboxPremiumOnlyIcon?: boolean; } const baseClass = "filter-pill"; @@ -26,11 +23,8 @@ const FilterPill = ({ label, icon, tooltipDescription, - premiumFeatureTooltipDelayHide, className, onClear, - isSandboxMode = false, - sandboxPremiumOnlyIcon = false, }: IFilterPillProps) => { const baseClasses = classnames(baseClass, className); const labelClasses = classnames(`${baseClass}__label`, { @@ -47,12 +41,6 @@ const FilterPill = ({
{icon && } - {isSandboxMode && sandboxPremiumOnlyIcon && ( - - )} void; onClickEditLabel: (evt: React.MouseEvent) => void; onClickDeleteLabel: () => void; - isSandboxMode?: boolean; } /** @@ -137,7 +136,6 @@ const HostsFilterBlock = ({ onChangeSoftwareInstallStatusFilter, onClickEditLabel, onClickDeleteLabel, - isSandboxMode = false, }: IHostsFilterBlockProps) => { const renderLabelFilterPill = () => { if (selectedLabel) { @@ -402,10 +400,7 @@ const HostsFilterBlock = ({ handleClearFilter(["low_disk_space"])} - isSandboxMode={isSandboxMode} - sandboxPremiumOnlyIcon /> ); }; diff --git a/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx b/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx index bcb632f7c127..146809ad5628 100644 --- a/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx +++ b/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx @@ -432,7 +432,10 @@ const HostSummary = ({ renderIssues()} {isPremiumTier && renderHostTeam()} {/* Rendering of OS Settings data */} - {(platform === "darwin" || platform === "windows") && + {(platform === "darwin" || + platform === "windows" || + platform === "ios" || + platform === "ipados") && isPremiumTier && isConnectedToFleetMdm && // show if 1 - host is enrolled in Fleet MDM, and hostMdmProfiles && diff --git a/frontend/pages/hosts/details/cards/HostSummary/OSSettingsIndicator/OSSettingsIndicator.tsx b/frontend/pages/hosts/details/cards/HostSummary/OSSettingsIndicator/OSSettingsIndicator.tsx index 68043e52a7f2..bd129a20c5bb 100644 --- a/frontend/pages/hosts/details/cards/HostSummary/OSSettingsIndicator/OSSettingsIndicator.tsx +++ b/frontend/pages/hosts/details/cards/HostSummary/OSSettingsIndicator/OSSettingsIndicator.tsx @@ -31,9 +31,7 @@ type StatusDisplayOptions = Record< const STATUS_DISPLAY_OPTIONS: StatusDisplayOptions = { Verified: { iconName: "success", - tooltipText: - "The host applied all OS settings. Fleet verified with osquery. " + - "Declaration profiles are verified with DDM.", + tooltipText: "These hosts applied all OS settings. Fleet verified.", }, Verifying: { iconName: "success-outline", diff --git a/frontend/utilities/constants.tsx b/frontend/utilities/constants.tsx index 05ae2bef61a4..4f97a39e94d0 100644 --- a/frontend/utilities/constants.tsx +++ b/frontend/utilities/constants.tsx @@ -204,8 +204,8 @@ const PLATFORM_LABEL_NAMES_FROM_API = [ "Red Hat Linux", "Ubuntu Linux", "chrome", - "ios", - "ipados", + "iOS", + "iPadOS", ] as const; type PlatformLabelNameFromAPI = typeof PLATFORM_LABEL_NAMES_FROM_API[number]; @@ -245,8 +245,8 @@ export const PLATFORM_LABEL_DISPLAY_NAMES: Record< "Red Hat Linux": "Red Hat Linux", "Ubuntu Linux": "Ubuntu Linux", chrome: "ChromeOS", - ios: "iOS", - ipados: "iPadOS", + iOS: "iOS", + iPadOS: "iPadOS", } as const; export const PLATFORM_LABEL_DISPLAY_TYPES: Record< @@ -261,14 +261,14 @@ export const PLATFORM_LABEL_DISPLAY_TYPES: Record< "Red Hat Linux": "platform", "Ubuntu Linux": "platform", chrome: "platform", - ios: "platform", - ipados: "platform", + iOS: "platform", + iPadOS: "platform", } as const; export const PLATFORM_TYPE_ICONS: Record< Extract< PlatformLabelNameFromAPI, - "All Linux" | "macOS" | "MS Windows" | "chrome" | "ios" | "ipados" + "All Linux" | "macOS" | "MS Windows" | "chrome" | "iOS" | "iPadOS" >, IconNames > = { @@ -276,15 +276,15 @@ export const PLATFORM_TYPE_ICONS: Record< macOS: "darwin", "MS Windows": "windows", chrome: "chrome", - ios: "iphone", - ipados: "ipad", + iOS: "iOS", + iPadOS: "iPadOS", } as const; export const hasPlatformTypeIcon = ( s: string ): s is Extract< PlatformLabelNameFromAPI, - "All Linux" | "macOS" | "MS Windows" | "chrome" | "ios" | "ipados" + "All Linux" | "macOS" | "MS Windows" | "chrome" | "iOS" | "iPadOS" > => { return !!PLATFORM_TYPE_ICONS[s as keyof typeof PLATFORM_TYPE_ICONS]; }; @@ -327,8 +327,8 @@ export const PLATFORM_NAME_TO_LABEL_NAME = { windows: "MS Windows", linux: "All Linux", chrome: "chrome", - ios: "iPhones", - ipados: "iPads", + ios: "iOS", + ipados: "iPadOS", }; export const HOSTS_SEARCH_BOX_PLACEHOLDER = From 63b82377545f41fb66639edbd88b0dc397a4ea0e Mon Sep 17 00:00:00 2001 From: RachelElysia Date: Tue, 2 Jul 2024 12:28:29 -0400 Subject: [PATCH 04/13] Fix broken icon, 8 page pagination, commit includes test data --- frontend/components/icons/index.ts | 2 + .../OSUpdates/OSUpdates.tsx | 3 +- .../OSVersionTable/OSVersionTable.tsx | 291 +++++++++++++++++- 3 files changed, 293 insertions(+), 3 deletions(-) diff --git a/frontend/components/icons/index.ts b/frontend/components/icons/index.ts index ef7cf59b50c3..d9cbb63a8f7d 100644 --- a/frontend/components/icons/index.ts +++ b/frontend/components/icons/index.ts @@ -116,7 +116,9 @@ export const ICON_MAP = { ubuntu: Ubuntu, chrome: Chrome, ChromeOS: Chrome, + ipados: iPadOS, iPadOS, + ios: iOS, iOS, "premium-feature": PremiumFeature, profile: Profile, diff --git a/frontend/pages/ManageControlsPage/OSUpdates/OSUpdates.tsx b/frontend/pages/ManageControlsPage/OSUpdates/OSUpdates.tsx index 59d4afa5eafc..22ba0b0cf510 100644 --- a/frontend/pages/ManageControlsPage/OSUpdates/OSUpdates.tsx +++ b/frontend/pages/ManageControlsPage/OSUpdates/OSUpdates.tsx @@ -40,11 +40,10 @@ const getSelectedPlatform = ( }; interface IOSUpdates { - router: InjectedRouter; teamIdForApi: number; } -const OSUpdates = ({ router, teamIdForApi }: IOSUpdates) => { +const OSUpdates = ({ teamIdForApi }: IOSUpdates) => { const { isPremiumTier, config, setConfig } = useContext(AppContext); const [ diff --git a/frontend/pages/ManageControlsPage/OSUpdates/components/OSVersionTable/OSVersionTable.tsx b/frontend/pages/ManageControlsPage/OSUpdates/components/OSVersionTable/OSVersionTable.tsx index 86322f80604d..fa9b2f502633 100644 --- a/frontend/pages/ManageControlsPage/OSUpdates/components/OSVersionTable/OSVersionTable.tsx +++ b/frontend/pages/ManageControlsPage/OSUpdates/components/OSVersionTable/OSVersionTable.tsx @@ -25,11 +25,299 @@ const OSVersionTable = ({ }: IOSVersionTableProps) => { const columns = generateTableHeaders(currentTeamId); + const osVersionData2 = [ + { + os_version_id: 179, + hosts_count: 38, + name: "iOS Name 10.0", + name_only: "iOS", + version: "14.5", + platform: "ios", + vulnerabilities: [], + }, + { + os_version_id: 180, + hosts_count: 38, + name: "iPadOS 17.5.1", + name_only: "iPadOS", + version: "17.5.1", + platform: "ipados", + vulnerabilities: [], + }, + { + os_version_id: 79, + hosts_count: 38, + name: "macOS 14.5", + name_only: "macOS", + version: "14.5", + platform: "darwin", + generated_cpes: [ + "cpe:2.3:o:apple:macos:14.5:*:*:*:*:*:*:*", + "cpe:2.3:o:apple:mac_os_x:14.5:*:*:*:*:*:*:*", + ], + vulnerabilities: [], + }, + { + os_version_id: 51, + hosts_count: 13, + name: "macOS 14.4.1", + name_only: "macOS", + version: "14.4.1", + platform: "darwin", + generated_cpes: [ + "cpe:2.3:o:apple:macos:14.4.1:*:*:*:*:*:*:*", + "cpe:2.3:o:apple:mac_os_x:14.4.1:*:*:*:*:*:*:*", + ], + vulnerabilities: [], + }, + { + os_version_id: 45, + hosts_count: 3, + name: "macOS 14.4", + name_only: "macOS", + version: "14.4", + platform: "darwin", + generated_cpes: [ + "cpe:2.3:o:apple:macos:14.4:*:*:*:*:*:*:*", + "cpe:2.3:o:apple:mac_os_x:14.4:*:*:*:*:*:*:*", + ], + vulnerabilities: [], + }, + { + os_version_id: 47, + hosts_count: 3, + name: "Microsoft Windows 11 Pro 23H2 10.0.22621.3296", + name_only: "Microsoft Windows 11 Pro 23H2", + version: "10.0.22621.3296", + platform: "windows", + vulnerabilities: [], + }, + { + os_version_id: 87, + hosts_count: 2, + name: "Microsoft Windows 11 Pro 23H2 10.0.22631.3737", + name_only: "Microsoft Windows 11 Pro 23H2", + version: "10.0.22631.3737", + platform: "windows", + vulnerabilities: [], + }, + { + os_version_id: 82, + hosts_count: 2, + name: "ChromeOS 124.0.6367.225", + name_only: "ChromeOS", + version: "124.0.6367.225", + platform: "chrome", + vulnerabilities: [], + }, + { + os_version_id: 86, + hosts_count: 2, + name: "macOS 15.0", + name_only: "macOS", + version: "15.0", + platform: "darwin", + generated_cpes: [ + "cpe:2.3:o:apple:macos:15.0:*:*:*:*:*:*:*", + "cpe:2.3:o:apple:mac_os_x:15.0:*:*:*:*:*:*:*", + ], + vulnerabilities: [ + { + cve: "CVE-2024-23252", + details_link: "https://nvd.nist.gov/vuln/detail/CVE-2024-23252", + epss_probability: 0.00043, + cisa_known_exploit: false, + cve_published: "2024-03-08T02:15:00Z", + cve_description: + "Rejected reason: This CVE ID has been rejected or withdrawn by its CVE Numbering Authority.", + resolved_in_version: "17.4", + }, + ], + }, + { + os_version_id: 39, + hosts_count: 2, + name: "Microsoft Windows 11 Pro 22H2 10.0.22621.3155", + name_only: "Microsoft Windows 11 Pro 22H2", + version: "10.0.22621.3155", + platform: "windows", + vulnerabilities: [], + }, + { + os_version_id: 90, + hosts_count: 1, + name: "Microsoft Windows 11 Pro 23H2 10.0.22631.3810", + name_only: "Microsoft Windows 11 Pro 23H2", + version: "10.0.22631.3810", + platform: "windows", + vulnerabilities: [], + }, + { + os_version_id: 64, + hosts_count: 1, + name: "macOS 13.5", + name_only: "macOS", + version: "13.5", + platform: "darwin", + generated_cpes: [ + "cpe:2.3:o:apple:macos:13.5:*:*:*:*:*:*:*", + "cpe:2.3:o:apple:mac_os_x:13.5:*:*:*:*:*:*:*", + ], + vulnerabilities: [], + }, + { + os_version_id: 73, + hosts_count: 1, + name: "Microsoft Windows 11 Pro 23H2 10.0.22631.3447", + name_only: "Microsoft Windows 11 Pro 23H2", + version: "10.0.22631.3447", + platform: "windows", + vulnerabilities: [], + }, + { + os_version_id: 76, + hosts_count: 1, + name: "Microsoft Windows 11 Pro 23H2 10.0.22631.3593", + name_only: "Microsoft Windows 11 Pro 23H2", + version: "10.0.22631.3593", + platform: "windows", + vulnerabilities: [], + }, + { + os_version_id: 88, + hosts_count: 1, + name: "Microsoft Windows 11 Pro 23H2 10.0.22631.3155", + name_only: "Microsoft Windows 11 Pro 23H2", + version: "10.0.22631.3155", + platform: "windows", + vulnerabilities: [], + }, + { + os_version_id: 72, + hosts_count: 1, + name: "Microsoft Windows Server 2022 Datacenter 21H2 10.0.20348.2113", + name_only: "Microsoft Windows Server 2022 Datacenter 21H2", + version: "10.0.20348.2113", + platform: "windows", + vulnerabilities: [], + }, + { + os_version_id: 34, + hosts_count: 1, + name: "Microsoft Windows 11 Pro 23H2 10.0.22621.3155", + name_only: "Microsoft Windows 11 Pro 23H2", + version: "10.0.22621.3155", + platform: "windows", + vulnerabilities: [], + }, + { + os_version_id: 83, + hosts_count: 1, + name: "Microsoft Windows 11 Pro 23H2 10.0.22631.3296", + name_only: "Microsoft Windows 11 Pro 23H2", + version: "10.0.22631.3296", + platform: "windows", + vulnerabilities: [], + }, + { + os_version_id: 7, + hosts_count: 1, + name: "macOS 13.5.1", + name_only: "macOS", + version: "13.5.1", + platform: "darwin", + generated_cpes: [ + "cpe:2.3:o:apple:macos:13.5.1:*:*:*:*:*:*:*", + "cpe:2.3:o:apple:mac_os_x:13.5.1:*:*:*:*:*:*:*", + ], + vulnerabilities: [], + }, + { + os_version_id: 10, + hosts_count: 1, + name: "macOS 14.1", + name_only: "macOS", + version: "14.1", + platform: "darwin", + generated_cpes: [ + "cpe:2.3:o:apple:macos:14.1:*:*:*:*:*:*:*", + "cpe:2.3:o:apple:mac_os_x:14.1:*:*:*:*:*:*:*", + ], + vulnerabilities: [], + }, + { + os_version_id: 65, + hosts_count: 1, + name: "macOS 14.2", + name_only: "macOS", + version: "14.2", + platform: "darwin", + generated_cpes: [ + "cpe:2.3:o:apple:macos:14.2:*:*:*:*:*:*:*", + "cpe:2.3:o:apple:mac_os_x:14.2:*:*:*:*:*:*:*", + ], + vulnerabilities: [], + }, + { + os_version_id: 13, + hosts_count: 1, + name: "macOS 14.2.1", + name_only: "macOS", + version: "14.2.1", + platform: "darwin", + generated_cpes: [ + "cpe:2.3:o:apple:macos:14.2.1:*:*:*:*:*:*:*", + "cpe:2.3:o:apple:mac_os_x:14.2.1:*:*:*:*:*:*:*", + ], + vulnerabilities: [], + }, + { + os_version_id: 14, + hosts_count: 1, + name: "macOS 14.3", + name_only: "macOS", + version: "14.3", + platform: "darwin", + generated_cpes: [ + "cpe:2.3:o:apple:macos:14.3:*:*:*:*:*:*:*", + "cpe:2.3:o:apple:mac_os_x:14.3:*:*:*:*:*:*:*", + ], + vulnerabilities: [], + }, + { + os_version_id: 89, + hosts_count: 1, + name: "Microsoft Windows 11 Home 23H2 10.0.22631.3737", + name_only: "Microsoft Windows 11 Home 23H2", + version: "10.0.22631.3737", + platform: "windows", + vulnerabilities: [], + }, + { + os_version_id: 77, + hosts_count: 1, + name: "Microsoft Windows 11 Enterprise Evaluation 22H2 10.0.22621.3447", + name_only: "Microsoft Windows 11 Enterprise Evaluation 22H2", + version: "10.0.22621.3447", + platform: "windows", + vulnerabilities: [], + }, + { + os_version_id: 74, + hosts_count: 1, + name: "Microsoft Windows 11 Enterprise 23H2 10.0.22631.3447", + name_only: "Microsoft Windows 11 Enterprise 23H2", + version: "10.0.22631.3447", + platform: "windows", + vulnerabilities: [], + }, + ]; + return (
); From 025193b3da2093133b7b033ab055639cbadf89df Mon Sep 17 00:00:00 2001 From: RachelElysia Date: Tue, 2 Jul 2024 13:00:59 -0400 Subject: [PATCH 05/13] Fix boolean like tabs to support 4 tabs --- .../OSUpdates/OSUpdates.tsx | 1 + .../components/NudgePreview/NudgePreview.tsx | 6 ++++++ .../components/PlatformTabs/PlatformTabs.tsx | 20 ++++++++++++++----- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/frontend/pages/ManageControlsPage/OSUpdates/OSUpdates.tsx b/frontend/pages/ManageControlsPage/OSUpdates/OSUpdates.tsx index 22ba0b0cf510..ad884d245b47 100644 --- a/frontend/pages/ManageControlsPage/OSUpdates/OSUpdates.tsx +++ b/frontend/pages/ManageControlsPage/OSUpdates/OSUpdates.tsx @@ -111,6 +111,7 @@ const OSUpdates = ({ teamIdForApi }: IOSUpdates) => { } // END TODO + console.log("selectedPlatform", selectedPlatform); return (

diff --git a/frontend/pages/ManageControlsPage/OSUpdates/components/NudgePreview/NudgePreview.tsx b/frontend/pages/ManageControlsPage/OSUpdates/components/NudgePreview/NudgePreview.tsx index 813689d2051f..9f75ee13bb90 100644 --- a/frontend/pages/ManageControlsPage/OSUpdates/components/NudgePreview/NudgePreview.tsx +++ b/frontend/pages/ManageControlsPage/OSUpdates/components/NudgePreview/NudgePreview.tsx @@ -64,6 +64,12 @@ interface INudgePreviewProps { } const NudgePreview = ({ platform }: INudgePreviewProps) => { + const isSupportedPlatform = platform === "windows" || platform === "darwin"; + + if (!isSupportedPlatform) { + return null; + } + // FIXME: on slow connection the image loads after the text which looks weird and can cause a // mismatch between the text and the image when switching between platforms. We should load the // image first and then the text. diff --git a/frontend/pages/ManageControlsPage/OSUpdates/components/PlatformTabs/PlatformTabs.tsx b/frontend/pages/ManageControlsPage/OSUpdates/components/PlatformTabs/PlatformTabs.tsx index 78e784849e6a..bee756b6b76a 100644 --- a/frontend/pages/ManageControlsPage/OSUpdates/components/PlatformTabs/PlatformTabs.tsx +++ b/frontend/pages/ManageControlsPage/OSUpdates/components/PlatformTabs/PlatformTabs.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useState } from "react"; import { Tab, TabList, TabPanel, Tabs } from "react-tabs"; import TabsWrapper from "components/TabsWrapper"; @@ -34,14 +34,24 @@ const PlatformTabs = ({ }: IPlatformTabsProps) => { // FIXME: This behaves unexpectedly when a user switches tabs or changes the teams dropdown while a form is // submitting. + + const PLATFORM_BY_INDEX: OSUpdatesSupportedPlatform[] = [ + "darwin", + "windows", + "iOS", + "iPadOS", + ]; + + const onTabChange = (index: number) => { + onSelectPlatform(PLATFORM_BY_INDEX[index]); + }; + return (

- onSelectPlatform(currentIndex === 0 ? "darwin" : "windows") - } + defaultIndex={PLATFORM_BY_INDEX.indexOf(selectedPlatform)} + onSelect={onTabChange} > {/* Bolding text when the tab is active causes a layout shift so From db3e7764b2b05f3bcc75b45e8132c14b4accd62b Mon Sep 17 00:00:00 2001 From: RachelElysia Date: Tue, 2 Jul 2024 15:56:46 -0400 Subject: [PATCH 06/13] Finish frontend (with mock data/code commented out) --- .../AddHostsModal/AddHostsModal.tests.tsx | 56 +++---------------- .../AddHostsModal/AddHostsModal.tsx | 12 +--- .../PlatformWrapper/PlatformWrapper.tsx | 33 +++++++++-- .../PlatformWrapper/_styles.scss | 2 +- .../TeamDetailsWrapper/TeamDetailsWrapper.tsx | 5 -- .../hosts/ManageHostsPage/ManageHostsPage.tsx | 12 +--- 6 files changed, 41 insertions(+), 79 deletions(-) diff --git a/frontend/components/AddHostsModal/AddHostsModal.tests.tsx b/frontend/components/AddHostsModal/AddHostsModal.tests.tsx index f3368a5140af..658bbd11882e 100644 --- a/frontend/components/AddHostsModal/AddHostsModal.tests.tsx +++ b/frontend/components/AddHostsModal/AddHostsModal.tests.tsx @@ -57,15 +57,13 @@ describe("AddHostsModal", () => { expect(windowsText).toBeInTheDocument(); expect(screen.queryByText(/--enable-scripts/i)).toBeInTheDocument(); - await user.click(screen.getByRole("tab", { name: "Linux (RPM)" })); - const linuxRPMText = screen.getByText(/--type=rpm/i); - expect(linuxRPMText).toBeInTheDocument(); - expect(screen.queryByText(/--enable-scripts/i)).toBeInTheDocument(); - - await user.click(screen.getByRole("tab", { name: "Linux (deb)" })); + await user.click(screen.getByRole("tab", { name: "Linux" })); const linuxDebText = screen.getByText(/--type=deb/i); expect(linuxDebText).toBeInTheDocument(); expect(screen.queryByText(/--enable-scripts/i)).toBeInTheDocument(); + expect( + screen.queryByText(/CentOS, Red Hat, and Fedora Linux, use --type=rpm/i) + ).toBeInTheDocument(); await user.click(screen.getByRole("tab", { name: "ChromeOS" })); const extensionId = screen.getByDisplayValue( @@ -74,6 +72,10 @@ describe("AddHostsModal", () => { expect(extensionId).toBeInTheDocument(); expect(screen.queryByText(/--enable-scripts/i)).not.toBeInTheDocument(); + await user.click(screen.getByRole("tab", { name: "iOS & iPadOS" })); + expect(screen.queryByText(/Apple Business Manager/i)).toBeInTheDocument(); + expect(screen.queryByText(/Learn more/i)).toBeInTheDocument(); + await user.click(screen.getByRole("tab", { name: "Advanced" })); const advancedText = screen.getByText(/--type=YOUR_TYPE/i); expect(advancedText).toBeInTheDocument(); @@ -146,41 +148,6 @@ describe("AddHostsModal", () => { expect(ctaButton).toBeEnabled(); }); - it("sandbox mode renders and download disabled until a platform is selected", async () => { - const render = createCustomRenderer({ - withBackendMock: true, - context: { - app: { - isPreviewMode: false, - config: createMockConfig(), - }, - }, - }); - - const { user } = render( - - ); - - const text = screen.getByText("Which platform is your host running?"); - const windowsText = screen.getByText("Windows"); - const downloadButton = screen.getByRole("button", { - name: /Download installer/i, - }); - - expect(text).toBeInTheDocument(); - expect(downloadButton).not.toBeEnabled(); - - await user.click(windowsText); - - expect(downloadButton).toBeEnabled(); - }); - it("excludes `--enable-scripts` flag if `config.server_settings.scripts-disabled` is `true`", async () => { const mockConfig = createMockConfig(); mockConfig.server_settings.scripts_disabled = true; @@ -214,16 +181,11 @@ describe("AddHostsModal", () => { expect(windowsText).toBeInTheDocument(); expect(screen.queryByText(/--enable-scripts/i)).not.toBeInTheDocument(); - await user.click(screen.getByRole("tab", { name: "Linux (RPM)" })); + await user.click(screen.getByRole("tab", { name: "Linux" })); const linuxRPMText = screen.getByText(/--type=rpm/i); expect(linuxRPMText).toBeInTheDocument(); expect(screen.queryByText(/--enable-scripts/i)).not.toBeInTheDocument(); - await user.click(screen.getByRole("tab", { name: "Linux (deb)" })); - const linuxDebText = screen.getByText(/--type=deb/i); - expect(linuxDebText).toBeInTheDocument(); - expect(screen.queryByText(/--enable-scripts/i)).not.toBeInTheDocument(); - await user.click(screen.getByRole("tab", { name: "ChromeOS" })); const extensionId = screen.getByDisplayValue( /fleeedmmihkfkeemmipgmhhjemlljidg/i diff --git a/frontend/components/AddHostsModal/AddHostsModal.tsx b/frontend/components/AddHostsModal/AddHostsModal.tsx index 7d74f7cfc3c2..04a42908ed2e 100644 --- a/frontend/components/AddHostsModal/AddHostsModal.tsx +++ b/frontend/components/AddHostsModal/AddHostsModal.tsx @@ -18,7 +18,6 @@ interface IAddHostsModal { enrollSecret?: string; isAnyTeamSelected: boolean; isLoading: boolean; - isSandboxMode?: boolean; onCancel: () => void; openEnrollSecretModal?: () => void; } @@ -28,7 +27,6 @@ const AddHostsModal = ({ enrollSecret, isAnyTeamSelected, isLoading, - isSandboxMode, onCancel, openEnrollSecretModal, }: IAddHostsModal): JSX.Element => { @@ -53,12 +51,6 @@ const AddHostsModal = ({ openEnrollSecretModal && openEnrollSecretModal(); }; - // TODO: Currently, prepacked installers in Fleet Sandbox use the global enroll secret, - // and Fleet Sandbox runs Fleet Free so the currentTeam check here is an - // additional precaution/reminder to revisit this in connection with future changes. - // See https://github.com/fleetdm/fleet/issues/4970#issuecomment-1187679407. - const shouldRenderDownloadInstallersContent = - isSandboxMode && !isAnyTeamSelected; const renderModalContent = () => { if (isLoading) { return ; @@ -81,9 +73,7 @@ const AddHostsModal = ({ ); } - return shouldRenderDownloadInstallersContent ? ( - - ) : ( + return ( ); } + + if (packageType === "ios-ipados") { + return ( +
+

+ Enroll iPhones and iPads by adding them to Fleet in Apple Business + Manager (ABM).{" "} + +

+
+ ); + } + if (packageType === "advanced") { return ( <> @@ -539,7 +556,11 @@ const PlatformWrapper = ({ label={renderLabel(packageType, renderInstallerString(packageType))} type="textarea" value={renderInstallerString(packageType)} - helpText="Distribute your package to add hosts to Fleet." + helpText={`Distribute your package to add hosts to Fleet.${ + packageType === "deb" + ? " For CentOS, Red Hat, and Fedora Linux, use --type=rpm." + : "" + }`} /> ); diff --git a/frontend/components/AddHostsModal/PlatformWrapper/_styles.scss b/frontend/components/AddHostsModal/PlatformWrapper/_styles.scss index b032d830b287..a038b91704e8 100644 --- a/frontend/components/AddHostsModal/PlatformWrapper/_styles.scss +++ b/frontend/components/AddHostsModal/PlatformWrapper/_styles.scss @@ -8,7 +8,7 @@ position: initial; .react-tabs { &__tab-list { - margin: 0 0 1.25rem; + margin: 0 0 $pad-large; } } } diff --git a/frontend/pages/admin/TeamManagementPage/TeamDetailsWrapper/TeamDetailsWrapper.tsx b/frontend/pages/admin/TeamManagementPage/TeamDetailsWrapper/TeamDetailsWrapper.tsx index 367c76e113b1..90a3d609d929 100644 --- a/frontend/pages/admin/TeamManagementPage/TeamDetailsWrapper/TeamDetailsWrapper.tsx +++ b/frontend/pages/admin/TeamManagementPage/TeamDetailsWrapper/TeamDetailsWrapper.tsx @@ -465,11 +465,6 @@ const TeamDetailsWrapper = ({ enrollSecret={teamSecrets?.[0]?.secret} isAnyTeamSelected={isAnyTeamSelected} isLoading={isLoadingTeams} - // TODO: Currently, prepacked installers in Fleet Sandbox use the global enroll secret, - // and Fleet Sandbox runs Fleet Free so explicitly setting isSandboxMode here is an - // additional precaution/reminder to revisit this in connection with future changes. - // See https://github.com/fleetdm/fleet/issues/4970#issuecomment-1187679407. - isSandboxMode={false} onCancel={toggleAddHostsModal} openEnrollSecretModal={toggleManageEnrollSecretsModal} /> diff --git a/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx b/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx index 3b99514e6ad6..d3d69af8d373 100644 --- a/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx +++ b/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx @@ -1258,21 +1258,15 @@ const ManageHostsPage = ({ ); const renderAddHostsModal = () => { - const enrollSecret = - // TODO: Currently, prepacked installers in Fleet Sandbox use the global enroll secret, - // and Fleet Sandbox runs Fleet Free so the isSandboxMode check here is an - // additional precaution/reminder to revisit this in connection with future changes. - // See https://github.com/fleetdm/fleet/issues/4970#issuecomment-1187679407. - isAnyTeamSelected && !isSandboxMode - ? teamSecrets?.[0].secret - : globalSecrets?.[0].secret; + const enrollSecret = isAnyTeamSelected + ? teamSecrets?.[0].secret + : globalSecrets?.[0].secret; return ( setShowEnrollSecretModal(true)} /> From 39673a95f9acf15b043602437fe5f425f4f28081 Mon Sep 17 00:00:00 2001 From: RachelElysia Date: Tue, 2 Jul 2024 16:35:31 -0400 Subject: [PATCH 07/13] Remove any mock data, remove code bypassing and logs --- .../cards/HostsSummary/HostsSummary.tsx | 4 +- .../OSSettings/OSSettings.tsx | 14 +- .../cards/CustomSettings/CustomSettings.tsx | 22 +- .../OSUpdates/OSUpdates.tsx | 25 +- .../OSVersionTable/OSVersionTable.tsx | 290 +----------------- frontend/utilities/constants.tsx | 6 +- 6 files changed, 20 insertions(+), 341 deletions(-) diff --git a/frontend/pages/DashboardPage/cards/HostsSummary/HostsSummary.tsx b/frontend/pages/DashboardPage/cards/HostsSummary/HostsSummary.tsx index 6cd39c361e58..3845e81c1ca7 100644 --- a/frontend/pages/DashboardPage/cards/HostsSummary/HostsSummary.tsx +++ b/frontend/pages/DashboardPage/cards/HostsSummary/HostsSummary.tsx @@ -137,7 +137,7 @@ const HostsSummary = ({ const renderIosCount = (teamId?: number) => { const iosLabelId = builtInLabels?.find( - (builtin) => builtin.name === PLATFORM_NAME_TO_LABEL_NAME.chrome // TODO: change to ios + (builtin) => builtin.name === PLATFORM_NAME_TO_LABEL_NAME.ios // TODO: change to ios )?.id; if (isLoadingHostsSummary || iosLabelId === undefined) { @@ -160,7 +160,7 @@ const HostsSummary = ({ const renderIpadosCount = (teamId?: number) => { const ipadosLabelId = builtInLabels?.find( - (builtin) => builtin.name === PLATFORM_NAME_TO_LABEL_NAME.chrome // TODO: change to ipados + (builtin) => builtin.name === PLATFORM_NAME_TO_LABEL_NAME.ipados // TODO: change to ipados )?.id; if (isLoadingHostsSummary || ipadosLabelId === undefined) { diff --git a/frontend/pages/ManageControlsPage/OSSettings/OSSettings.tsx b/frontend/pages/ManageControlsPage/OSSettings/OSSettings.tsx index f69713de50a7..65caa724e8e4 100644 --- a/frontend/pages/ManageControlsPage/OSSettings/OSSettings.tsx +++ b/frontend/pages/ManageControlsPage/OSSettings/OSSettings.tsx @@ -51,14 +51,12 @@ const OSSettings = ({ ); // MDM is not on so show messaging for user to enable it. - // TODO: Reinstate when ready - // if ( - // !config?.mdm.enabled_and_configured && - // !config?.mdm.windows_enabled_and_configured - // ) { - // return ; - // } - // END TODO + if ( + !config?.mdm.enabled_and_configured && + !config?.mdm.windows_enabled_and_configured + ) { + return ; + } const DEFAULT_SETTINGS_SECTION = OS_SETTINGS_NAV_ITEMS[0]; diff --git a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/CustomSettings.tsx b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/CustomSettings.tsx index 820a32dca9ed..bee17934991f 100644 --- a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/CustomSettings.tsx +++ b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/CustomSettings.tsx @@ -57,28 +57,8 @@ const CustomSettings = ({ const selectedProfile = useRef(null); - const profilesData: IMdmProfilesResponse = { - profiles: [ - { - profile_uuid: "12345", - team_id: 1, - name: "Profile name", - platform: "ios", - identifier: "1234", // null for windows profiles - created_at: "2024-03-07T14:40:00Z", - updated_at: "2024-03-07T14:40:00Z", - checksum: "1234", // null for windows profiles - labels: [{ name: "string", broken: false }], - }, - ], - meta: { - has_next_results: true, - has_previous_results: false, - }, - }; - const { - data: profilesData2, + data: profilesData, isLoading: isLoadingProfiles, isError: isErrorProfiles, refetch: refetchProfiles, diff --git a/frontend/pages/ManageControlsPage/OSUpdates/OSUpdates.tsx b/frontend/pages/ManageControlsPage/OSUpdates/OSUpdates.tsx index ad884d245b47..e18a4afca21e 100644 --- a/frontend/pages/ManageControlsPage/OSUpdates/OSUpdates.tsx +++ b/frontend/pages/ManageControlsPage/OSUpdates/OSUpdates.tsx @@ -40,10 +40,11 @@ const getSelectedPlatform = ( }; interface IOSUpdates { + router: InjectedRouter; teamIdForApi: number; } -const OSUpdates = ({ teamIdForApi }: IOSUpdates) => { +const OSUpdates = ({ router, teamIdForApi }: IOSUpdates) => { const { isPremiumTier, config, setConfig } = useContext(AppContext); const [ @@ -92,26 +93,18 @@ const OSUpdates = ({ teamIdForApi }: IOSUpdates) => { // FIXME: Handle error states for app config and team config (need specifications for this). // mdm is not enabled for mac or windows. - // TODO: Reinstate when ready - // if ( - // !config?.mdm.enabled_and_configured && - // !config?.mdm.windows_enabled_and_configured - // ) { - // return ; - // } - // END TODO + + if ( + !config?.mdm.enabled_and_configured && + !config?.mdm.windows_enabled_and_configured + ) { + return ; + } // If the user has not selected a platform yet, we default to the platform that // is enabled and configured. const selectedPlatform = selectedPlatformTab || getSelectedPlatform(config); - // TODO: Remove when ready - if (!config) { - return null; - } - // END TODO - - console.log("selectedPlatform", selectedPlatform); return (

diff --git a/frontend/pages/ManageControlsPage/OSUpdates/components/OSVersionTable/OSVersionTable.tsx b/frontend/pages/ManageControlsPage/OSUpdates/components/OSVersionTable/OSVersionTable.tsx index fa9b2f502633..372430e0c036 100644 --- a/frontend/pages/ManageControlsPage/OSUpdates/components/OSVersionTable/OSVersionTable.tsx +++ b/frontend/pages/ManageControlsPage/OSUpdates/components/OSVersionTable/OSVersionTable.tsx @@ -25,299 +25,11 @@ const OSVersionTable = ({ }: IOSVersionTableProps) => { const columns = generateTableHeaders(currentTeamId); - const osVersionData2 = [ - { - os_version_id: 179, - hosts_count: 38, - name: "iOS Name 10.0", - name_only: "iOS", - version: "14.5", - platform: "ios", - vulnerabilities: [], - }, - { - os_version_id: 180, - hosts_count: 38, - name: "iPadOS 17.5.1", - name_only: "iPadOS", - version: "17.5.1", - platform: "ipados", - vulnerabilities: [], - }, - { - os_version_id: 79, - hosts_count: 38, - name: "macOS 14.5", - name_only: "macOS", - version: "14.5", - platform: "darwin", - generated_cpes: [ - "cpe:2.3:o:apple:macos:14.5:*:*:*:*:*:*:*", - "cpe:2.3:o:apple:mac_os_x:14.5:*:*:*:*:*:*:*", - ], - vulnerabilities: [], - }, - { - os_version_id: 51, - hosts_count: 13, - name: "macOS 14.4.1", - name_only: "macOS", - version: "14.4.1", - platform: "darwin", - generated_cpes: [ - "cpe:2.3:o:apple:macos:14.4.1:*:*:*:*:*:*:*", - "cpe:2.3:o:apple:mac_os_x:14.4.1:*:*:*:*:*:*:*", - ], - vulnerabilities: [], - }, - { - os_version_id: 45, - hosts_count: 3, - name: "macOS 14.4", - name_only: "macOS", - version: "14.4", - platform: "darwin", - generated_cpes: [ - "cpe:2.3:o:apple:macos:14.4:*:*:*:*:*:*:*", - "cpe:2.3:o:apple:mac_os_x:14.4:*:*:*:*:*:*:*", - ], - vulnerabilities: [], - }, - { - os_version_id: 47, - hosts_count: 3, - name: "Microsoft Windows 11 Pro 23H2 10.0.22621.3296", - name_only: "Microsoft Windows 11 Pro 23H2", - version: "10.0.22621.3296", - platform: "windows", - vulnerabilities: [], - }, - { - os_version_id: 87, - hosts_count: 2, - name: "Microsoft Windows 11 Pro 23H2 10.0.22631.3737", - name_only: "Microsoft Windows 11 Pro 23H2", - version: "10.0.22631.3737", - platform: "windows", - vulnerabilities: [], - }, - { - os_version_id: 82, - hosts_count: 2, - name: "ChromeOS 124.0.6367.225", - name_only: "ChromeOS", - version: "124.0.6367.225", - platform: "chrome", - vulnerabilities: [], - }, - { - os_version_id: 86, - hosts_count: 2, - name: "macOS 15.0", - name_only: "macOS", - version: "15.0", - platform: "darwin", - generated_cpes: [ - "cpe:2.3:o:apple:macos:15.0:*:*:*:*:*:*:*", - "cpe:2.3:o:apple:mac_os_x:15.0:*:*:*:*:*:*:*", - ], - vulnerabilities: [ - { - cve: "CVE-2024-23252", - details_link: "https://nvd.nist.gov/vuln/detail/CVE-2024-23252", - epss_probability: 0.00043, - cisa_known_exploit: false, - cve_published: "2024-03-08T02:15:00Z", - cve_description: - "Rejected reason: This CVE ID has been rejected or withdrawn by its CVE Numbering Authority.", - resolved_in_version: "17.4", - }, - ], - }, - { - os_version_id: 39, - hosts_count: 2, - name: "Microsoft Windows 11 Pro 22H2 10.0.22621.3155", - name_only: "Microsoft Windows 11 Pro 22H2", - version: "10.0.22621.3155", - platform: "windows", - vulnerabilities: [], - }, - { - os_version_id: 90, - hosts_count: 1, - name: "Microsoft Windows 11 Pro 23H2 10.0.22631.3810", - name_only: "Microsoft Windows 11 Pro 23H2", - version: "10.0.22631.3810", - platform: "windows", - vulnerabilities: [], - }, - { - os_version_id: 64, - hosts_count: 1, - name: "macOS 13.5", - name_only: "macOS", - version: "13.5", - platform: "darwin", - generated_cpes: [ - "cpe:2.3:o:apple:macos:13.5:*:*:*:*:*:*:*", - "cpe:2.3:o:apple:mac_os_x:13.5:*:*:*:*:*:*:*", - ], - vulnerabilities: [], - }, - { - os_version_id: 73, - hosts_count: 1, - name: "Microsoft Windows 11 Pro 23H2 10.0.22631.3447", - name_only: "Microsoft Windows 11 Pro 23H2", - version: "10.0.22631.3447", - platform: "windows", - vulnerabilities: [], - }, - { - os_version_id: 76, - hosts_count: 1, - name: "Microsoft Windows 11 Pro 23H2 10.0.22631.3593", - name_only: "Microsoft Windows 11 Pro 23H2", - version: "10.0.22631.3593", - platform: "windows", - vulnerabilities: [], - }, - { - os_version_id: 88, - hosts_count: 1, - name: "Microsoft Windows 11 Pro 23H2 10.0.22631.3155", - name_only: "Microsoft Windows 11 Pro 23H2", - version: "10.0.22631.3155", - platform: "windows", - vulnerabilities: [], - }, - { - os_version_id: 72, - hosts_count: 1, - name: "Microsoft Windows Server 2022 Datacenter 21H2 10.0.20348.2113", - name_only: "Microsoft Windows Server 2022 Datacenter 21H2", - version: "10.0.20348.2113", - platform: "windows", - vulnerabilities: [], - }, - { - os_version_id: 34, - hosts_count: 1, - name: "Microsoft Windows 11 Pro 23H2 10.0.22621.3155", - name_only: "Microsoft Windows 11 Pro 23H2", - version: "10.0.22621.3155", - platform: "windows", - vulnerabilities: [], - }, - { - os_version_id: 83, - hosts_count: 1, - name: "Microsoft Windows 11 Pro 23H2 10.0.22631.3296", - name_only: "Microsoft Windows 11 Pro 23H2", - version: "10.0.22631.3296", - platform: "windows", - vulnerabilities: [], - }, - { - os_version_id: 7, - hosts_count: 1, - name: "macOS 13.5.1", - name_only: "macOS", - version: "13.5.1", - platform: "darwin", - generated_cpes: [ - "cpe:2.3:o:apple:macos:13.5.1:*:*:*:*:*:*:*", - "cpe:2.3:o:apple:mac_os_x:13.5.1:*:*:*:*:*:*:*", - ], - vulnerabilities: [], - }, - { - os_version_id: 10, - hosts_count: 1, - name: "macOS 14.1", - name_only: "macOS", - version: "14.1", - platform: "darwin", - generated_cpes: [ - "cpe:2.3:o:apple:macos:14.1:*:*:*:*:*:*:*", - "cpe:2.3:o:apple:mac_os_x:14.1:*:*:*:*:*:*:*", - ], - vulnerabilities: [], - }, - { - os_version_id: 65, - hosts_count: 1, - name: "macOS 14.2", - name_only: "macOS", - version: "14.2", - platform: "darwin", - generated_cpes: [ - "cpe:2.3:o:apple:macos:14.2:*:*:*:*:*:*:*", - "cpe:2.3:o:apple:mac_os_x:14.2:*:*:*:*:*:*:*", - ], - vulnerabilities: [], - }, - { - os_version_id: 13, - hosts_count: 1, - name: "macOS 14.2.1", - name_only: "macOS", - version: "14.2.1", - platform: "darwin", - generated_cpes: [ - "cpe:2.3:o:apple:macos:14.2.1:*:*:*:*:*:*:*", - "cpe:2.3:o:apple:mac_os_x:14.2.1:*:*:*:*:*:*:*", - ], - vulnerabilities: [], - }, - { - os_version_id: 14, - hosts_count: 1, - name: "macOS 14.3", - name_only: "macOS", - version: "14.3", - platform: "darwin", - generated_cpes: [ - "cpe:2.3:o:apple:macos:14.3:*:*:*:*:*:*:*", - "cpe:2.3:o:apple:mac_os_x:14.3:*:*:*:*:*:*:*", - ], - vulnerabilities: [], - }, - { - os_version_id: 89, - hosts_count: 1, - name: "Microsoft Windows 11 Home 23H2 10.0.22631.3737", - name_only: "Microsoft Windows 11 Home 23H2", - version: "10.0.22631.3737", - platform: "windows", - vulnerabilities: [], - }, - { - os_version_id: 77, - hosts_count: 1, - name: "Microsoft Windows 11 Enterprise Evaluation 22H2 10.0.22621.3447", - name_only: "Microsoft Windows 11 Enterprise Evaluation 22H2", - version: "10.0.22621.3447", - platform: "windows", - vulnerabilities: [], - }, - { - os_version_id: 74, - hosts_count: 1, - name: "Microsoft Windows 11 Enterprise 23H2 10.0.22631.3447", - name_only: "Microsoft Windows 11 Enterprise 23H2", - version: "10.0.22631.3447", - platform: "windows", - vulnerabilities: [], - }, - ]; - return (

Date: Wed, 3 Jul 2024 10:24:23 -0400 Subject: [PATCH 08/13] Clean up interfaces, better responsive design --- .../PlatformCompatibility.tsx | 4 +- frontend/interfaces/platform.ts | 14 +++-- .../cards/HostsSummary/HostsSummary.tsx | 20 +++---- .../HostsSummary/SummaryTile/_styles.scss | 1 - .../cards/HostsSummary/_styles.scss | 30 +++-------- frontend/pages/DashboardPage/helpers.ts | 0 frontend/utilities/constants.tsx | 52 ++++++++++++------- 7 files changed, 54 insertions(+), 67 deletions(-) delete mode 100644 frontend/pages/DashboardPage/helpers.ts diff --git a/frontend/components/PlatformCompatibility/PlatformCompatibility.tsx b/frontend/components/PlatformCompatibility/PlatformCompatibility.tsx index a48f973d41ba..82dd6780e7eb 100644 --- a/frontend/components/PlatformCompatibility/PlatformCompatibility.tsx +++ b/frontend/components/PlatformCompatibility/PlatformCompatibility.tsx @@ -1,6 +1,6 @@ import React from "react"; -import { DashboardOsqueryPlatform, OsqueryPlatform } from "interfaces/platform"; +import { DisplayPlatform, OsqueryPlatform } from "interfaces/platform"; import { PLATFORM_DISPLAY_NAMES } from "utilities/constants"; import TooltipWrapper from "components/TooltipWrapper"; @@ -24,7 +24,7 @@ const ERROR_NO_COMPATIBLE_TABLES = Error("no tables in query"); const formatPlatformsForDisplay = ( compatiblePlatforms: OsqueryPlatform[] -): DashboardOsqueryPlatform[] => { +): DisplayPlatform[] => { return compatiblePlatforms.map((str) => PLATFORM_DISPLAY_NAMES[str] || str); }; diff --git a/frontend/interfaces/platform.ts b/frontend/interfaces/platform.ts index 32d7114c5f9a..0d4704ac029c 100644 --- a/frontend/interfaces/platform.ts +++ b/frontend/interfaces/platform.ts @@ -1,14 +1,12 @@ -export type OsqueryPlatform = - | "darwin" +export type DisplayPlatform = | "macOS" - | "windows" | "Windows" - | "linux" | "Linux" - | "chrome" - | "ChromeOS"; + | "ChromeOS" + | "iOS" + | "iPadOS"; -export type DashboardOsqueryPlatform = OsqueryPlatform | "iOS" | "iPadOS"; +export type OsqueryPlatform = Exclude; export type SupportedPlatform = "darwin" | "windows" | "linux" | "chrome"; @@ -31,7 +29,7 @@ export type SelectedPlatformString = export type DashboardPlatform = SelectedPlatform | "ios" | "ipados"; // TODO: revisit this approach pending resolution of https://github.com/fleetdm/fleet/issues/3555. -export const MACADMINS_EXTENSION_TABLES: Record = { +export const MACADMINS_EXTENSION_TABLES: Record = { file_lines: ["darwin", "linux", "windows"], filevault_users: ["darwin"], google_chrome_profiles: ["darwin", "linux", "windows"], diff --git a/frontend/pages/DashboardPage/cards/HostsSummary/HostsSummary.tsx b/frontend/pages/DashboardPage/cards/HostsSummary/HostsSummary.tsx index 3845e81c1ca7..55c7b32690d5 100644 --- a/frontend/pages/DashboardPage/cards/HostsSummary/HostsSummary.tsx +++ b/frontend/pages/DashboardPage/cards/HostsSummary/HostsSummary.tsx @@ -137,7 +137,7 @@ const HostsSummary = ({ const renderIosCount = (teamId?: number) => { const iosLabelId = builtInLabels?.find( - (builtin) => builtin.name === PLATFORM_NAME_TO_LABEL_NAME.ios // TODO: change to ios + (builtin) => builtin.name === PLATFORM_NAME_TO_LABEL_NAME.ios )?.id; if (isLoadingHostsSummary || iosLabelId === undefined) { @@ -160,7 +160,7 @@ const HostsSummary = ({ const renderIpadosCount = (teamId?: number) => { const ipadosLabelId = builtInLabels?.find( - (builtin) => builtin.name === PLATFORM_NAME_TO_LABEL_NAME.ipados // TODO: change to ipados + (builtin) => builtin.name === PLATFORM_NAME_TO_LABEL_NAME.ipados )?.id; if (isLoadingHostsSummary || ipadosLabelId === undefined) { @@ -198,16 +198,12 @@ const HostsSummary = ({ default: return ( <> -
- {renderMacCount(teamId)} - {renderWindowsCount(teamId)} - {renderLinuxCount(teamId)} -
-
- {renderChromeCount(teamId)} - {renderIosCount(teamId)} - {renderIpadosCount(teamId)} -
+ {renderMacCount(teamId)} + {renderWindowsCount(teamId)} + {renderLinuxCount(teamId)} + {renderChromeCount(teamId)} + {renderIosCount(teamId)} + {renderIpadosCount(teamId)} ); } diff --git a/frontend/pages/DashboardPage/cards/HostsSummary/SummaryTile/_styles.scss b/frontend/pages/DashboardPage/cards/HostsSummary/SummaryTile/_styles.scss index e5cef444a638..3b7b73e82458 100644 --- a/frontend/pages/DashboardPage/cards/HostsSummary/SummaryTile/_styles.scss +++ b/frontend/pages/DashboardPage/cards/HostsSummary/SummaryTile/_styles.scss @@ -1,5 +1,4 @@ .summary-tile { - width: 100%; display: flex; justify-content: space-around; diff --git a/frontend/pages/DashboardPage/cards/HostsSummary/_styles.scss b/frontend/pages/DashboardPage/cards/HostsSummary/_styles.scss index 8c3a729a44ac..c5a6a566f091 100644 --- a/frontend/pages/DashboardPage/cards/HostsSummary/_styles.scss +++ b/frontend/pages/DashboardPage/cards/HostsSummary/_styles.scss @@ -2,37 +2,19 @@ margin-top: $pad-large; width: 100%; display: flex; - flex-direction: column; + flex-direction: row; justify-content: space-around; + flex-wrap: wrap; font-size: $x-small; gap: $pad-medium; - &__row { - display: flex; - justify-content: space-around; + .summary-tile { + flex: 1 1 30%; } - // Create a single row @media (min-width: $break-md) { - flex-direction: row; - gap: initial; - - &__row { - flex: 1 100%; - } - } - - &__tile { - flex-grow: 1; - display: flex; - justify-content: center; - align-items: center; - - &:first-of-type { - justify-content: flex-end; - } - &:last-of-type { - justify-content: flex-start; + .summary-tile { + flex: initial; } } diff --git a/frontend/pages/DashboardPage/helpers.ts b/frontend/pages/DashboardPage/helpers.ts deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/frontend/utilities/constants.tsx b/frontend/utilities/constants.tsx index 2a3c7c2ffdf0..41daf8d2eac3 100644 --- a/frontend/utilities/constants.tsx +++ b/frontend/utilities/constants.tsx @@ -1,5 +1,5 @@ import URL_PREFIX from "router/url_prefix"; -import { DashboardOsqueryPlatform } from "interfaces/platform"; +import { DisplayPlatform } from "interfaces/platform"; import paths from "router/paths"; import { ISchedulableQuery } from "interfaces/schedulable_query"; import React from "react"; @@ -212,10 +212,7 @@ export const isPlatformLabelNameFromAPI = ( return PLATFORM_LABEL_NAMES_FROM_API.includes(s as PlatformLabelNameFromAPI); }; -export const PLATFORM_DISPLAY_NAMES: Record< - string, - DashboardOsqueryPlatform -> = { +export const PLATFORM_DISPLAY_NAMES: Record = { darwin: "macOS", macOS: "macOS", windows: "Windows", @@ -285,19 +282,30 @@ export const hasPlatformTypeIcon = ( return !!PLATFORM_TYPE_ICONS[s as keyof typeof PLATFORM_TYPE_ICONS]; }; +type PlatformLabelOptions = + | "All" + | "Windows" + | "Linux" + | "macOS" + | "ChromeOS" + | "iOS" + | "iPadOS"; +type PlatformValueOptions = + | "all" + | "windows" + | "linux" + | "darwin" + | "chrome" + | "ios" + | "ipados" + | ""; interface IPlatformDropdownOptions { - label: "All" | "Windows" | "Linux" | "macOS" | "ChromeOS" | "iOS" | "iPadOS"; - value: - | "all" - | "windows" - | "linux" - | "darwin" - | "chrome" - | "ios" - | "ipados" - | ""; - path?: string; + label: PlatformLabelOptions; + value: PlatformValueOptions; + path: string; } + +/** Select platform on dashboard */ export const PLATFORM_DROPDOWN_OPTIONS: IPlatformDropdownOptions[] = [ { label: "All", value: "all", path: paths.DASHBOARD }, { label: "macOS", value: "darwin", path: paths.DASHBOARD_MAC }, @@ -308,17 +316,21 @@ export const PLATFORM_DROPDOWN_OPTIONS: IPlatformDropdownOptions[] = [ { label: "iPadOS", value: "ipados", path: paths.DASHBOARD_IPADOS }, ]; -// Scheduling queries do not support ChromeOS, iOS, or iPadOS -export const SCHEDULE_PLATFORM_DROPDOWN_OPTIONS: IPlatformDropdownOptions[] = [ +/** Scheduled queries do not support ChromeOS, iOS, or iPadOS */ +interface ISchedulePlatformDropdownOptions { + label: Exclude; + value: Exclude; +} + +export const SCHEDULE_PLATFORM_DROPDOWN_OPTIONS: ISchedulePlatformDropdownOptions[] = [ { label: "All", value: "" }, // API empty string runs on all platforms { label: "macOS", value: "darwin" }, { label: "Windows", value: "windows" }, { label: "Linux", value: "linux" }, ]; -// Builtin label names returned from API +/** Selected platform on dashboard mapped to built in label name */ export const PLATFORM_NAME_TO_LABEL_NAME = { - all: "", darwin: "macOS", windows: "MS Windows", linux: "All Linux", From 5cc4c651ba929c66c4ed687649e57e5d2017cc01 Mon Sep 17 00:00:00 2001 From: RachelElysia Date: Wed, 3 Jul 2024 11:42:52 -0400 Subject: [PATCH 09/13] Fix platform typing --- .../PlatformCompatibility.tsx | 12 +++++-- .../ColumnListItem/ColumnListItem.tsx | 9 +++-- .../QueryTablePlatforms.tsx | 3 +- frontend/hooks/usePlatformCompatibility.tsx | 4 +-- frontend/interfaces/osquery_table.ts | 8 +++-- .../pages/DashboardPage/DashboardPage.tsx | 10 +++--- .../cards/HostsSummary/HostsSummary.tsx | 2 +- frontend/pages/DashboardPage/helpers.tsx | 33 +++++++++++++++++++ frontend/pages/SoftwarePage/helpers.ts | 0 frontend/utilities/constants.tsx | 32 ++---------------- frontend/utilities/sql_tools.ts | 6 ++-- 11 files changed, 69 insertions(+), 50 deletions(-) create mode 100644 frontend/pages/DashboardPage/helpers.tsx delete mode 100644 frontend/pages/SoftwarePage/helpers.ts diff --git a/frontend/components/PlatformCompatibility/PlatformCompatibility.tsx b/frontend/components/PlatformCompatibility/PlatformCompatibility.tsx index 82dd6780e7eb..7e3982e29fcf 100644 --- a/frontend/components/PlatformCompatibility/PlatformCompatibility.tsx +++ b/frontend/components/PlatformCompatibility/PlatformCompatibility.tsx @@ -1,13 +1,17 @@ import React from "react"; -import { DisplayPlatform, OsqueryPlatform } from "interfaces/platform"; +import { + DisplayPlatform, + OsqueryPlatform, + SupportedPlatform, +} from "interfaces/platform"; import { PLATFORM_DISPLAY_NAMES } from "utilities/constants"; import TooltipWrapper from "components/TooltipWrapper"; import Icon from "components/Icon"; interface IPlatformCompatibilityProps { - compatiblePlatforms: OsqueryPlatform[] | null; + compatiblePlatforms: any[] | null; error: Error | null; } @@ -23,7 +27,7 @@ const DISPLAY_ORDER = [ const ERROR_NO_COMPATIBLE_TABLES = Error("no tables in query"); const formatPlatformsForDisplay = ( - compatiblePlatforms: OsqueryPlatform[] + compatiblePlatforms: SupportedPlatform[] ): DisplayPlatform[] => { return compatiblePlatforms.map((str) => PLATFORM_DISPLAY_NAMES[str] || str); }; @@ -52,6 +56,8 @@ const PlatformCompatibility = ({ return null; } + console.log("compatiblePlat", compatiblePlatforms); + const displayPlatforms = formatPlatformsForDisplay(compatiblePlatforms); const renderCompatiblePlatforms = () => { diff --git a/frontend/components/side_panels/QuerySidePanel/QueryTableColumns/ColumnListItem/ColumnListItem.tsx b/frontend/components/side_panels/QuerySidePanel/QueryTableColumns/ColumnListItem/ColumnListItem.tsx index fa67493864f4..efdbbabbf73a 100644 --- a/frontend/components/side_panels/QuerySidePanel/QueryTableColumns/ColumnListItem/ColumnListItem.tsx +++ b/frontend/components/side_panels/QuerySidePanel/QueryTableColumns/ColumnListItem/ColumnListItem.tsx @@ -1,10 +1,13 @@ import React from "react"; import classnames from "classnames"; -import { ColumnType, IQueryTableColumn } from "interfaces/osquery_table"; +import { + ColumnType, + IQueryTableColumn, + TableSchemaPlatforms, +} from "interfaces/osquery_table"; import TooltipWrapper from "components/TooltipWrapper"; import { buildQueryStringFromParams } from "utilities/url"; -import { OsqueryPlatform } from "interfaces/platform"; interface IColumnListItemProps { column: IQueryTableColumn; @@ -55,7 +58,7 @@ const renderTooltip = ( ); }; - const renderPlatformFootnotes = (columnPlatforms: OsqueryPlatform[]) => { + const renderPlatformFootnotes = (columnPlatforms: TableSchemaPlatforms[]) => { let platformsCopy; switch (columnPlatforms.length) { case 1: diff --git a/frontend/components/side_panels/QuerySidePanel/QueryTablePlatforms/QueryTablePlatforms.tsx b/frontend/components/side_panels/QuerySidePanel/QueryTablePlatforms/QueryTablePlatforms.tsx index c517e213505c..39804b43df4d 100644 --- a/frontend/components/side_panels/QuerySidePanel/QueryTablePlatforms/QueryTablePlatforms.tsx +++ b/frontend/components/side_panels/QuerySidePanel/QueryTablePlatforms/QueryTablePlatforms.tsx @@ -3,6 +3,7 @@ import React from "react"; import { OsqueryPlatform } from "interfaces/platform"; import { PLATFORM_DISPLAY_NAMES } from "utilities/constants"; import Icon from "components/Icon"; +import { TableSchemaPlatforms } from "interfaces/osquery_table"; interface IPLatformListItemProps { platform: OsqueryPlatform; @@ -20,7 +21,7 @@ const PlatformListItem = ({ platform }: IPLatformListItemProps) => { }; // TODO: remove when freebsd is removed -type IPlatformsWithFreebsd = OsqueryPlatform | "freebsd"; +type IPlatformsWithFreebsd = TableSchemaPlatforms | "freebsd"; interface IQueryTablePlatformsProps { platforms: IPlatformsWithFreebsd[]; diff --git a/frontend/hooks/usePlatformCompatibility.tsx b/frontend/hooks/usePlatformCompatibility.tsx index 15fa948d33d7..a5c447131f3d 100644 --- a/frontend/hooks/usePlatformCompatibility.tsx +++ b/frontend/hooks/usePlatformCompatibility.tsx @@ -1,7 +1,7 @@ import React, { useCallback, useState } from "react"; import { useDebouncedCallback } from "use-debounce"; -import { OsqueryPlatform, SUPPORTED_PLATFORMS } from "interfaces/platform"; +import { SupportedPlatform, SUPPORTED_PLATFORMS } from "interfaces/platform"; import { checkPlatformCompatibility } from "utilities/sql_tools"; import PlatformCompatibility from "components/PlatformCompatibility"; @@ -16,7 +16,7 @@ const DEBOUNCE_DELAY = 300; const usePlatformCompatibility = (): IPlatformCompatibility => { const [compatiblePlatforms, setCompatiblePlatforms] = useState< - OsqueryPlatform[] | null + SupportedPlatform[] | null >(null); const [error, setError] = useState(null); diff --git a/frontend/interfaces/osquery_table.ts b/frontend/interfaces/osquery_table.ts index 3befc8f40305..34fa8b7f0742 100644 --- a/frontend/interfaces/osquery_table.ts +++ b/frontend/interfaces/osquery_table.ts @@ -1,5 +1,5 @@ import PropTypes from "prop-types"; -import { OsqueryPlatform } from "./platform"; +import { SupportedPlatform, OsqueryPlatform } from "./platform"; export default PropTypes.shape({ columns: PropTypes.arrayOf( @@ -23,6 +23,8 @@ export type ColumnType = | "STRING" | "string"; // TODO: Why do we have type string, STRING, and text in schema.json? +// TODO: Replace with one or the other once osquery_fleet_schema.json follows one type or other +export type TableSchemaPlatforms = OsqueryPlatform | SupportedPlatform; export interface IQueryTableColumn { name: string; description: string; @@ -30,7 +32,7 @@ export interface IQueryTableColumn { hidden: boolean; required: boolean; index: boolean; - platforms?: OsqueryPlatform[]; + platforms?: TableSchemaPlatforms[]; requires_user_context?: boolean; } @@ -38,7 +40,7 @@ export interface IOsQueryTable { name: string; description: string; url: string; - platforms: OsqueryPlatform[]; + platforms: TableSchemaPlatforms[]; evented: boolean; cacheable: boolean; columns: IQueryTableColumn[]; diff --git a/frontend/pages/DashboardPage/DashboardPage.tsx b/frontend/pages/DashboardPage/DashboardPage.tsx index 91e9c50331e3..a88a641c941b 100644 --- a/frontend/pages/DashboardPage/DashboardPage.tsx +++ b/frontend/pages/DashboardPage/DashboardPage.tsx @@ -48,11 +48,7 @@ import configAPI from "services/entities/config"; import hosts from "services/entities/hosts"; import sortUtils from "utilities/sort"; -import { - DEFAULT_USE_QUERY_OPTIONS, - PLATFORM_DROPDOWN_OPTIONS, - PLATFORM_NAME_TO_LABEL_NAME, -} from "utilities/constants"; +import { DEFAULT_USE_QUERY_OPTIONS } from "utilities/constants"; import { ITableQueryData } from "components/TableContainer/TableContainer"; @@ -64,6 +60,10 @@ import Dropdown from "components/forms/fields/Dropdown"; import MainContent from "components/MainContent"; import LastUpdatedText from "components/LastUpdatedText"; +import { + PLATFORM_DROPDOWN_OPTIONS, + PLATFORM_NAME_TO_LABEL_NAME, +} from "./helpers"; import useInfoCard from "./components/InfoCard"; import MissingHosts from "./cards/MissingHosts"; import LowDiskSpaceHosts from "./cards/LowDiskSpaceHosts"; diff --git a/frontend/pages/DashboardPage/cards/HostsSummary/HostsSummary.tsx b/frontend/pages/DashboardPage/cards/HostsSummary/HostsSummary.tsx index 55c7b32690d5..098d44f894e7 100644 --- a/frontend/pages/DashboardPage/cards/HostsSummary/HostsSummary.tsx +++ b/frontend/pages/DashboardPage/cards/HostsSummary/HostsSummary.tsx @@ -1,7 +1,7 @@ import React from "react"; import PATHS from "router/paths"; -import { PLATFORM_NAME_TO_LABEL_NAME } from "utilities/constants"; +import { PLATFORM_NAME_TO_LABEL_NAME } from "pages/DashboardPage/helpers"; import DataError from "components/DataError"; import { DashboardPlatform } from "interfaces/platform"; import { IHostSummary } from "interfaces/host_summary"; diff --git a/frontend/pages/DashboardPage/helpers.tsx b/frontend/pages/DashboardPage/helpers.tsx new file mode 100644 index 000000000000..b0682ae4318e --- /dev/null +++ b/frontend/pages/DashboardPage/helpers.tsx @@ -0,0 +1,33 @@ +import paths from "router/paths"; + +import { + PlatformLabelOptions, + PlatformValueOptions, +} from "utilities/constants"; + +interface IPlatformDropdownOptions { + label: PlatformLabelOptions; + value: PlatformValueOptions; + path: string; +} + +/** Select platform */ +export const PLATFORM_DROPDOWN_OPTIONS: IPlatformDropdownOptions[] = [ + { label: "All", value: "all", path: paths.DASHBOARD }, + { label: "macOS", value: "darwin", path: paths.DASHBOARD_MAC }, + { label: "Windows", value: "windows", path: paths.DASHBOARD_WINDOWS }, + { label: "Linux", value: "linux", path: paths.DASHBOARD_LINUX }, + { label: "ChromeOS", value: "chrome", path: paths.DASHBOARD_CHROME }, + { label: "iOS", value: "ios", path: paths.DASHBOARD_IOS }, + { label: "iPadOS", value: "ipados", path: paths.DASHBOARD_IPADOS }, +]; + +/** Selected platform value mapped to built in label name */ +export const PLATFORM_NAME_TO_LABEL_NAME = { + darwin: "macOS", + windows: "MS Windows", + linux: "All Linux", + chrome: "chrome", + ios: "iOS", + ipados: "iPadOS", +}; diff --git a/frontend/pages/SoftwarePage/helpers.ts b/frontend/pages/SoftwarePage/helpers.ts deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/frontend/utilities/constants.tsx b/frontend/utilities/constants.tsx index 41daf8d2eac3..3c46d16c4bf0 100644 --- a/frontend/utilities/constants.tsx +++ b/frontend/utilities/constants.tsx @@ -1,6 +1,5 @@ import URL_PREFIX from "router/url_prefix"; import { DisplayPlatform } from "interfaces/platform"; -import paths from "router/paths"; import { ISchedulableQuery } from "interfaces/schedulable_query"; import React from "react"; import { IDropdownOption } from "interfaces/dropdownOption"; @@ -282,7 +281,7 @@ export const hasPlatformTypeIcon = ( return !!PLATFORM_TYPE_ICONS[s as keyof typeof PLATFORM_TYPE_ICONS]; }; -type PlatformLabelOptions = +export type PlatformLabelOptions = | "All" | "Windows" | "Linux" @@ -290,7 +289,8 @@ type PlatformLabelOptions = | "ChromeOS" | "iOS" | "iPadOS"; -type PlatformValueOptions = + +export type PlatformValueOptions = | "all" | "windows" | "linux" @@ -299,22 +299,6 @@ type PlatformValueOptions = | "ios" | "ipados" | ""; -interface IPlatformDropdownOptions { - label: PlatformLabelOptions; - value: PlatformValueOptions; - path: string; -} - -/** Select platform on dashboard */ -export const PLATFORM_DROPDOWN_OPTIONS: IPlatformDropdownOptions[] = [ - { label: "All", value: "all", path: paths.DASHBOARD }, - { label: "macOS", value: "darwin", path: paths.DASHBOARD_MAC }, - { label: "Windows", value: "windows", path: paths.DASHBOARD_WINDOWS }, - { label: "Linux", value: "linux", path: paths.DASHBOARD_LINUX }, - { label: "ChromeOS", value: "chrome", path: paths.DASHBOARD_CHROME }, - { label: "iOS", value: "ios", path: paths.DASHBOARD_IOS }, - { label: "iPadOS", value: "ipados", path: paths.DASHBOARD_IPADOS }, -]; /** Scheduled queries do not support ChromeOS, iOS, or iPadOS */ interface ISchedulePlatformDropdownOptions { @@ -329,16 +313,6 @@ export const SCHEDULE_PLATFORM_DROPDOWN_OPTIONS: ISchedulePlatformDropdownOption { label: "Linux", value: "linux" }, ]; -/** Selected platform on dashboard mapped to built in label name */ -export const PLATFORM_NAME_TO_LABEL_NAME = { - darwin: "macOS", - windows: "MS Windows", - linux: "All Linux", - chrome: "chrome", - ios: "iOS", - ipados: "iPadOS", -}; - export const HOSTS_SEARCH_BOX_PLACEHOLDER = "Search name, hostname, UUID, serial number, or private IP address"; diff --git a/frontend/utilities/sql_tools.ts b/frontend/utilities/sql_tools.ts index e8255767af90..e1890f8abea6 100644 --- a/frontend/utilities/sql_tools.ts +++ b/frontend/utilities/sql_tools.ts @@ -3,11 +3,11 @@ import sqliteParser from "sqlite-parser"; import { intersection, isPlainObject } from "lodash"; import { osqueryTablesAvailable } from "utilities/osquery_tables"; import { - OsqueryPlatform, MACADMINS_EXTENSION_TABLES, SUPPORTED_PLATFORMS, SupportedPlatform, } from "interfaces/platform"; +import { TableSchemaPlatforms } from "interfaces/osquery_table"; type IAstNode = Record; @@ -15,10 +15,10 @@ type IAstNode = Record; // TODO: Is it ever possible that osquery_tables.json would be missing name or platforms? interface IOsqueryTable { name: string; - platforms: OsqueryPlatform[]; + platforms: TableSchemaPlatforms[]; } -type IPlatformDictionary = Record; +type IPlatformDictionary = Record; const platformsByTableDictionary: IPlatformDictionary = (osqueryTablesAvailable as IOsqueryTable[]).reduce( (dictionary: IPlatformDictionary, osqueryTable) => { From e5c27a403ae8c7e4c84ce5966afe919d3593ed58 Mon Sep 17 00:00:00 2001 From: RachelElysia Date: Wed, 3 Jul 2024 12:22:58 -0400 Subject: [PATCH 10/13] Final updates to platform interfaces --- .../PlatformCompatibility.tsx | 4 +-- .../DataTable/PlatformCell/PlatformCell.tsx | 2 +- .../QueryTablePlatforms.tsx | 6 ++--- frontend/hooks/usePlatformCompatibility.tsx | 2 +- frontend/hooks/usePlatformSelector.tsx | 3 ++- frontend/interfaces/osquery_table.ts | 4 +-- frontend/interfaces/platform.ts | 17 ++++++++++--- .../pages/DashboardPage/DashboardPage.tsx | 14 +++++++---- .../cards/HostsSummary/HostsSummary.tsx | 4 +-- .../OperatingSystems/OperatingSystems.tsx | 11 +++++--- frontend/services/entities/hosts.ts | 7 +++--- .../services/entities/operating_systems.ts | 4 +-- frontend/utilities/constants.tsx | 25 ++++--------------- 13 files changed, 52 insertions(+), 51 deletions(-) diff --git a/frontend/components/PlatformCompatibility/PlatformCompatibility.tsx b/frontend/components/PlatformCompatibility/PlatformCompatibility.tsx index 7e3982e29fcf..c8e595370ab8 100644 --- a/frontend/components/PlatformCompatibility/PlatformCompatibility.tsx +++ b/frontend/components/PlatformCompatibility/PlatformCompatibility.tsx @@ -2,7 +2,7 @@ import React from "react"; import { DisplayPlatform, - OsqueryPlatform, + SupportedDisplayPlatform, SupportedPlatform, } from "interfaces/platform"; import { PLATFORM_DISPLAY_NAMES } from "utilities/constants"; @@ -22,7 +22,7 @@ const DISPLAY_ORDER = [ "Windows", "Linux", "ChromeOS", -] as OsqueryPlatform[]; +] as SupportedDisplayPlatform[]; const ERROR_NO_COMPATIBLE_TABLES = Error("no tables in query"); diff --git a/frontend/components/TableContainer/DataTable/PlatformCell/PlatformCell.tsx b/frontend/components/TableContainer/DataTable/PlatformCell/PlatformCell.tsx index 48665040c643..b81901218f95 100644 --- a/frontend/components/TableContainer/DataTable/PlatformCell/PlatformCell.tsx +++ b/frontend/components/TableContainer/DataTable/PlatformCell/PlatformCell.tsx @@ -9,7 +9,7 @@ interface IPlatformCellProps { const baseClass = "platform-cell"; -const ICONS: Record = { +const ICONS: Record = { darwin: "darwin", windows: "windows", linux: "linux", diff --git a/frontend/components/side_panels/QuerySidePanel/QueryTablePlatforms/QueryTablePlatforms.tsx b/frontend/components/side_panels/QuerySidePanel/QueryTablePlatforms/QueryTablePlatforms.tsx index 39804b43df4d..188e8cb3bc70 100644 --- a/frontend/components/side_panels/QuerySidePanel/QueryTablePlatforms/QueryTablePlatforms.tsx +++ b/frontend/components/side_panels/QuerySidePanel/QueryTablePlatforms/QueryTablePlatforms.tsx @@ -1,12 +1,12 @@ import React from "react"; -import { OsqueryPlatform } from "interfaces/platform"; +import { SupportedDisplayPlatform } from "interfaces/platform"; import { PLATFORM_DISPLAY_NAMES } from "utilities/constants"; import Icon from "components/Icon"; import { TableSchemaPlatforms } from "interfaces/osquery_table"; interface IPLatformListItemProps { - platform: OsqueryPlatform; + platform: SupportedDisplayPlatform; } const baseClassListItem = "platform-list-item"; @@ -39,7 +39,7 @@ const QueryTablePlatforms = ({ platforms }: IQueryTablePlatformsProps) => { return ( ); }); diff --git a/frontend/hooks/usePlatformCompatibility.tsx b/frontend/hooks/usePlatformCompatibility.tsx index a5c447131f3d..7569d2b6197b 100644 --- a/frontend/hooks/usePlatformCompatibility.tsx +++ b/frontend/hooks/usePlatformCompatibility.tsx @@ -7,7 +7,7 @@ import { checkPlatformCompatibility } from "utilities/sql_tools"; import PlatformCompatibility from "components/PlatformCompatibility"; export interface IPlatformCompatibility { - getCompatiblePlatforms: () => ("darwin" | "windows" | "linux" | "chrome")[]; + getCompatiblePlatforms: () => SupportedPlatform[]; setCompatiblePlatforms: (sqlString: string) => void; render: () => JSX.Element; } diff --git a/frontend/hooks/usePlatformSelector.tsx b/frontend/hooks/usePlatformSelector.tsx index 0583f16ec37f..497516259e33 100644 --- a/frontend/hooks/usePlatformSelector.tsx +++ b/frontend/hooks/usePlatformSelector.tsx @@ -4,13 +4,14 @@ import { forEach } from "lodash"; import { SelectedPlatformString, SUPPORTED_PLATFORMS, + SupportedPlatform, } from "interfaces/platform"; import PlatformSelector from "components/PlatformSelector"; export interface IPlatformSelector { setSelectedPlatforms: (platforms: string[]) => void; - getSelectedPlatforms: () => ("darwin" | "windows" | "linux" | "chrome")[]; + getSelectedPlatforms: () => SupportedPlatform[]; isAnyPlatformSelected: boolean; render: () => JSX.Element; disabled?: boolean; diff --git a/frontend/interfaces/osquery_table.ts b/frontend/interfaces/osquery_table.ts index 34fa8b7f0742..6ce07c85315a 100644 --- a/frontend/interfaces/osquery_table.ts +++ b/frontend/interfaces/osquery_table.ts @@ -1,5 +1,5 @@ import PropTypes from "prop-types"; -import { SupportedPlatform, OsqueryPlatform } from "./platform"; +import { SupportedPlatform, SupportedDisplayPlatform } from "./platform"; export default PropTypes.shape({ columns: PropTypes.arrayOf( @@ -24,7 +24,7 @@ export type ColumnType = | "string"; // TODO: Why do we have type string, STRING, and text in schema.json? // TODO: Replace with one or the other once osquery_fleet_schema.json follows one type or other -export type TableSchemaPlatforms = OsqueryPlatform | SupportedPlatform; +export type TableSchemaPlatforms = SupportedDisplayPlatform | SupportedPlatform; export interface IQueryTableColumn { name: string; description: string; diff --git a/frontend/interfaces/platform.ts b/frontend/interfaces/platform.ts index 0d4704ac029c..13815dd82d1b 100644 --- a/frontend/interfaces/platform.ts +++ b/frontend/interfaces/platform.ts @@ -6,9 +6,20 @@ export type DisplayPlatform = | "iOS" | "iPadOS"; -export type OsqueryPlatform = Exclude; +export type Platform = + | "darwin" + | "windows" + | "linux" + | "chrome" + | "ios" + | "ipados"; -export type SupportedPlatform = "darwin" | "windows" | "linux" | "chrome"; +export type SupportedDisplayPlatform = Exclude< + DisplayPlatform, + "iOS" | "iPadOS" +>; + +export type SupportedPlatform = Exclude; export const SUPPORTED_PLATFORMS: SupportedPlatform[] = [ "darwin", @@ -26,8 +37,6 @@ export type SelectedPlatformString = | `${SupportedPlatform},${SupportedPlatform},${SupportedPlatform}` | `${SupportedPlatform},${SupportedPlatform},${SupportedPlatform},${SupportedPlatform}`; -export type DashboardPlatform = SelectedPlatform | "ios" | "ipados"; - // TODO: revisit this approach pending resolution of https://github.com/fleetdm/fleet/issues/3555. export const MACADMINS_EXTENSION_TABLES: Record = { file_lines: ["darwin", "linux", "windows"], diff --git a/frontend/pages/DashboardPage/DashboardPage.tsx b/frontend/pages/DashboardPage/DashboardPage.tsx index a88a641c941b..2d84c01f80ea 100644 --- a/frontend/pages/DashboardPage/DashboardPage.tsx +++ b/frontend/pages/DashboardPage/DashboardPage.tsx @@ -29,7 +29,7 @@ import { IMdmSummaryResponse, IMdmSummaryMdmSolution, } from "interfaces/mdm"; -import { DashboardPlatform, SelectedPlatform } from "interfaces/platform"; +import { Platform, SelectedPlatform } from "interfaces/platform"; import { ISoftwareResponse, ISoftwareCountResponse } from "interfaces/software"; import { API_ALL_TEAMS_ID, ITeam } from "interfaces/team"; import { IConfig } from "interfaces/config"; @@ -48,7 +48,10 @@ import configAPI from "services/entities/config"; import hosts from "services/entities/hosts"; import sortUtils from "utilities/sort"; -import { DEFAULT_USE_QUERY_OPTIONS } from "utilities/constants"; +import { + DEFAULT_USE_QUERY_OPTIONS, + PlatformValueOptions, +} from "utilities/constants"; import { ITableQueryData } from "components/TableContainer/TableContainer"; @@ -124,9 +127,10 @@ const DashboardPage = ({ router, location }: IDashboardProps): JSX.Element => { includeNoTeam: false, }); - const [selectedPlatform, setSelectedPlatform] = useState( - "all" - ); + const [ + selectedPlatform, + setSelectedPlatform, + ] = useState("all"); const [ selectedPlatformLabelId, setSelectedPlatformLabelId, diff --git a/frontend/pages/DashboardPage/cards/HostsSummary/HostsSummary.tsx b/frontend/pages/DashboardPage/cards/HostsSummary/HostsSummary.tsx index 098d44f894e7..764491d55c4c 100644 --- a/frontend/pages/DashboardPage/cards/HostsSummary/HostsSummary.tsx +++ b/frontend/pages/DashboardPage/cards/HostsSummary/HostsSummary.tsx @@ -3,8 +3,8 @@ import PATHS from "router/paths"; import { PLATFORM_NAME_TO_LABEL_NAME } from "pages/DashboardPage/helpers"; import DataError from "components/DataError"; -import { DashboardPlatform } from "interfaces/platform"; import { IHostSummary } from "interfaces/host_summary"; +import { PlatformValueOptions } from "utilities/constants"; import SummaryTile from "./SummaryTile"; @@ -22,7 +22,7 @@ interface IHostSummaryProps { builtInLabels?: IHostSummary["builtin_labels"]; showHostsUI: boolean; errorHosts: boolean; - selectedPlatform?: DashboardPlatform; + selectedPlatform?: PlatformValueOptions; } const HostsSummary = ({ diff --git a/frontend/pages/DashboardPage/cards/OperatingSystems/OperatingSystems.tsx b/frontend/pages/DashboardPage/cards/OperatingSystems/OperatingSystems.tsx index afe3999a496d..8751d1ff30c0 100644 --- a/frontend/pages/DashboardPage/cards/OperatingSystems/OperatingSystems.tsx +++ b/frontend/pages/DashboardPage/cards/OperatingSystems/OperatingSystems.tsx @@ -5,14 +5,17 @@ import { OS_END_OF_LIFE_LINK_BY_PLATFORM, OS_VENDOR_BY_PLATFORM, } from "interfaces/operating_system"; -import { DashboardPlatform } from "interfaces/platform"; +import { Platform } from "interfaces/platform"; import { getOSVersions, IGetOSVersionsQueryKey, IOSVersionsResponse, OS_VERSIONS_API_SUPPORTED_PLATFORMS, } from "services/entities/operating_systems"; -import { PLATFORM_DISPLAY_NAMES } from "utilities/constants"; +import { + PLATFORM_DISPLAY_NAMES, + PlatformValueOptions, +} from "utilities/constants"; import TableContainer from "components/TableContainer"; import Spinner from "components/Spinner"; @@ -26,7 +29,7 @@ import generateTableHeaders from "./OperatingSystemsTableConfig"; interface IOperatingSystemsCardProps { currentTeamId: number | undefined; - selectedPlatform: DashboardPlatform; + selectedPlatform: PlatformValueOptions; showTitle: boolean; /** controls the displaying of description text under the title. Defaults to `true` */ showDescription?: boolean; @@ -42,7 +45,7 @@ const DEFAULT_SORT_HEADER = "hosts_count"; const PAGE_SIZE = 8; const baseClass = "operating-systems"; -const EmptyOperatingSystems = (platform: DashboardPlatform): JSX.Element => ( +const EmptyOperatingSystems = (platform: PlatformValueOptions): JSX.Element => ( { }; }; -const createMdmParams = (platform?: DashboardPlatform, teamId?: number) => { +const createMdmParams = (platform?: PlatformValueOptions, teamId?: number) => { if (platform === "all") { return buildQueryStringFromParams({ team_id: teamId }); } @@ -535,7 +534,7 @@ export default { return sendRequest("GET", HOST_MDM(id)); }, - getMdmSummary: (platform?: DashboardPlatform, teamId?: number) => { + getMdmSummary: (platform?: PlatformValueOptions, teamId?: number) => { const { MDM_SUMMARY } = endpoints; if (!platform || platform === "linux") { diff --git a/frontend/services/entities/operating_systems.ts b/frontend/services/entities/operating_systems.ts index 3f5bffd74db7..92e11937de29 100644 --- a/frontend/services/entities/operating_systems.ts +++ b/frontend/services/entities/operating_systems.ts @@ -2,7 +2,7 @@ import sendRequest from "services"; import endpoints from "utilities/endpoints"; import { IOperatingSystemVersion } from "interfaces/operating_system"; -import { DashboardPlatform } from "interfaces/platform"; +import { Platform } from "interfaces/platform"; import { buildQueryStringFromParams } from "utilities/url"; import { API_NO_TEAM_ID } from "interfaces/team"; @@ -14,7 +14,7 @@ export const OS_VERSIONS_API_SUPPORTED_PLATFORMS = [ ]; export interface IGetOSVersionsQueryParams { - platform?: DashboardPlatform; + platform?: Platform | ""; teamId?: number; os_name?: string; os_version?: string; diff --git a/frontend/utilities/constants.tsx b/frontend/utilities/constants.tsx index 3c46d16c4bf0..b3267c4580a4 100644 --- a/frontend/utilities/constants.tsx +++ b/frontend/utilities/constants.tsx @@ -1,5 +1,5 @@ import URL_PREFIX from "router/url_prefix"; -import { DisplayPlatform } from "interfaces/platform"; +import { DisplayPlatform, Platform } from "interfaces/platform"; import { ISchedulableQuery } from "interfaces/schedulable_query"; import React from "react"; import { IDropdownOption } from "interfaces/dropdownOption"; @@ -281,29 +281,14 @@ export const hasPlatformTypeIcon = ( return !!PLATFORM_TYPE_ICONS[s as keyof typeof PLATFORM_TYPE_ICONS]; }; -export type PlatformLabelOptions = - | "All" - | "Windows" - | "Linux" - | "macOS" - | "ChromeOS" - | "iOS" - | "iPadOS"; - -export type PlatformValueOptions = - | "all" - | "windows" - | "linux" - | "darwin" - | "chrome" - | "ios" - | "ipados" - | ""; +export type PlatformLabelOptions = DisplayPlatform | "All"; + +export type PlatformValueOptions = Platform | "all"; /** Scheduled queries do not support ChromeOS, iOS, or iPadOS */ interface ISchedulePlatformDropdownOptions { label: Exclude; - value: Exclude; + value: Exclude | ""; } export const SCHEDULE_PLATFORM_DROPDOWN_OPTIONS: ISchedulePlatformDropdownOptions[] = [ From a6f7ed541c6081192d8d74b1863466efb9dfb6cc Mon Sep 17 00:00:00 2001 From: RachelElysia Date: Wed, 3 Jul 2024 12:45:23 -0400 Subject: [PATCH 11/13] Interface cleanup, casing bug, hook up os_versions API call, show os settings modal --- .../QueryTableColumns/ColumnListItem/ColumnListItem.tsx | 4 ++-- .../QueryTablePlatforms/QueryTablePlatforms.tsx | 9 ++++----- frontend/interfaces/osquery_table.ts | 6 +++--- frontend/pages/DashboardPage/DashboardPage.tsx | 3 +-- .../OSSettingsTable/OSSettingsTableConfig.tsx | 4 ++++ frontend/services/entities/operating_systems.ts | 2 ++ frontend/utilities/sql_tools.ts | 6 +++--- frontend/utilities/strings/stringUtils.ts | 4 +++- 8 files changed, 22 insertions(+), 16 deletions(-) diff --git a/frontend/components/side_panels/QuerySidePanel/QueryTableColumns/ColumnListItem/ColumnListItem.tsx b/frontend/components/side_panels/QuerySidePanel/QueryTableColumns/ColumnListItem/ColumnListItem.tsx index efdbbabbf73a..8a061ca4a92d 100644 --- a/frontend/components/side_panels/QuerySidePanel/QueryTableColumns/ColumnListItem/ColumnListItem.tsx +++ b/frontend/components/side_panels/QuerySidePanel/QueryTableColumns/ColumnListItem/ColumnListItem.tsx @@ -4,7 +4,7 @@ import classnames from "classnames"; import { ColumnType, IQueryTableColumn, - TableSchemaPlatforms, + TableSchemaPlatform, } from "interfaces/osquery_table"; import TooltipWrapper from "components/TooltipWrapper"; import { buildQueryStringFromParams } from "utilities/url"; @@ -58,7 +58,7 @@ const renderTooltip = ( ); }; - const renderPlatformFootnotes = (columnPlatforms: TableSchemaPlatforms[]) => { + const renderPlatformFootnotes = (columnPlatforms: TableSchemaPlatform[]) => { let platformsCopy; switch (columnPlatforms.length) { case 1: diff --git a/frontend/components/side_panels/QuerySidePanel/QueryTablePlatforms/QueryTablePlatforms.tsx b/frontend/components/side_panels/QuerySidePanel/QueryTablePlatforms/QueryTablePlatforms.tsx index 188e8cb3bc70..7b63f253d6a7 100644 --- a/frontend/components/side_panels/QuerySidePanel/QueryTablePlatforms/QueryTablePlatforms.tsx +++ b/frontend/components/side_panels/QuerySidePanel/QueryTablePlatforms/QueryTablePlatforms.tsx @@ -1,12 +1,11 @@ import React from "react"; -import { SupportedDisplayPlatform } from "interfaces/platform"; import { PLATFORM_DISPLAY_NAMES } from "utilities/constants"; import Icon from "components/Icon"; -import { TableSchemaPlatforms } from "interfaces/osquery_table"; +import { TableSchemaPlatform } from "interfaces/osquery_table"; interface IPLatformListItemProps { - platform: SupportedDisplayPlatform; + platform: TableSchemaPlatform; } const baseClassListItem = "platform-list-item"; @@ -21,7 +20,7 @@ const PlatformListItem = ({ platform }: IPLatformListItemProps) => { }; // TODO: remove when freebsd is removed -type IPlatformsWithFreebsd = TableSchemaPlatforms | "freebsd"; +type IPlatformsWithFreebsd = TableSchemaPlatform | "freebsd"; interface IQueryTablePlatformsProps { platforms: IPlatformsWithFreebsd[]; @@ -39,7 +38,7 @@ const QueryTablePlatforms = ({ platforms }: IQueryTablePlatformsProps) => { return ( ); }); diff --git a/frontend/interfaces/osquery_table.ts b/frontend/interfaces/osquery_table.ts index 6ce07c85315a..1166d75a7db5 100644 --- a/frontend/interfaces/osquery_table.ts +++ b/frontend/interfaces/osquery_table.ts @@ -24,7 +24,7 @@ export type ColumnType = | "string"; // TODO: Why do we have type string, STRING, and text in schema.json? // TODO: Replace with one or the other once osquery_fleet_schema.json follows one type or other -export type TableSchemaPlatforms = SupportedDisplayPlatform | SupportedPlatform; +export type TableSchemaPlatform = SupportedDisplayPlatform | SupportedPlatform; export interface IQueryTableColumn { name: string; description: string; @@ -32,7 +32,7 @@ export interface IQueryTableColumn { hidden: boolean; required: boolean; index: boolean; - platforms?: TableSchemaPlatforms[]; + platforms?: TableSchemaPlatform[]; requires_user_context?: boolean; } @@ -40,7 +40,7 @@ export interface IOsQueryTable { name: string; description: string; url: string; - platforms: TableSchemaPlatforms[]; + platforms: TableSchemaPlatform[]; evented: boolean; cacheable: boolean; columns: IQueryTableColumn[]; diff --git a/frontend/pages/DashboardPage/DashboardPage.tsx b/frontend/pages/DashboardPage/DashboardPage.tsx index 2d84c01f80ea..321ba4c2c7db 100644 --- a/frontend/pages/DashboardPage/DashboardPage.tsx +++ b/frontend/pages/DashboardPage/DashboardPage.tsx @@ -29,7 +29,6 @@ import { IMdmSummaryResponse, IMdmSummaryMdmSolution, } from "interfaces/mdm"; -import { Platform, SelectedPlatform } from "interfaces/platform"; import { ISoftwareResponse, ISoftwareCountResponse } from "interfaces/software"; import { API_ALL_TEAMS_ID, ITeam } from "interfaces/team"; import { IConfig } from "interfaces/config"; @@ -886,7 +885,7 @@ const DashboardPage = ({ router, location }: IDashboardProps): JSX.Element => { className={`${baseClass}__platform_dropdown`} options={PLATFORM_DROPDOWN_OPTIONS} searchable={false} - onChange={(value: SelectedPlatform) => { + onChange={(value: PlatformValueOptions) => { const selectedPlatformOption = PLATFORM_DROPDOWN_OPTIONS.find( (platform) => platform.value === value ); diff --git a/frontend/pages/hosts/details/OSSettingsModal/OSSettingsTable/OSSettingsTableConfig.tsx b/frontend/pages/hosts/details/OSSettingsModal/OSSettingsTable/OSSettingsTableConfig.tsx index badef6d0b790..197c8603ccca 100644 --- a/frontend/pages/hosts/details/OSSettingsModal/OSSettingsTable/OSSettingsTableConfig.tsx +++ b/frontend/pages/hosts/details/OSSettingsModal/OSSettingsTable/OSSettingsTableConfig.tsx @@ -146,6 +146,10 @@ export const generateTableData = ( return makeWindowsRows(hostMDMData); case "darwin": return makeDarwinRows(hostMDMData); + case "ios": + return hostMDMData.profiles; + case "ipados": + return hostMDMData.profiles; default: return null; } diff --git a/frontend/services/entities/operating_systems.ts b/frontend/services/entities/operating_systems.ts index 92e11937de29..1611243bfd91 100644 --- a/frontend/services/entities/operating_systems.ts +++ b/frontend/services/entities/operating_systems.ts @@ -11,6 +11,8 @@ export const OS_VERSIONS_API_SUPPORTED_PLATFORMS = [ "darwin", "windows", "chrome", + "ios", + "ipados", ]; export interface IGetOSVersionsQueryParams { diff --git a/frontend/utilities/sql_tools.ts b/frontend/utilities/sql_tools.ts index e1890f8abea6..71dc64333383 100644 --- a/frontend/utilities/sql_tools.ts +++ b/frontend/utilities/sql_tools.ts @@ -7,7 +7,7 @@ import { SUPPORTED_PLATFORMS, SupportedPlatform, } from "interfaces/platform"; -import { TableSchemaPlatforms } from "interfaces/osquery_table"; +import { TableSchemaPlatform } from "interfaces/osquery_table"; type IAstNode = Record; @@ -15,10 +15,10 @@ type IAstNode = Record; // TODO: Is it ever possible that osquery_tables.json would be missing name or platforms? interface IOsqueryTable { name: string; - platforms: TableSchemaPlatforms[]; + platforms: TableSchemaPlatform[]; } -type IPlatformDictionary = Record; +type IPlatformDictionary = Record; const platformsByTableDictionary: IPlatformDictionary = (osqueryTablesAvailable as IOsqueryTable[]).reduce( (dictionary: IPlatformDictionary, osqueryTable) => { diff --git a/frontend/utilities/strings/stringUtils.ts b/frontend/utilities/strings/stringUtils.ts index e7e205d98eda..6d0c8756feee 100644 --- a/frontend/utilities/strings/stringUtils.ts +++ b/frontend/utilities/strings/stringUtils.ts @@ -20,6 +20,8 @@ const capitalizeRole = (str: UserRole): UserRole => { export const STYLIZATIONS_AND_ACRONYMS = [ "macOS", + "iOS", + "iPadOS", "osquery", "MySQL", "MDM", @@ -29,7 +31,7 @@ export const STYLIZATIONS_AND_ACRONYMS = [ ]; // fleetdm.com/handbook/marketing/content-style-guide#sentence-case -// * doesn't recognize proper nouns! +/** Does not recognize proper nouns! */ export const enforceFleetSentenceCasing = (s: string) => { const resArr = s.split(" ").map((word, i) => { if (!STYLIZATIONS_AND_ACRONYMS.includes(word)) { From 0f7907ac889c786a8cff494fdb94de30c1d03a65 Mon Sep 17 00:00:00 2001 From: RachelElysia Date: Wed, 3 Jul 2024 16:01:51 -0400 Subject: [PATCH 12/13] Code review updates --- .../PlatformCompatibility.tests.tsx | 4 +-- .../PlatformCompatibility.tsx | 10 +++--- .../PlatformCell/PlatformCell.tests.tsx | 4 +-- .../DataTable/PlatformCell/PlatformCell.tsx | 8 ++--- frontend/hooks/usePlatformCompatibility.tsx | 6 ++-- frontend/hooks/usePlatformSelector.tsx | 4 +-- frontend/interfaces/osquery_table.ts | 4 +-- frontend/interfaces/platform.ts | 18 +++++----- frontend/interfaces/schedulable_query.ts | 4 +-- .../cards/HostsSummary/HostsSummary.tsx | 34 ++++++++----------- .../cards/HostsSummary/_styles.scss | 1 - .../OperatingSystems/OperatingSystems.tsx | 1 - .../DashboardPage/{helpers.tsx => helpers.ts} | 0 .../cards/CustomSettings/CustomSettings.tsx | 6 ++-- .../ProfileListItem/ProfileListItem.tsx | 2 +- .../EmptyTargetForm/EmptyTargetForm.tsx | 16 ++------- .../components/PlatformTabs/PlatformTabs.tsx | 10 +++--- .../TargetSection/TargetSection.tsx | 3 +- .../components/FilterPill/FilterPill.tsx | 1 - .../DiskEncryptionKeyModal.tsx | 4 +-- .../ManageQueriesPage/ManageQueriesPage.tsx | 4 +-- .../QueriesTable/QueriesTableConfig.tsx | 4 +-- frontend/utilities/sql_tools.ts | 6 ++-- 23 files changed, 67 insertions(+), 87 deletions(-) rename frontend/pages/DashboardPage/{helpers.tsx => helpers.ts} (100%) diff --git a/frontend/components/PlatformCompatibility/PlatformCompatibility.tests.tsx b/frontend/components/PlatformCompatibility/PlatformCompatibility.tests.tsx index b0fc1c950a56..10fbbb4faf7e 100644 --- a/frontend/components/PlatformCompatibility/PlatformCompatibility.tests.tsx +++ b/frontend/components/PlatformCompatibility/PlatformCompatibility.tests.tsx @@ -7,7 +7,7 @@ describe("Platform compatibility", () => { it("renders compatible platforms", () => { render( ); @@ -38,7 +38,7 @@ describe("Platform compatibility", () => { it("renders error state", () => { render( ); diff --git a/frontend/components/PlatformCompatibility/PlatformCompatibility.tsx b/frontend/components/PlatformCompatibility/PlatformCompatibility.tsx index c8e595370ab8..700726d37ecb 100644 --- a/frontend/components/PlatformCompatibility/PlatformCompatibility.tsx +++ b/frontend/components/PlatformCompatibility/PlatformCompatibility.tsx @@ -2,8 +2,8 @@ import React from "react"; import { DisplayPlatform, - SupportedDisplayPlatform, - SupportedPlatform, + QueryableDisplayPlatform, + QueryablePlatform, } from "interfaces/platform"; import { PLATFORM_DISPLAY_NAMES } from "utilities/constants"; @@ -22,12 +22,12 @@ const DISPLAY_ORDER = [ "Windows", "Linux", "ChromeOS", -] as SupportedDisplayPlatform[]; +] as QueryableDisplayPlatform[]; const ERROR_NO_COMPATIBLE_TABLES = Error("no tables in query"); const formatPlatformsForDisplay = ( - compatiblePlatforms: SupportedPlatform[] + compatiblePlatforms: QueryablePlatform[] ): DisplayPlatform[] => { return compatiblePlatforms.map((str) => PLATFORM_DISPLAY_NAMES[str] || str); }; @@ -56,8 +56,6 @@ const PlatformCompatibility = ({ return null; } - console.log("compatiblePlat", compatiblePlatforms); - const displayPlatforms = formatPlatformsForDisplay(compatiblePlatforms); const renderCompatiblePlatforms = () => { diff --git a/frontend/components/TableContainer/DataTable/PlatformCell/PlatformCell.tests.tsx b/frontend/components/TableContainer/DataTable/PlatformCell/PlatformCell.tests.tsx index 630eb461043e..9f91b32ee384 100644 --- a/frontend/components/TableContainer/DataTable/PlatformCell/PlatformCell.tests.tsx +++ b/frontend/components/TableContainer/DataTable/PlatformCell/PlatformCell.tests.tsx @@ -2,10 +2,10 @@ import React from "react"; import { render, screen } from "@testing-library/react"; import { DEFAULT_EMPTY_CELL_VALUE } from "utilities/constants"; -import { SupportedPlatform } from "interfaces/platform"; +import { QueryablePlatform } from "interfaces/platform"; import PlatformCell from "./PlatformCell"; -const PLATFORMS: SupportedPlatform[] = ["windows", "darwin", "linux", "chrome"]; +const PLATFORMS: QueryablePlatform[] = ["windows", "darwin", "linux", "chrome"]; describe("Platform cell", () => { it("renders platform icons in correct order", () => { diff --git a/frontend/components/TableContainer/DataTable/PlatformCell/PlatformCell.tsx b/frontend/components/TableContainer/DataTable/PlatformCell/PlatformCell.tsx index b81901218f95..f88026663840 100644 --- a/frontend/components/TableContainer/DataTable/PlatformCell/PlatformCell.tsx +++ b/frontend/components/TableContainer/DataTable/PlatformCell/PlatformCell.tsx @@ -1,22 +1,22 @@ import React from "react"; import Icon from "components/Icon"; -import { SupportedPlatform } from "interfaces/platform"; +import { QueryablePlatform } from "interfaces/platform"; import { DEFAULT_EMPTY_CELL_VALUE } from "utilities/constants"; interface IPlatformCellProps { - platforms: SupportedPlatform[]; + platforms: QueryablePlatform[]; } const baseClass = "platform-cell"; -const ICONS: Record = { +const ICONS: Record = { darwin: "darwin", windows: "windows", linux: "linux", chrome: "chrome", }; -const DISPLAY_ORDER: SupportedPlatform[] = [ +const DISPLAY_ORDER: QueryablePlatform[] = [ "darwin", "windows", "linux", diff --git a/frontend/hooks/usePlatformCompatibility.tsx b/frontend/hooks/usePlatformCompatibility.tsx index 7569d2b6197b..ebb4ec1ee4e1 100644 --- a/frontend/hooks/usePlatformCompatibility.tsx +++ b/frontend/hooks/usePlatformCompatibility.tsx @@ -1,13 +1,13 @@ import React, { useCallback, useState } from "react"; import { useDebouncedCallback } from "use-debounce"; -import { SupportedPlatform, SUPPORTED_PLATFORMS } from "interfaces/platform"; +import { QueryablePlatform, SUPPORTED_PLATFORMS } from "interfaces/platform"; import { checkPlatformCompatibility } from "utilities/sql_tools"; import PlatformCompatibility from "components/PlatformCompatibility"; export interface IPlatformCompatibility { - getCompatiblePlatforms: () => SupportedPlatform[]; + getCompatiblePlatforms: () => QueryablePlatform[]; setCompatiblePlatforms: (sqlString: string) => void; render: () => JSX.Element; } @@ -16,7 +16,7 @@ const DEBOUNCE_DELAY = 300; const usePlatformCompatibility = (): IPlatformCompatibility => { const [compatiblePlatforms, setCompatiblePlatforms] = useState< - SupportedPlatform[] | null + QueryablePlatform[] | null >(null); const [error, setError] = useState(null); diff --git a/frontend/hooks/usePlatformSelector.tsx b/frontend/hooks/usePlatformSelector.tsx index 497516259e33..b1fb384dd98f 100644 --- a/frontend/hooks/usePlatformSelector.tsx +++ b/frontend/hooks/usePlatformSelector.tsx @@ -4,14 +4,14 @@ import { forEach } from "lodash"; import { SelectedPlatformString, SUPPORTED_PLATFORMS, - SupportedPlatform, + QueryablePlatform, } from "interfaces/platform"; import PlatformSelector from "components/PlatformSelector"; export interface IPlatformSelector { setSelectedPlatforms: (platforms: string[]) => void; - getSelectedPlatforms: () => SupportedPlatform[]; + getSelectedPlatforms: () => QueryablePlatform[]; isAnyPlatformSelected: boolean; render: () => JSX.Element; disabled?: boolean; diff --git a/frontend/interfaces/osquery_table.ts b/frontend/interfaces/osquery_table.ts index 1166d75a7db5..c61faecba79d 100644 --- a/frontend/interfaces/osquery_table.ts +++ b/frontend/interfaces/osquery_table.ts @@ -1,5 +1,5 @@ import PropTypes from "prop-types"; -import { SupportedPlatform, SupportedDisplayPlatform } from "./platform"; +import { QueryablePlatform, QueryableDisplayPlatform } from "./platform"; export default PropTypes.shape({ columns: PropTypes.arrayOf( @@ -24,7 +24,7 @@ export type ColumnType = | "string"; // TODO: Why do we have type string, STRING, and text in schema.json? // TODO: Replace with one or the other once osquery_fleet_schema.json follows one type or other -export type TableSchemaPlatform = SupportedDisplayPlatform | SupportedPlatform; +export type TableSchemaPlatform = QueryableDisplayPlatform | QueryablePlatform; export interface IQueryTableColumn { name: string; description: string; diff --git a/frontend/interfaces/platform.ts b/frontend/interfaces/platform.ts index 13815dd82d1b..5c9a9042cdd8 100644 --- a/frontend/interfaces/platform.ts +++ b/frontend/interfaces/platform.ts @@ -14,31 +14,31 @@ export type Platform = | "ios" | "ipados"; -export type SupportedDisplayPlatform = Exclude< +export type QueryableDisplayPlatform = Exclude< DisplayPlatform, "iOS" | "iPadOS" >; -export type SupportedPlatform = Exclude; +export type QueryablePlatform = Exclude; -export const SUPPORTED_PLATFORMS: SupportedPlatform[] = [ +export const SUPPORTED_PLATFORMS: QueryablePlatform[] = [ "darwin", "windows", "linux", "chrome", ]; -export type SelectedPlatform = SupportedPlatform | "all"; +export type SelectedPlatform = QueryablePlatform | "all"; export type SelectedPlatformString = | "" - | SupportedPlatform - | `${SupportedPlatform},${SupportedPlatform}` - | `${SupportedPlatform},${SupportedPlatform},${SupportedPlatform}` - | `${SupportedPlatform},${SupportedPlatform},${SupportedPlatform},${SupportedPlatform}`; + | QueryablePlatform + | `${QueryablePlatform},${QueryablePlatform}` + | `${QueryablePlatform},${QueryablePlatform},${QueryablePlatform}` + | `${QueryablePlatform},${QueryablePlatform},${QueryablePlatform},${QueryablePlatform}`; // TODO: revisit this approach pending resolution of https://github.com/fleetdm/fleet/issues/3555. -export const MACADMINS_EXTENSION_TABLES: Record = { +export const MACADMINS_EXTENSION_TABLES: Record = { file_lines: ["darwin", "linux", "windows"], filevault_users: ["darwin"], google_chrome_profiles: ["darwin", "linux", "windows"], diff --git a/frontend/interfaces/schedulable_query.ts b/frontend/interfaces/schedulable_query.ts index 89d56dc72699..23d2a9cd27d0 100644 --- a/frontend/interfaces/schedulable_query.ts +++ b/frontend/interfaces/schedulable_query.ts @@ -3,7 +3,7 @@ import PropTypes from "prop-types"; import { IFormField } from "./form_field"; import { IPack } from "./pack"; -import { SelectedPlatformString, SupportedPlatform } from "./platform"; +import { SelectedPlatformString, QueryablePlatform } from "./platform"; // Query itself export interface ISchedulableQuery { @@ -32,7 +32,7 @@ export interface ISchedulableQuery { export interface IEnhancedQuery extends ISchedulableQuery { performance: string; - platforms: SupportedPlatform[]; + platforms: QueryablePlatform[]; } export interface ISchedulableQueryStats { user_time_p50?: number | null; diff --git a/frontend/pages/DashboardPage/cards/HostsSummary/HostsSummary.tsx b/frontend/pages/DashboardPage/cards/HostsSummary/HostsSummary.tsx index 764491d55c4c..6b9ced88ed96 100644 --- a/frontend/pages/DashboardPage/cards/HostsSummary/HostsSummary.tsx +++ b/frontend/pages/DashboardPage/cards/HostsSummary/HostsSummary.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useCallback } from "react"; import PATHS from "router/paths"; import { PLATFORM_NAME_TO_LABEL_NAME } from "pages/DashboardPage/helpers"; @@ -45,10 +45,16 @@ const HostsSummary = ({ opacity = isLoadingHostsSummary ? { opacity: 0.4 } : { opacity: 1 }; } + const getBuiltinLabelId = useCallback( + (platformName: keyof typeof PLATFORM_NAME_TO_LABEL_NAME) => + builtInLabels?.find( + (builtin) => builtin.name === PLATFORM_NAME_TO_LABEL_NAME[platformName] + )?.id, + [builtInLabels] + ); + const renderMacCount = (teamId?: number) => { - const macLabelId = builtInLabels?.find((builtin) => { - return builtin.name === PLATFORM_NAME_TO_LABEL_NAME.darwin; - })?.id; + const macLabelId = getBuiltinLabelId("darwin"); if (isLoadingHostsSummary || macLabelId === undefined) { return <>; @@ -69,9 +75,7 @@ const HostsSummary = ({ }; const renderWindowsCount = (teamId?: number) => { - const windowsLabelId = builtInLabels?.find( - (builtin) => builtin.name === PLATFORM_NAME_TO_LABEL_NAME.windows - )?.id; + const windowsLabelId = getBuiltinLabelId("windows"); if (isLoadingHostsSummary || windowsLabelId === undefined) { return <>; @@ -91,9 +95,7 @@ const HostsSummary = ({ }; const renderLinuxCount = (teamId?: number) => { - const linuxLabelId = builtInLabels?.find( - (builtin) => builtin.name === PLATFORM_NAME_TO_LABEL_NAME.linux - )?.id; + const linuxLabelId = getBuiltinLabelId("linux"); if (isLoadingHostsSummary || linuxLabelId === undefined) { return <>; @@ -113,9 +115,7 @@ const HostsSummary = ({ }; const renderChromeCount = (teamId?: number) => { - const chromeLabelId = builtInLabels?.find( - (builtin) => builtin.name === PLATFORM_NAME_TO_LABEL_NAME.chrome - )?.id; + const chromeLabelId = getBuiltinLabelId("chrome"); if (isLoadingHostsSummary || chromeLabelId === undefined) { return <>; @@ -136,9 +136,7 @@ const HostsSummary = ({ }; const renderIosCount = (teamId?: number) => { - const iosLabelId = builtInLabels?.find( - (builtin) => builtin.name === PLATFORM_NAME_TO_LABEL_NAME.ios - )?.id; + const iosLabelId = getBuiltinLabelId("ios"); if (isLoadingHostsSummary || iosLabelId === undefined) { return <>; @@ -159,9 +157,7 @@ const HostsSummary = ({ }; const renderIpadosCount = (teamId?: number) => { - const ipadosLabelId = builtInLabels?.find( - (builtin) => builtin.name === PLATFORM_NAME_TO_LABEL_NAME.ipados - )?.id; + const ipadosLabelId = getBuiltinLabelId("ipados"); if (isLoadingHostsSummary || ipadosLabelId === undefined) { return <>; diff --git a/frontend/pages/DashboardPage/cards/HostsSummary/_styles.scss b/frontend/pages/DashboardPage/cards/HostsSummary/_styles.scss index c5a6a566f091..d1a532e0ea34 100644 --- a/frontend/pages/DashboardPage/cards/HostsSummary/_styles.scss +++ b/frontend/pages/DashboardPage/cards/HostsSummary/_styles.scss @@ -2,7 +2,6 @@ margin-top: $pad-large; width: 100%; display: flex; - flex-direction: row; justify-content: space-around; flex-wrap: wrap; font-size: $x-small; diff --git a/frontend/pages/DashboardPage/cards/OperatingSystems/OperatingSystems.tsx b/frontend/pages/DashboardPage/cards/OperatingSystems/OperatingSystems.tsx index 8751d1ff30c0..5d2ef7f5dafb 100644 --- a/frontend/pages/DashboardPage/cards/OperatingSystems/OperatingSystems.tsx +++ b/frontend/pages/DashboardPage/cards/OperatingSystems/OperatingSystems.tsx @@ -5,7 +5,6 @@ import { OS_END_OF_LIFE_LINK_BY_PLATFORM, OS_VENDOR_BY_PLATFORM, } from "interfaces/operating_system"; -import { Platform } from "interfaces/platform"; import { getOSVersions, IGetOSVersionsQueryKey, diff --git a/frontend/pages/DashboardPage/helpers.tsx b/frontend/pages/DashboardPage/helpers.ts similarity index 100% rename from frontend/pages/DashboardPage/helpers.tsx rename to frontend/pages/DashboardPage/helpers.ts diff --git a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/CustomSettings.tsx b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/CustomSettings.tsx index bee17934991f..89887e9b838f 100644 --- a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/CustomSettings.tsx +++ b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/CustomSettings.tsx @@ -131,9 +131,9 @@ const CustomSettings = ({ return ; } - // if (isErrorProfiles) { - // return ; - // } + if (isErrorProfiles) { + return ; + } if (!profiles?.length) { return null; diff --git a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileListItem/ProfileListItem.tsx b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileListItem/ProfileListItem.tsx index bdc046ed7dea..a44779603434 100644 --- a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileListItem/ProfileListItem.tsx +++ b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileListItem/ProfileListItem.tsx @@ -39,7 +39,7 @@ const ProfileDetails = ({ }: IProfileDetailsProps) => { const getPlatformName = () => { if (platform === "windows") return "Windows"; - return isDDM ? "macOS (declaration)" : "macOS, iOS, iPadOS"; // TODO: Confirm this is correct logic and copy text + return isDDM ? "macOS (declaration)" : "macOS, iOS, iPadOS"; }; return ( diff --git a/frontend/pages/ManageControlsPage/OSUpdates/components/EmptyTargetForm/EmptyTargetForm.tsx b/frontend/pages/ManageControlsPage/OSUpdates/components/EmptyTargetForm/EmptyTargetForm.tsx index 2db6c843c256..80d24adc39a3 100644 --- a/frontend/pages/ManageControlsPage/OSUpdates/components/EmptyTargetForm/EmptyTargetForm.tsx +++ b/frontend/pages/ManageControlsPage/OSUpdates/components/EmptyTargetForm/EmptyTargetForm.tsx @@ -1,15 +1,5 @@ -import React, { useContext, useState } from "react"; -import { isEmpty } from "lodash"; +import React from "react"; -import { APP_CONTEXT_NO_TEAM_ID } from "interfaces/team"; -import { NotificationContext } from "context/notification"; -import configAPI from "services/entities/config"; -import teamsAPI from "services/entities/teams"; - -// @ts-ignore -import InputField from "components/forms/fields/InputField"; -import Button from "components/buttons/Button"; -import validatePresence from "components/forms/validators/validate_presence"; import CustomLink from "components/CustomLink"; const baseClass = "empty-target-form"; @@ -20,7 +10,7 @@ interface IEmptyTargetFormProps { const EmptyTargetForm = ({ targetPlatform }: IEmptyTargetFormProps) => { return ( - <> +

{targetPlatform} updates are coming soon.

@@ -32,7 +22,7 @@ const EmptyTargetForm = ({ targetPlatform }: IEmptyTargetFormProps) => { newTab />

- +
); }; diff --git a/frontend/pages/ManageControlsPage/OSUpdates/components/PlatformTabs/PlatformTabs.tsx b/frontend/pages/ManageControlsPage/OSUpdates/components/PlatformTabs/PlatformTabs.tsx index bee756b6b76a..3befce43aab7 100644 --- a/frontend/pages/ManageControlsPage/OSUpdates/components/PlatformTabs/PlatformTabs.tsx +++ b/frontend/pages/ManageControlsPage/OSUpdates/components/PlatformTabs/PlatformTabs.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React from "react"; import { Tab, TabList, TabPanel, Tabs } from "react-tabs"; import TabsWrapper from "components/TabsWrapper"; @@ -56,16 +56,16 @@ const PlatformTabs = ({ {/* Bolding text when the tab is active causes a layout shift so we add a hidden pseudo element with the same text string */} - + macOS - + Windows - + iOS - + iPadOS diff --git a/frontend/pages/ManageControlsPage/OSUpdates/components/TargetSection/TargetSection.tsx b/frontend/pages/ManageControlsPage/OSUpdates/components/TargetSection/TargetSection.tsx index 2214f3688670..e9af3e926e59 100644 --- a/frontend/pages/ManageControlsPage/OSUpdates/components/TargetSection/TargetSection.tsx +++ b/frontend/pages/ManageControlsPage/OSUpdates/components/TargetSection/TargetSection.tsx @@ -109,8 +109,7 @@ const TargetSection = ({ }); const renderTargetForms = () => { - if (!isMacMdmEnabled && !isWindowsMdmEnabled) { - // if (isMacMdmEnabled && isWindowsMdmEnabled) { + if (isMacMdmEnabled && isWindowsMdmEnabled) { return ( ; diff --git a/frontend/pages/queries/ManageQueriesPage/ManageQueriesPage.tsx b/frontend/pages/queries/ManageQueriesPage/ManageQueriesPage.tsx index dd4ed9ba99f2..f737f22cfd3b 100644 --- a/frontend/pages/queries/ManageQueriesPage/ManageQueriesPage.tsx +++ b/frontend/pages/queries/ManageQueriesPage/ManageQueriesPage.tsx @@ -14,7 +14,7 @@ import { QueryContext } from "context/query"; import { TableContext } from "context/table"; import { NotificationContext } from "context/notification"; import { getPerformanceImpactDescription } from "utilities/helpers"; -import { SupportedPlatform, SelectedPlatform } from "interfaces/platform"; +import { QueryablePlatform, SelectedPlatform } from "interfaces/platform"; import { IEnhancedQuery, IQueryKeyQueriesLoadAll, @@ -54,7 +54,7 @@ interface IManageQueriesPageProps { }; } -const getPlatforms = (queryString: string): SupportedPlatform[] => { +const getPlatforms = (queryString: string): QueryablePlatform[] => { const { platforms } = checkPlatformCompatibility(queryString); return platforms ?? []; diff --git a/frontend/pages/queries/ManageQueriesPage/components/QueriesTable/QueriesTableConfig.tsx b/frontend/pages/queries/ManageQueriesPage/components/QueriesTable/QueriesTableConfig.tsx index 81ff22dcf883..b38b394735aa 100644 --- a/frontend/pages/queries/ManageQueriesPage/components/QueriesTable/QueriesTableConfig.tsx +++ b/frontend/pages/queries/ManageQueriesPage/components/QueriesTable/QueriesTableConfig.tsx @@ -12,7 +12,7 @@ import { IEnhancedQuery, ISchedulableQuery, } from "interfaces/schedulable_query"; -import { SupportedPlatform } from "interfaces/platform"; +import { QueryablePlatform } from "interfaces/platform"; import { API_ALL_TEAMS_ID } from "interfaces/team"; import Icon from "components/Icon"; @@ -81,7 +81,7 @@ interface IBoolCellProps extends IRowProps { } interface IPlatformCellProps extends IRowProps { cell: { - value: SupportedPlatform[]; + value: QueryablePlatform[]; }; } diff --git a/frontend/utilities/sql_tools.ts b/frontend/utilities/sql_tools.ts index 71dc64333383..edf845fc0d79 100644 --- a/frontend/utilities/sql_tools.ts +++ b/frontend/utilities/sql_tools.ts @@ -5,7 +5,7 @@ import { osqueryTablesAvailable } from "utilities/osquery_tables"; import { MACADMINS_EXTENSION_TABLES, SUPPORTED_PLATFORMS, - SupportedPlatform, + QueryablePlatform, } from "interfaces/platform"; import { TableSchemaPlatform } from "interfaces/osquery_table"; @@ -57,7 +57,7 @@ const _visit = ( const filterCompatiblePlatforms = ( sqlTables: string[] -): SupportedPlatform[] => { +): QueryablePlatform[] => { if (!sqlTables.length) { return [...SUPPORTED_PLATFORMS]; // if a query has no tables but is still syntatically valid sql, it is treated as compatible with all platforms } @@ -147,7 +147,7 @@ export const checkTable = ( export const checkPlatformCompatibility = ( sqlString: string, includeCteTables = false -): { platforms: SupportedPlatform[] | null; error: Error | null } => { +): { platforms: QueryablePlatform[] | null; error: Error | null } => { let sqlTables: string[] | undefined; try { // get tables from str From 0ee31bd148128d548146f4005189115687428793 Mon Sep 17 00:00:00 2001 From: RachelElysia Date: Fri, 5 Jul 2024 14:06:48 -0400 Subject: [PATCH 13/13] Fix file extension downloader for ios/ipado --- .../components/ProfileListItem/ProfileListItem.tsx | 5 +++-- .../ProfileUploader/components/AddProfileModal/helpers.tsx | 1 - 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileListItem/ProfileListItem.tsx b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileListItem/ProfileListItem.tsx index a44779603434..a7ba5829c469 100644 --- a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileListItem/ProfileListItem.tsx +++ b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileListItem/ProfileListItem.tsx @@ -4,6 +4,7 @@ import FileSaver from "file-saver"; import classnames from "classnames"; import { IMdmProfile } from "interfaces/mdm"; +import { isAppleDevice } from "interfaces/platform"; import mdmAPI, { isDDMProfile } from "services/entities/mdm"; import Button from "components/buttons/Button"; @@ -57,7 +58,7 @@ const createProfileExtension = (profile: IMdmProfile) => { if (isDDMProfile(profile)) { return "json"; } - return profile.platform === "darwin" ? "mobileconfig" : "xml"; + return isAppleDevice(profile.platform) ? "mobileconfig" : "xml"; }; const createFileContent = async (profile: IMdmProfile) => { @@ -95,7 +96,7 @@ const ProfileListItem = ({ const onClickDownload = async () => { const fileContent = await createFileContent(profile); const formatDate = format(new Date(), "yyyy-MM-dd"); - const extension = createProfileExtension(profile); // TODO: How does createProfileExtension work with iOS/iPadOS profiles + const extension = createProfileExtension(profile); const filename = `${formatDate}_${name}.${extension}`; const file = new File([fileContent], filename); FileSaver.saveAs(file); diff --git a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileUploader/components/AddProfileModal/helpers.tsx b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileUploader/components/AddProfileModal/helpers.tsx index e8ff573ecefe..f1ed1acdd7b8 100644 --- a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileUploader/components/AddProfileModal/helpers.tsx +++ b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileUploader/components/AddProfileModal/helpers.tsx @@ -1,7 +1,6 @@ import React from "react"; import { IDropdownOption } from "interfaces/dropdownOption"; -import { snakeCase } from "lodash"; export const CUSTOM_TARGET_OPTIONS: IDropdownOption[] = [ {