diff --git a/Makefile b/Makefile index cd54e4c20a..839f2e8fd8 100644 --- a/Makefile +++ b/Makefile @@ -239,7 +239,7 @@ generate-dev: .prefix NODE_ENV=development yarn run webpack --progress --watch generate-mock: .prefix - go generate github.com/fleetdm/fleet/v4/server/mock github.com/fleetdm/fleet/v4/server/mock/mockresult github.com/fleetdm/fleet/v4/server/service/mock + go generate github.com/fleetdm/fleet/v4/server/mock github.com/fleetdm/fleet/v4/server/mock/mockresult github.com/fleetdm/fleet/v4/server/service/mock github.com/fleetdm/fleet/v4/server/mdm/android/mock generate-doc: .prefix go generate github.com/fleetdm/fleet/v4/server/fleet diff --git a/articles/configuring-full-names-in-google-workspace.md b/articles/configuring-full-names-in-google-workspace.md index 39cdf668ce..bf34b6e567 100644 --- a/articles/configuring-full-names-in-google-workspace.md +++ b/articles/configuring-full-names-in-google-workspace.md @@ -1,7 +1,5 @@ # Configuring full names in Google Workspace for Fleet integration -## Introduction - Fleet requires user full names to be configured in your Identity Provider (IdP) using specific attributes. Since Google Workspace doesn't natively provide a full name attribute that matches Fleet's requirements, this guide will walk you through setting up automatic synchronization of full names using Google's custom attributes and Apps Script. ## What we're solving diff --git a/articles/windows-mdm-setup.md b/articles/windows-mdm-setup.md index a3b2587229..bd137c30aa 100644 --- a/articles/windows-mdm-setup.md +++ b/articles/windows-mdm-setup.md @@ -173,6 +173,13 @@ Once the automatic migration is enabled, Fleet sends a notification to each host You can track migration progress in Fleet. Learn how [here](https://fleetdm.com/guides/mdm-migration#check-migration-progress). +## Turn off Windows MDM + +1. Turn off MDM for each host, by running [this script](https://github.com/fleetdm/fleet/blob/main/it-and-security/lib/windows/scripts/turn-off-mdm.ps1) on all your Windows hosts. +2. Head to **Settings > Integrations > MDM**. +3. In the **Mobile device management (MDM)** section, select **Edit** next to "Windows MDM turned on." +4. Switch **Windows MDM on** to **Windows MDM off** and select **Save**. + diff --git a/changes/25834-always-allow-passwords b/changes/25834-always-allow-passwords new file mode 100644 index 0000000000..aa11717ed9 --- /dev/null +++ b/changes/25834-always-allow-passwords @@ -0,0 +1 @@ +- Fixed password authentication getting disabled when SMTP isn't configured diff --git a/frontend/components/PlatformCompatibility/PlatformCompatibility.tsx b/frontend/components/PlatformCompatibility/PlatformCompatibility.tsx index 05ae3619a3..25cbe7f4ea 100644 --- a/frontend/components/PlatformCompatibility/PlatformCompatibility.tsx +++ b/frontend/components/PlatformCompatibility/PlatformCompatibility.tsx @@ -48,6 +48,31 @@ const displayIncompatibilityText = (err: Error) => { } }; +// const tipContent = ( +// <> +// Estimated compatibility based on the
+// tables used in the query. Querying
+// iPhones, iPads, and Android hosts is not
+// supported. +// +// ); + +// TODO(android): replace with the above tipContent when Android feature flag is removed +const tipContent = ( + <> + Estimated compatibility based on the
+ tables used in the query. Check the
+ table documentation (schema) to verify
+ compatibility of individual columns. +
+
+ Only live queries are supported on ChromeOS. +
+
+ Querying iPhones & iPads is not supported. + +); + const PlatformCompatibility = ({ compatiblePlatforms, error, @@ -84,22 +109,7 @@ const PlatformCompatibility = ({ return (
- - Estimated compatibility based on the
- tables used in the query. Check the
- table documentation (schema) to verify
- compatibility of individual columns. -
-
- Only live queries are supported on ChromeOS. -
-
- Querying iPhones & iPads is not supported. - - } - > + Compatible with:
diff --git a/frontend/components/icons/Android.tsx b/frontend/components/icons/Android.tsx new file mode 100644 index 0000000000..6ca60464e4 --- /dev/null +++ b/frontend/components/icons/Android.tsx @@ -0,0 +1,30 @@ +import React from "react"; +import { COLORS, Colors } from "styles/var/colors"; +import { ICON_SIZES, IconSizes } from "styles/var/icon_sizes"; + +const Android = ({ + size = "medium", + color = "ui-fleet-black-75", +}: { + size: IconSizes; + color?: Colors; +}) => { + return ( + + + + ); +}; + +export default Android; diff --git a/frontend/components/icons/index.ts b/frontend/components/icons/index.ts index 810998b63e..754e683c9a 100644 --- a/frontend/components/icons/index.ts +++ b/frontend/components/icons/index.ts @@ -69,6 +69,7 @@ import AutomaticSelfService from "./AutomaticSelfService"; import User from "./User"; import InfoOutline from "./InfoOutline"; import GitOpsMode from "./GitOpsMode"; +import Android from "./Android"; // a mapping of the usable names of icons to the icon source. export const ICON_MAP = { @@ -133,6 +134,7 @@ export const ICON_MAP = { iPadOS, ios: iOS, iOS, + android: Android, "premium-feature": PremiumFeature, profile: Profile, download: Download, diff --git a/frontend/interfaces/platform.ts b/frontend/interfaces/platform.ts index 9fd2d4502c..753cfc41b8 100644 --- a/frontend/interfaces/platform.ts +++ b/frontend/interfaces/platform.ts @@ -11,24 +11,27 @@ export const PLATFORM_DISPLAY_NAMES = { windows: "Windows", linux: "Linux", chrome: "ChromeOS", + android: "Android", ...APPLE_PLATFORM_DISPLAY_NAMES, } as const; +export const QUERYABLE_PLATFORMS = [ + "darwin", + "windows", + "linux", + "chrome", +] as const; + +export const NON_QUERYABLE_PLATFORMS = ["ios", "ipados", "android"] as const; + export type Platform = keyof typeof PLATFORM_DISPLAY_NAMES; export type DisplayPlatform = typeof PLATFORM_DISPLAY_NAMES[keyof typeof PLATFORM_DISPLAY_NAMES]; export type QueryableDisplayPlatform = Exclude< DisplayPlatform, - "iOS" | "iPadOS" + typeof PLATFORM_DISPLAY_NAMES[typeof NON_QUERYABLE_PLATFORMS[number]] >; -export type QueryablePlatform = Exclude; - -export const QUERYABLE_PLATFORMS: QueryablePlatform[] = [ - "darwin", - "windows", - "linux", - "chrome", -]; +export type QueryablePlatform = typeof QUERYABLE_PLATFORMS[number]; export const isQueryablePlatform = ( platform: string | undefined @@ -111,7 +114,8 @@ export type HostPlatform = | typeof HOST_LINUX_PLATFORMS[number] | typeof HOST_APPLE_PLATFORMS[number] | "windows" - | "chrome"; + | "chrome" + | "android"; /** * Checks if the provided platform is a Linux-like OS. We can recieve many @@ -133,6 +137,14 @@ export const isAppleDevice = (platform: string) => { export const isIPadOrIPhone = (platform: string | HostPlatform) => ["ios", "ipados"].includes(platform); +export const isAndroid = ( + platform: string | HostPlatform +): platform is "android" => platform === "android"; + +/** isMobilePlatform checks if the platform is an iPad or iPhone or Android. */ +export const isMobilePlatform = (platform: string | HostPlatform) => + isIPadOrIPhone(platform) || isAndroid(platform); + export const DISK_ENCRYPTION_SUPPORTED_LINUX_PLATFORMS = [ "ubuntu", // covers Kubuntu "rhel", // *included here to support Fedora systems. Necessary to cross-check with `os_versions` as well to confrim host is Fedora and not another, non-support rhel-like platform. @@ -161,6 +173,9 @@ export const platformSupportsDiskEncryption = ( /** os_version necessary to differentiate Fedora from other rhel-like platforms */ os_version?: string ) => { + if (isAndroid(platform)) { + return false; + } if (platform === "rhel") { return !!os_version && os_version.toLowerCase().includes("fedora"); } @@ -179,6 +194,9 @@ export const isOsSettingsDisplayPlatform = ( platform: HostPlatform, os_version: string ) => { + if (isAndroid(platform)) { + return false; + } if (platform === "rhel") { return !!os_version && os_version.toLowerCase().includes("fedora"); } diff --git a/frontend/interfaces/script.ts b/frontend/interfaces/script.ts index 15497dcc90..7bbdd4dc21 100644 --- a/frontend/interfaces/script.ts +++ b/frontend/interfaces/script.ts @@ -9,7 +9,7 @@ export interface IScript { } export const isScriptSupportedPlatform = (hostPlatform: string) => - ["darwin", "windows", ...HOST_LINUX_PLATFORMS].includes(hostPlatform); // excludes chrome, ios, ipados see also https://github.com/fleetdm/fleet/blob/5a21e2cfb029053ddad0508869eb9f1f23997bf2/server/fleet/hosts.go#L775 + ["darwin", "windows", ...HOST_LINUX_PLATFORMS].includes(hostPlatform); // excludes chrome, ios, ipados, android see also https://github.com/fleetdm/fleet/blob/5a21e2cfb029053ddad0508869eb9f1f23997bf2/server/fleet/hosts.go#L775 export type IScriptExecutionStatus = "ran" | "pending" | "error"; diff --git a/frontend/pages/DashboardPage/DashboardPage.tsx b/frontend/pages/DashboardPage/DashboardPage.tsx index 8a1489250c..505a13c9c5 100644 --- a/frontend/pages/DashboardPage/DashboardPage.tsx +++ b/frontend/pages/DashboardPage/DashboardPage.tsx @@ -137,6 +137,7 @@ const DashboardPage = ({ router, location }: IDashboardProps): JSX.Element => { const [chromeCount, setChromeCount] = useState(0); const [iosCount, setIosCount] = useState(0); const [ipadosCount, setIpadosCount] = useState(0); + const [androidCount, setAndroidCount] = useState(0); const [missingCount, setMissingCount] = useState(0); const [lowDiskSpaceCount, setLowDiskSpaceCount] = useState(0); const [showActivityFeedTitle, setShowActivityFeedTitle] = useState(false); @@ -191,6 +192,14 @@ const DashboardPage = ({ router, location }: IDashboardProps): JSX.Element => { IConfig >(["config"], () => configAPI.loadAll(), { ...DEFAULT_USE_QUERY_OPTIONS }); + // TODO(android): remove this when the feature flag is removed + const platformOptions = useMemo(() => { + if (!config?.android_enabled) { + return PLATFORM_DROPDOWN_OPTIONS.filter((o) => o.value !== "android"); + } + return [...PLATFORM_DROPDOWN_OPTIONS]; + }, [config?.android_enabled]); + const { data: teams, isLoading: isLoadingTeams } = useQuery< ILoadTeamsResponse, Error, @@ -242,12 +251,17 @@ const DashboardPage = ({ router, location }: IDashboardProps): JSX.Element => { (platform: IHostSummaryPlatforms) => platform.platform === "ipados" ) || { platform: "ipados", hosts_count: 0 }; + const android = data.platforms?.find( + (platform: IHostSummaryPlatforms) => platform.platform === "android" + ) || { platform: "android", 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); + setAndroidCount(android.hosts_count); setShowHostsUI(true); }, } @@ -540,6 +554,7 @@ const DashboardPage = ({ router, location }: IDashboardProps): JSX.Element => { const HostCountCards = ( <> { chromeCount={chromeCount} iosCount={iosCount} ipadosCount={ipadosCount} + androidCount={androidCount} builtInLabels={labels} selectedPlatform={selectedPlatform} errorHosts={!!errorHosts} @@ -764,6 +780,12 @@ const DashboardPage = ({ router, location }: IDashboardProps): JSX.Element => { ); + const androidLayout = () => ( + <> + {showMdmCard &&
{MDMCard}
} + + ); + const renderCards = () => { switch (selectedPlatform) { case "darwin": @@ -778,6 +800,8 @@ const DashboardPage = ({ router, location }: IDashboardProps): JSX.Element => { return iosLayout(); case "ipados": return ipadosLayout(); + case "android": + return androidLayout(); default: return allLayout(); } @@ -861,7 +885,7 @@ const DashboardPage = ({ router, location }: IDashboardProps): JSX.Element => { name="platform-filter" value={selectedPlatform || ""} className={`${baseClass}__platform-filter`} - options={PLATFORM_DROPDOWN_OPTIONS} + options={platformOptions} onChange={(option: SingleValue) => { const selectedPlatformOption = PLATFORM_DROPDOWN_OPTIONS.find( (platform) => platform.value === option?.value diff --git a/frontend/pages/DashboardPage/cards/ActivityFeed/GlobalActivityItem/GlobalActivityItem.tsx b/frontend/pages/DashboardPage/cards/ActivityFeed/GlobalActivityItem/GlobalActivityItem.tsx index d7fffd988b..423ea53824 100644 --- a/frontend/pages/DashboardPage/cards/ActivityFeed/GlobalActivityItem/GlobalActivityItem.tsx +++ b/frontend/pages/DashboardPage/cards/ActivityFeed/GlobalActivityItem/GlobalActivityItem.tsx @@ -1340,7 +1340,7 @@ const GlobalActivityItem = ({ const hasDetails = ACTIVITIES_WITH_DETAILS.has(activity.type); const renderActivityPrefix = () => { - const DEFAULT_ACTOR_DISPLAY = {activity.actor_full_name} ; + const DEFAULT_ACTOR_DISPLAY = {activity.actor_full_name ?? "Fleet"} ; switch (activity.type) { case ActivityType.UserLoggedIn: diff --git a/frontend/pages/DashboardPage/helpers.ts b/frontend/pages/DashboardPage/helpers.ts index 34d5f96dda..e01d3336f7 100644 --- a/frontend/pages/DashboardPage/helpers.ts +++ b/frontend/pages/DashboardPage/helpers.ts @@ -1,18 +1,7 @@ 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[] = [ +export const PLATFORM_DROPDOWN_OPTIONS = [ { label: "All", value: "all", path: paths.DASHBOARD }, { label: "macOS", value: "darwin", path: paths.DASHBOARD_MAC }, { label: "Windows", value: "windows", path: paths.DASHBOARD_WINDOWS }, @@ -20,7 +9,8 @@ export const PLATFORM_DROPDOWN_OPTIONS: IPlatformDropdownOptions[] = [ { label: "ChromeOS", value: "chrome", path: paths.DASHBOARD_CHROME }, { label: "iOS", value: "ios", path: paths.DASHBOARD_IOS }, { label: "iPadOS", value: "ipados", path: paths.DASHBOARD_IPADOS }, -]; + { label: "Android", value: "android", path: paths.DASHBOARD_ANDROID }, +] as const; /** Selected platform value mapped to built in label name */ export const PLATFORM_NAME_TO_LABEL_NAME = { @@ -30,7 +20,8 @@ export const PLATFORM_NAME_TO_LABEL_NAME = { chrome: "chrome", ios: "iOS", ipados: "iPadOS", -}; + android: "Android", +} as const; /** Premium feature, Gb must be set between 1-100 */ export const LOW_DISK_SPACE_GB = 32; diff --git a/frontend/pages/DashboardPage/sections/MetricsHostCounts/MetricsHostCounts.tsx b/frontend/pages/DashboardPage/sections/MetricsHostCounts/MetricsHostCounts.tsx index a44b3f9427..90d77e3562 100644 --- a/frontend/pages/DashboardPage/sections/MetricsHostCounts/MetricsHostCounts.tsx +++ b/frontend/pages/DashboardPage/sections/MetricsHostCounts/MetricsHostCounts.tsx @@ -66,7 +66,8 @@ const MetricsHostCounts = ({ {selectedPlatform === "all" && TotalHostsCard} {isPremiumTier && selectedPlatform !== "ios" && - selectedPlatform !== "ipados" && ( + selectedPlatform !== "ipados" && + selectedPlatform !== "android" && ( <> {MissingHostsCard} {LowDiskSpaceHostsCard} diff --git a/frontend/pages/DashboardPage/sections/PlatformHostCounts/PlatformHostCounts.tsx b/frontend/pages/DashboardPage/sections/PlatformHostCounts/PlatformHostCounts.tsx index 4e4133c9c4..a9676b3a1f 100644 --- a/frontend/pages/DashboardPage/sections/PlatformHostCounts/PlatformHostCounts.tsx +++ b/frontend/pages/DashboardPage/sections/PlatformHostCounts/PlatformHostCounts.tsx @@ -12,6 +12,7 @@ import HostCountCard from "../../cards/HostCountCard"; const baseClass = "platform-host-counts"; interface IPlatformHostCountsProps { + androidDevEnabled: boolean; // TODO(android): remove when feature flag is removed currentTeamId: number | undefined; macCount: number; windowsCount: number; @@ -19,6 +20,7 @@ interface IPlatformHostCountsProps { chromeCount: number; iosCount: number; ipadosCount: number; + androidCount: number; builtInLabels?: IHostSummary["builtin_labels"]; errorHosts: boolean; selectedPlatform?: PlatformValueOptions; @@ -26,6 +28,7 @@ interface IPlatformHostCountsProps { } const PlatformHostCounts = ({ + androidDevEnabled, currentTeamId, macCount, windowsCount, @@ -33,6 +36,7 @@ const PlatformHostCounts = ({ chromeCount, iosCount, ipadosCount, + androidCount, builtInLabels, errorHosts, selectedPlatform, @@ -187,6 +191,34 @@ const PlatformHostCounts = ({ ); }; + const renderAndroidCount = (teamId?: number) => { + if (!androidDevEnabled) { + // TODO(android): remove when feature flag is removed + return null; + } + + const androidLabelId = getBuiltinLabelId("android"); + + if (hidePlatformCard(androidCount)) { + return null; + } + + if (androidLabelId === undefined) { + return <>; + } + + return ( + + ); + }; + const renderCounts = (teamId?: number) => { switch (selectedPlatform) { case "darwin": @@ -201,7 +233,10 @@ const PlatformHostCounts = ({ return renderIosCount(teamId); case "ipados": return renderIpadosCount(teamId); + case "android": + return renderAndroidCount(teamId); default: + // TODO(android): responsive layout with variable column widths (see figma for 2x2x3 grid) return ( <> {renderMacCard(teamId)} @@ -210,6 +245,7 @@ const PlatformHostCounts = ({ {renderChromeCard(teamId)} {renderIosCount(teamId)} {renderIpadosCount(teamId)} + {renderAndroidCount(teamId)} ); } diff --git a/frontend/pages/ManageControlsPage/OSUpdates/OSUpdates.tsx b/frontend/pages/ManageControlsPage/OSUpdates/OSUpdates.tsx index ebbda487a9..2306b79739 100644 --- a/frontend/pages/ManageControlsPage/OSUpdates/OSUpdates.tsx +++ b/frontend/pages/ManageControlsPage/OSUpdates/OSUpdates.tsx @@ -6,7 +6,7 @@ import { AppContext } from "context/app"; import { IConfig } from "interfaces/config"; import { ITeamConfig } from "interfaces/team"; -import { ApplePlatform } from "interfaces/platform"; +import { ApplePlatform, isAndroid } from "interfaces/platform"; import configAPI from "services/entities/config"; import teamsAPI, { ILoadTeamResponse } from "services/entities/teams"; @@ -22,11 +22,13 @@ import { parseOSUpdatesCurrentVersionsQueryParams } from "./components/CurrentVe export type OSUpdatesSupportedPlatform = ApplePlatform | "windows"; +export type OSUpdatesTargetPlatform = OSUpdatesSupportedPlatform | "android"; // used for displaying "coming soon" messaging + const baseClass = "os-updates"; -const getSelectedPlatform = ( +const getDefaultSelectedPlatform = ( appConfig: IConfig | null -): OSUpdatesSupportedPlatform => { +): OSUpdatesTargetPlatform => { // We dont have the data ready yet so we default to mac. // This is usually when the users first comes to this page. if (appConfig === null) return "darwin"; @@ -34,7 +36,7 @@ const getSelectedPlatform = ( // if the mac mdm is enable and configured we check the app config to see if // the mdm for mac is enabled. If it is, it does not matter if windows is // enabled and configured and we will always return "mac". - return appConfig.mdm.enabled_and_configured ? "darwin" : "windows"; + return appConfig.mdm.enabled_and_configured ? "darwin" : "windows"; // TODO(android): adjust this when android is supported }; interface IOSUpdates { @@ -49,7 +51,7 @@ const OSUpdates = ({ router, teamIdForApi, queryParams }: IOSUpdates) => { const [ selectedPlatformTab, setSelectedPlatformTab, - ] = useState(null); + ] = useState(null); const { isError: isErrorConfig, @@ -102,7 +104,8 @@ const OSUpdates = ({ router, teamIdForApi, queryParams }: IOSUpdates) => { // If the user has not selected a platform yet, we default to the platform that // is enabled and configured. - const selectedPlatform = selectedPlatformTab || getSelectedPlatform(config); + const selectedPlatform = + selectedPlatformTab || getDefaultSelectedPlatform(config); return (
@@ -131,9 +134,11 @@ const OSUpdates = ({ router, teamIdForApi, queryParams }: IOSUpdates) => { refetchTeamConfig={refetchTeamConfig} />
-
- -
+ {!isAndroid(selectedPlatform) && ( +
+ +
+ )}
); diff --git a/frontend/pages/ManageControlsPage/OSUpdates/components/PlatformTabs/PlatformTabs.tsx b/frontend/pages/ManageControlsPage/OSUpdates/components/PlatformTabs/PlatformTabs.tsx index df5be12011..d69a9ec838 100644 --- a/frontend/pages/ManageControlsPage/OSUpdates/components/PlatformTabs/PlatformTabs.tsx +++ b/frontend/pages/ManageControlsPage/OSUpdates/components/PlatformTabs/PlatformTabs.tsx @@ -1,9 +1,11 @@ import React from "react"; import { Tab, TabList, TabPanel, Tabs } from "react-tabs"; import TabsWrapper from "components/TabsWrapper"; +import CustomLink from "components/CustomLink"; +import { SUPPORT_LINK } from "utilities/constants"; import WindowsTargetForm from "../WindowsTargetForm"; -import { OSUpdatesSupportedPlatform } from "../../OSUpdates"; +import { OSUpdatesTargetPlatform } from "../../OSUpdates"; import AppleOSTargetForm from "../AppleOSTargetForm"; const baseClass = "platform-tabs"; @@ -18,11 +20,12 @@ interface IPlatformTabsProps { defaultIPadOSDeadline: string; defaultWindowsDeadlineDays: string; defaultWindowsGracePeriodDays: string; - selectedPlatform: OSUpdatesSupportedPlatform; - onSelectPlatform: (platform: OSUpdatesSupportedPlatform) => void; + selectedPlatform: OSUpdatesTargetPlatform; + onSelectPlatform: (platform: OSUpdatesTargetPlatform) => void; refetchAppConfig: () => void; refetchTeamConfig: () => void; isWindowsMdmEnabled: boolean; + isAndroidMdmEnabled: boolean; } const PlatformTabs = ({ @@ -40,23 +43,28 @@ const PlatformTabs = ({ refetchAppConfig, refetchTeamConfig, isWindowsMdmEnabled, + isAndroidMdmEnabled, }: 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[] = isWindowsMdmEnabled + const platformByIndex: OSUpdatesTargetPlatform[] = isWindowsMdmEnabled ? ["darwin", "windows", "ios", "ipados"] : ["darwin", "ios", "ipados"]; + if (isAndroidMdmEnabled) { + platformByIndex.push("android"); + } + const onTabChange = (index: number) => { - onSelectPlatform(PLATFORM_BY_INDEX[index]); + onSelectPlatform(platformByIndex[index]); }; return (
@@ -76,6 +84,11 @@ const PlatformTabs = ({ iPadOS + {isAndroidMdmEnabled && ( + + Android + + )} + {isAndroidMdmEnabled && ( + +
+

+ Android updates are coming soon. +

+

+ Need to encourage installation of Android updates?{" "} + +

+
+
+ )}
diff --git a/frontend/pages/ManageControlsPage/OSUpdates/components/PlatformTabs/_styles.scss b/frontend/pages/ManageControlsPage/OSUpdates/components/PlatformTabs/_styles.scss index 2cf0a6f4ab..d38e98c5f2 100644 --- a/frontend/pages/ManageControlsPage/OSUpdates/components/PlatformTabs/_styles.scss +++ b/frontend/pages/ManageControlsPage/OSUpdates/components/PlatformTabs/_styles.scss @@ -2,4 +2,10 @@ .react-tabs__tab-list { margin-bottom: $pad-large; } + &__coming-soon { + p { + margin: 0; + padding-bottom: $pad-small; + } + } } diff --git a/frontend/pages/ManageControlsPage/OSUpdates/components/TargetSection/TargetSection.tsx b/frontend/pages/ManageControlsPage/OSUpdates/components/TargetSection/TargetSection.tsx index b0bb07e3c1..f4704e5de0 100644 --- a/frontend/pages/ManageControlsPage/OSUpdates/components/TargetSection/TargetSection.tsx +++ b/frontend/pages/ManageControlsPage/OSUpdates/components/TargetSection/TargetSection.tsx @@ -9,7 +9,7 @@ import Spinner from "components/Spinner"; import WindowsTargetForm from "../WindowsTargetForm"; import PlatformTabs from "../PlatformTabs"; -import { OSUpdatesSupportedPlatform } from "../../OSUpdates"; +import { OSUpdatesTargetPlatform } from "../../OSUpdates"; const baseClass = "os-updates-target-section"; @@ -86,9 +86,9 @@ interface ITargetSectionProps { appConfig: IConfig; currentTeamId: number; isFetching: boolean; - selectedPlatform: OSUpdatesSupportedPlatform; + selectedPlatform: OSUpdatesTargetPlatform; teamConfig?: ITeamConfig; - onSelectPlatform: (platform: OSUpdatesSupportedPlatform) => void; + onSelectPlatform: (platform: OSUpdatesTargetPlatform) => void; refetchAppConfig: () => void; refetchTeamConfig: () => void; } @@ -107,6 +107,8 @@ const TargetSection = ({ return ; } + const isAndroidMdmEnabled = appConfig.mdm.android_enabled_and_configured; + const isAppleMdmEnabled = appConfig.mdm.enabled_and_configured; const isWindowsMdmEnabled = appConfig.mdm.windows_enabled_and_configured; @@ -161,33 +163,34 @@ const TargetSection = ({ }); const renderTargetForms = () => { - if (isAppleMdmEnabled) { + if (isWindowsMdmEnabled && !isAppleMdmEnabled && !isAndroidMdmEnabled) { return ( - ); } return ( - ); }; diff --git a/frontend/pages/admin/UserManagementPage/components/UserForm/UserForm.tsx b/frontend/pages/admin/UserManagementPage/components/UserForm/UserForm.tsx index cb5dd38f2f..e1148242f4 100644 --- a/frontend/pages/admin/UserManagementPage/components/UserForm/UserForm.tsx +++ b/frontend/pages/admin/UserManagementPage/components/UserForm/UserForm.tsx @@ -589,7 +589,6 @@ const UserForm = ({ id="password-authentication" // allow the user to change auth back to password if they only changed the form to SSO in // the current session, that is, in the db, the user is still password authenticated - disabled={!(smtpConfigured || sesConfigured) && !initiallyPasswordAuth} checked={!formData.sso_enabled} value="false" name="authentication-type" diff --git a/frontend/pages/hosts/ManageHostsPage/HostTableConfig.tsx b/frontend/pages/hosts/ManageHostsPage/HostTableConfig.tsx index f5837eed38..633901fff4 100644 --- a/frontend/pages/hosts/ManageHostsPage/HostTableConfig.tsx +++ b/frontend/pages/hosts/ManageHostsPage/HostTableConfig.tsx @@ -6,6 +6,8 @@ import { CellProps, Column } from "react-table"; import ReactTooltip from "react-tooltip"; import { IDeviceUser, IHost } from "interfaces/host"; +import { isAndroid, isMobilePlatform } from "interfaces/platform"; + import Checkbox from "components/forms/fields/Checkbox"; import DiskSpaceIndicator from "pages/hosts/components/DiskSpaceIndicator"; import HeaderCell from "components/TableContainer/DataTable/HeaderCell/HeaderCell"; @@ -225,10 +227,7 @@ const allHostTableHeaders: IHostTableColumnConfig[] = [ accessor: "status", id: "status", Cell: (cellProps: IHostTableStringCellProps) => { - if ( - cellProps.row.original.platform === "ios" || - cellProps.row.original.platform === "ipados" - ) { + if (isMobilePlatform(cellProps.row.original.platform)) { return NotSupported; } const value = cellProps.cell.value; @@ -247,10 +246,7 @@ const allHostTableHeaders: IHostTableColumnConfig[] = [ id: "issues", sortDescFirst: true, Cell: (cellProps: IIssuesCellProps) => { - if ( - cellProps.row.original.platform === "ios" || - cellProps.row.original.platform === "ipados" - ) { + if (isMobilePlatform(cellProps.row.original.platform)) { return NotSupported; } return ( @@ -302,6 +298,7 @@ const allHostTableHeaders: IHostTableColumnConfig[] = [ accessor: "os_version", id: "os_version", Cell: (cellProps: IHostTableStringCellProps) => ( + // TODO(android): is Android supported? what about the os versions endpoint and dashboard card? ), }, @@ -316,10 +313,7 @@ const allHostTableHeaders: IHostTableColumnConfig[] = [ accessor: "osquery_version", id: "osquery_version", Cell: (cellProps: IHostTableStringCellProps) => { - if ( - cellProps.row.original.platform === "ios" || - cellProps.row.original.platform === "ipados" - ) { + if (isMobilePlatform(cellProps.row.original.platform)) { return NotSupported; } return ; @@ -332,6 +326,7 @@ const allHostTableHeaders: IHostTableColumnConfig[] = [ accessor: "device_mapping", id: "device_mapping", Cell: (cellProps: IDeviceUserCellProps) => { + // TODO(android): is android supported? const numUsers = cellProps.cell.value?.length || 0; const users = condenseDeviceUsers(cellProps.cell.value || []); if (users.length > 1) { @@ -364,10 +359,7 @@ const allHostTableHeaders: IHostTableColumnConfig[] = [ accessor: "primary_ip", id: "primary_ip", Cell: (cellProps: IHostTableStringCellProps) => { - if ( - cellProps.row.original.platform === "ios" || - cellProps.row.original.platform === "ipados" - ) { + if (isMobilePlatform(cellProps.row.original.platform)) { return NotSupported; } return ; @@ -442,10 +434,7 @@ const allHostTableHeaders: IHostTableColumnConfig[] = [ accessor: "public_ip", id: "public_ip", Cell: (cellProps: IHostTableStringCellProps) => { - if ( - cellProps.row.original.platform === "ios" || - cellProps.row.original.platform === "ipados" - ) { + if (isMobilePlatform(cellProps.row.original.platform)) { return NotSupported; } return ( @@ -478,6 +467,7 @@ const allHostTableHeaders: IHostTableColumnConfig[] = [ accessor: "detail_updated_at", id: "detail_updated_at", Cell: (cellProps: IHostTableStringCellProps) => ( + // TODO(android): android doesn't support refetch? { - if ( - cellProps.row.original.platform === "ios" || - cellProps.row.original.platform === "ipados" - ) { + if (isMobilePlatform(cellProps.row.original.platform)) { return NotSupported; } return ( @@ -546,11 +533,7 @@ const allHostTableHeaders: IHostTableColumnConfig[] = [ Cell: (cellProps: IHostTableStringCellProps) => { const { platform, last_restarted_at } = cellProps.row.original; - if ( - platform === "ios" || - platform === "ipados" || - platform === "chrome" - ) { + if (isMobilePlatform(platform) || platform === "chrome") { return NotSupported; } return ( @@ -608,9 +591,13 @@ const allHostTableHeaders: IHostTableColumnConfig[] = [ ), accessor: "primary_mac", id: "primary_mac", - Cell: (cellProps: IHostTableStringCellProps) => ( - - ), + Cell: (cellProps: IHostTableStringCellProps) => { + // TODO(android): is iOS/iPadOS supported? + if (isAndroid(cellProps.row.original.platform)) { + return NotSupported; + } + return ; + }, }, { title: "Serial number", @@ -622,9 +609,13 @@ const allHostTableHeaders: IHostTableColumnConfig[] = [ ), accessor: "hardware_serial", id: "hardware_serial", - Cell: (cellProps: IHostTableStringCellProps) => ( - - ), + Cell: (cellProps: IHostTableStringCellProps) => { + // TODO(android): is iOS/iPadOS supported? + if (isAndroid(cellProps.row.original.platform)) { + return NotSupported; + } + return ; + }, }, { title: "Hardware model", diff --git a/frontend/pages/hosts/components/DeleteHostModal/DeleteHostModal.tsx b/frontend/pages/hosts/components/DeleteHostModal/DeleteHostModal.tsx index 8f11661fa6..45a9356301 100644 --- a/frontend/pages/hosts/components/DeleteHostModal/DeleteHostModal.tsx +++ b/frontend/pages/hosts/components/DeleteHostModal/DeleteHostModal.tsx @@ -77,7 +77,11 @@ const DeleteHostModal = ({ newTab /> -
  • iOS and iPadOS hosts will re-appear unless MDM is turned off.
  • +
  • + {/* TODO(android): iOS, iPadOS, and Android hosts will re-appear unless MDM is turned + off. */} + iOS and iPadOS hosts will re-appear unless MDM is turned off. +