mirror of
https://github.com/empayre/fleet.git
synced 2024-11-06 08:55:24 +00:00
add verified status to UI for profile statuses (#11886)
relates to #11238 This implements the Verified status for the profile statute on the macOS settings pages and the Host Details and My Device pages. - [x] Changes file added for user-visible changes in `changes/` or `orbit/changes/`. - [x] Manual QA for all new/changed functionality
This commit is contained in:
parent
f140797938
commit
2c9c9b4f0e
@ -0,0 +1 @@
|
||||
- add "verified" profile status to fleet UI
|
@ -1,4 +1,19 @@
|
||||
import { IHost } from "interfaces/host";
|
||||
import { IHostMacMdmProfile } from "interfaces/mdm";
|
||||
|
||||
const DEFAULT_HOST_PROFILE_MOCK: IHostMacMdmProfile = {
|
||||
profile_id: 1,
|
||||
name: "Test Profile",
|
||||
operation_type: "install",
|
||||
status: "verified",
|
||||
detail: "This is verified",
|
||||
};
|
||||
|
||||
export const createMockHostMacMdmProfile = (
|
||||
overrides?: Partial<IHostMacMdmProfile>
|
||||
): IHostMacMdmProfile => {
|
||||
return { ...DEFAULT_HOST_PROFILE_MOCK, ...overrides };
|
||||
};
|
||||
|
||||
const DEFAULT_HOST_MOCK: IHost = {
|
||||
id: 1,
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { IHostMdmData } from "interfaces/host";
|
||||
import { IMdmSolution } from "interfaces/mdm";
|
||||
import { IMdmSolution, IMdmProfile } from "interfaces/mdm";
|
||||
|
||||
const DEFAULT_MDM_SOLUTION_MOCK: IMdmSolution = {
|
||||
id: 1,
|
||||
@ -14,6 +14,21 @@ export const createMockMdmSolution = (
|
||||
return { ...DEFAULT_MDM_SOLUTION_MOCK, ...overrides };
|
||||
};
|
||||
|
||||
const DEFAULT_MDM_PROFILE_DATA: IMdmProfile = {
|
||||
profile_id: 1,
|
||||
team_id: 0,
|
||||
name: "Test Profile",
|
||||
identifier: "com.test.profile",
|
||||
created_at: "2021-01-01T00:00:00Z",
|
||||
updated_at: "2021-01-01T00:00:00Z",
|
||||
};
|
||||
|
||||
export const createMockMdmProfile = (
|
||||
overrides?: Partial<IMdmProfile>
|
||||
): IMdmProfile => {
|
||||
return { ...DEFAULT_MDM_PROFILE_DATA, ...overrides };
|
||||
};
|
||||
|
||||
const DEFAULT_HOST_MDM_DATA: IHostMdmData = {
|
||||
encryption_key_available: false,
|
||||
enrollment_status: "On (automatic)",
|
||||
|
@ -70,7 +70,7 @@ export interface IMdmProfilesResponse {
|
||||
profiles: IMdmProfile[] | null;
|
||||
}
|
||||
|
||||
export type MdmProfileStatus = "verifying" | "pending" | "failed";
|
||||
export type MdmProfileStatus = "verified" | "verifying" | "pending" | "failed";
|
||||
|
||||
export type MacMdmProfileOperationType = "remove" | "install";
|
||||
|
||||
@ -83,22 +83,13 @@ export interface IHostMacMdmProfile {
|
||||
detail: string;
|
||||
}
|
||||
|
||||
export interface IFileVaultSummaryResponse {
|
||||
verifying: number;
|
||||
action_required: number;
|
||||
enforcing: number;
|
||||
failed: number;
|
||||
removing_enforcement: number;
|
||||
}
|
||||
|
||||
export enum FileVaultProfileStatus {
|
||||
VERIFIED = "verified",
|
||||
VERIFYING = "verifying",
|
||||
ACTION_REQUIRED = "action_required",
|
||||
ENFORCING = "enforcing",
|
||||
FAILED = "failed",
|
||||
REMOVING_ENFORCEMENT = "removing_enforcement",
|
||||
}
|
||||
export type FileVaultProfileStatus =
|
||||
| "verified"
|
||||
| "verifying"
|
||||
| "action_required"
|
||||
| "enforcing"
|
||||
| "failed"
|
||||
| "removing_enforcement";
|
||||
|
||||
// // TODO: update when list profiles API returns identifier
|
||||
// export const FLEET_FILEVAULT_PROFILE_IDENTIFIER =
|
||||
|
@ -18,26 +18,34 @@ interface IAggregateDisplayOption {
|
||||
}
|
||||
|
||||
const AGGREGATE_STATUS_DISPLAY_OPTIONS: IAggregateDisplayOption[] = [
|
||||
{
|
||||
value: "verified",
|
||||
text: "Verified",
|
||||
iconName: "success",
|
||||
tooltipText:
|
||||
"These hosts installed all configuration profiles. Fleet verified with osquery.",
|
||||
},
|
||||
{
|
||||
value: "verifying",
|
||||
text: "Verifying",
|
||||
iconName: "success-partial",
|
||||
tooltipText:
|
||||
"Hosts that told Fleet all settings are enforced. Fleet is verifying.",
|
||||
"These hosts acknowledged all MDM commands to install configuration profiles. " +
|
||||
"Fleet is verifying the profiles are installed with osquery.",
|
||||
},
|
||||
{
|
||||
value: "pending",
|
||||
text: "Pending",
|
||||
iconName: "pending-partial",
|
||||
tooltipText:
|
||||
"Hosts that will have settings enforced when the hosts come online.",
|
||||
"These hosts will receive MDM commands to install configuration profiles when the hosts come online.",
|
||||
},
|
||||
{
|
||||
value: "failed",
|
||||
text: "Failed",
|
||||
iconName: "error",
|
||||
tooltipText:
|
||||
"Hosts that failed to apply settings. Click on a host to view error(s).",
|
||||
"These hosts failed to install configuration profiles. Click on a host to view error(s).",
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -1,8 +1,7 @@
|
||||
import React from "react";
|
||||
import { useQuery } from "react-query";
|
||||
|
||||
import { IFileVaultSummaryResponse } from "interfaces/mdm";
|
||||
import mdmAPI from "services/entities/mdm";
|
||||
import mdmAPI, { IFileVaultSummaryResponse } from "services/entities/mdm";
|
||||
|
||||
import TableContainer from "components/TableContainer";
|
||||
import EmptyTable from "components/EmptyTable";
|
||||
@ -23,11 +22,10 @@ const DEFAULT_SORT_HEADER = "hosts";
|
||||
const DEFAULT_SORT_DIRECTION = "asc";
|
||||
|
||||
const DiskEncryptionTable = ({ currentTeamId }: IDiskEncryptionTableProps) => {
|
||||
const { data, error } = useQuery<
|
||||
IFileVaultSummaryResponse,
|
||||
Error,
|
||||
IFileVaultSummaryResponse
|
||||
>(
|
||||
const {
|
||||
data: diskEncryptionStatusData,
|
||||
error: diskEncryptionStatusError,
|
||||
} = useQuery<IFileVaultSummaryResponse, Error, IFileVaultSummaryResponse>(
|
||||
["disk-encryption-summary", currentTeamId],
|
||||
() => mdmAPI.getDiskEncryptionAggregate(currentTeamId),
|
||||
{
|
||||
@ -37,13 +35,14 @@ const DiskEncryptionTable = ({ currentTeamId }: IDiskEncryptionTableProps) => {
|
||||
);
|
||||
|
||||
const tableHeaders = generateTableHeaders();
|
||||
const tableData = generateTableData(data, currentTeamId);
|
||||
|
||||
if (error) {
|
||||
const tableData = generateTableData(diskEncryptionStatusData, currentTeamId);
|
||||
|
||||
if (diskEncryptionStatusError) {
|
||||
return <DataError />;
|
||||
}
|
||||
|
||||
if (!data) return null;
|
||||
if (!diskEncryptionStatusData) return null;
|
||||
|
||||
return (
|
||||
<div className={baseClass}>
|
||||
|
@ -1,9 +1,7 @@
|
||||
import React from "react";
|
||||
|
||||
import {
|
||||
FileVaultProfileStatus,
|
||||
IFileVaultSummaryResponse,
|
||||
} from "interfaces/mdm";
|
||||
import { FileVaultProfileStatus } from "interfaces/mdm";
|
||||
import { IFileVaultSummaryResponse } from "services/entities/mdm";
|
||||
|
||||
import TextCell from "components/TableContainer/DataTable/TextCell";
|
||||
import HeaderCell from "components/TableContainer/DataTable/HeaderCell";
|
||||
@ -115,19 +113,22 @@ const STATUS_CELL_VALUES: Record<FileVaultProfileStatus, IStatusCellValue> = {
|
||||
verified: {
|
||||
displayName: "Verified",
|
||||
statusName: "success",
|
||||
value: FileVaultProfileStatus.VERIFIED,
|
||||
tooltip: "Disk encryption on and key stored in Fleet. Fleet has verified.",
|
||||
value: "verified",
|
||||
tooltip:
|
||||
"These hosts turned disk encryption on and sent their key to Fleet. Fleet verified with osquery.",
|
||||
},
|
||||
verifying: {
|
||||
displayName: "Verifying",
|
||||
statusName: "successPartial",
|
||||
value: FileVaultProfileStatus.VERIFYING,
|
||||
tooltip: "Disk encryption on and key stored in Fleet. Fleet will verify.",
|
||||
value: "verifying",
|
||||
tooltip:
|
||||
"These hosts acknowledged the MDM command to install disk encryption profile. " +
|
||||
"Fleet is verifying with osquery and retrieving the disk encryption key. This may take up to one hour.",
|
||||
},
|
||||
action_required: {
|
||||
displayName: "Action required (pending)",
|
||||
statusName: "pendingPartial",
|
||||
value: FileVaultProfileStatus.ACTION_REQUIRED,
|
||||
value: "action_required",
|
||||
tooltip: (
|
||||
<>
|
||||
Ask the end user to follow <b>Disk encryption</b> instructions on their{" "}
|
||||
@ -138,19 +139,21 @@ const STATUS_CELL_VALUES: Record<FileVaultProfileStatus, IStatusCellValue> = {
|
||||
enforcing: {
|
||||
displayName: "Enforcing (pending)",
|
||||
statusName: "pendingPartial",
|
||||
value: FileVaultProfileStatus.ENFORCING,
|
||||
tooltip: "Setting will be enforced when the hosts come online.",
|
||||
value: "enforcing",
|
||||
tooltip:
|
||||
"These hosts will receive the MDM command to install the disk encryption profile when the hosts come online.",
|
||||
},
|
||||
failed: {
|
||||
displayName: "Failed",
|
||||
statusName: "error",
|
||||
value: FileVaultProfileStatus.FAILED,
|
||||
value: "failed",
|
||||
},
|
||||
removing_enforcement: {
|
||||
displayName: "Removing enforcement (pending)",
|
||||
statusName: "pendingPartial",
|
||||
value: FileVaultProfileStatus.REMOVING_ENFORCEMENT,
|
||||
tooltip: "Enforcement will be removed when the hosts come online.",
|
||||
value: "removing_enforcement",
|
||||
tooltip:
|
||||
"These hosts will receive the MDM command to remove the disk encryption profile when the hosts come online.",
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -53,6 +53,11 @@ export const getHostSelectStatuses = (isSandboxMode = false) => {
|
||||
};
|
||||
|
||||
export const MAC_SETTINGS_FILTER_OPTIONS = [
|
||||
{
|
||||
disabled: false,
|
||||
label: "Verified",
|
||||
value: "verified",
|
||||
},
|
||||
{
|
||||
disabled: false,
|
||||
label: "Verifying",
|
||||
|
@ -9,30 +9,35 @@ import { FileVaultProfileStatus } from "interfaces/mdm";
|
||||
const baseClass = "disk-encryption-status-filter";
|
||||
|
||||
const DISK_ENCRYPTION_STATUS_OPTIONS: IDropdownOption[] = [
|
||||
{
|
||||
disabled: false,
|
||||
label: "Verified",
|
||||
value: "verified",
|
||||
},
|
||||
{
|
||||
disabled: false,
|
||||
label: "Verifying",
|
||||
value: FileVaultProfileStatus.VERIFYING,
|
||||
value: "verifying",
|
||||
},
|
||||
{
|
||||
disabled: false,
|
||||
label: "Action required",
|
||||
value: FileVaultProfileStatus.ACTION_REQUIRED,
|
||||
value: "action_required",
|
||||
},
|
||||
{
|
||||
disabled: false,
|
||||
label: "Enforcing",
|
||||
value: FileVaultProfileStatus.ENFORCING,
|
||||
value: "enforcing",
|
||||
},
|
||||
{
|
||||
disabled: false,
|
||||
label: "Failed",
|
||||
value: FileVaultProfileStatus.FAILED,
|
||||
value: "failed",
|
||||
},
|
||||
{
|
||||
disabled: false,
|
||||
label: "Removing enforcement",
|
||||
value: FileVaultProfileStatus.REMOVING_ENFORCEMENT,
|
||||
value: "removing_enforcement",
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -411,7 +411,7 @@ const DeviceUserPage = ({
|
||||
bootstrapPackageData={bootstrapPackageData}
|
||||
isPremiumTier={isPremiumTier}
|
||||
toggleMacSettingsModal={toggleMacSettingsModal}
|
||||
hostMacSettings={host?.mdm.profiles ?? []}
|
||||
hostMdmProfiles={host?.mdm.profiles ?? []}
|
||||
mdmName={deviceMacAdminsData?.mobile_device_management?.name}
|
||||
showRefetchSpinner={showRefetchSpinner}
|
||||
onRefetchHost={onRefetchHost}
|
||||
|
@ -42,6 +42,8 @@ import {
|
||||
} from "utilities/helpers";
|
||||
import permissions from "utilities/permissions";
|
||||
|
||||
import { createMockHostMacMdmProfile } from "__mocks__/hostMock";
|
||||
|
||||
import HostSummaryCard from "../cards/HostSummary";
|
||||
import AboutCard from "../cards/About";
|
||||
import AgentOptionsCard from "../cards/AgentOptions";
|
||||
@ -693,7 +695,7 @@ const HostDetailsPage = ({
|
||||
toggleOSPolicyModal={toggleOSPolicyModal}
|
||||
toggleMacSettingsModal={toggleMacSettingsModal}
|
||||
toggleBootstrapPackageModal={toggleBootstrapPackageModal}
|
||||
hostMacSettings={host?.mdm.profiles ?? []}
|
||||
hostMdmProfiles={host?.mdm.profiles ?? []}
|
||||
mdmName={mdm?.name}
|
||||
showRefetchSpinner={showRefetchSpinner}
|
||||
onRefetchHost={onRefetchHost}
|
||||
|
@ -8,7 +8,6 @@ import { generateTableData } from "./MacSettingsTable/MacSettingsTableConfig";
|
||||
|
||||
interface IMacSettingsModalProps {
|
||||
hostMDMData?: Pick<IHostMdmData, "profiles" | "macos_settings">;
|
||||
isDeviceUser?: boolean;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,11 @@ describe("Mac setting status cell", () => {
|
||||
const operationType: MacMdmProfileOperationType = "install";
|
||||
|
||||
render(
|
||||
<MacSettingStatusCell status={status} operationType={operationType} />
|
||||
<MacSettingStatusCell
|
||||
profileName="Test Profile"
|
||||
status={status}
|
||||
operationType={operationType}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(screen.getByText("Verifying")).toBeInTheDocument();
|
||||
@ -23,13 +27,17 @@ describe("Mac setting status cell", () => {
|
||||
const customRender = createCustomRenderer();
|
||||
|
||||
const { user } = customRender(
|
||||
<MacSettingStatusCell status={status} operationType={operationType} />
|
||||
<MacSettingStatusCell
|
||||
profileName="Test Profile"
|
||||
status={status}
|
||||
operationType={operationType}
|
||||
/>
|
||||
);
|
||||
|
||||
const statusText = screen.getByText("Verifying");
|
||||
|
||||
await user.hover(statusText);
|
||||
|
||||
expect(screen.getByText("Host applied the setting.")).toBeInTheDocument();
|
||||
expect(screen.getByText(/verifying/)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
@ -5,7 +5,10 @@ import { uniqueId } from "lodash";
|
||||
import Icon from "components/Icon";
|
||||
import { IconNames } from "components/icons";
|
||||
import TextCell from "components/TableContainer/DataTable/TextCell";
|
||||
import { MacMdmProfileOperationType } from "interfaces/mdm";
|
||||
import {
|
||||
FLEET_FILEVAULT_PROFILE_DISPLAY_NAME,
|
||||
MacMdmProfileOperationType,
|
||||
} from "interfaces/mdm";
|
||||
|
||||
import { MacSettingsTableStatusValue } from "../MacSettingsTableConfig";
|
||||
import TooltipContent, {
|
||||
@ -36,17 +39,36 @@ const PROFILE_DISPLAY_CONFIG: ProfileDisplayConfig = {
|
||||
pending: {
|
||||
statusText: "Enforcing (pending)",
|
||||
iconName: "pending-partial",
|
||||
tooltip: "Setting will be enforced when the host comes online.", // TODO: this doesn't work for disk encryption or the device page generally
|
||||
tooltip: (innerProps) =>
|
||||
innerProps.isDiskEncryptionProfile
|
||||
? "The host will receive the MDM command to install the disk encryption profile when the " +
|
||||
"host comes online."
|
||||
: "The host will receive the MDM command to install the configuration profile when the " +
|
||||
"host comes online.",
|
||||
},
|
||||
action_required: {
|
||||
statusText: "Action required (pending)",
|
||||
iconName: "pending-partial",
|
||||
tooltip: TooltipInnerContentActionRequired as TooltipInnerContentFunc,
|
||||
},
|
||||
verified: {
|
||||
statusText: "Verified",
|
||||
iconName: "success",
|
||||
tooltip: (innerProps) =>
|
||||
innerProps.isDiskEncryptionProfile
|
||||
? "The host turned disk encryption on and " +
|
||||
"sent their key to Fleet. Fleet verified with osquery."
|
||||
: "The host installed the configuration profile. Fleet verified with osquery.",
|
||||
},
|
||||
verifying: {
|
||||
statusText: "Verifying",
|
||||
iconName: "success-partial",
|
||||
tooltip: "Host applied the setting.",
|
||||
tooltip: (innerProps) =>
|
||||
innerProps.isDiskEncryptionProfile
|
||||
? "The host acknowledged the MDM command to install disk encryption profile. Fleet is " +
|
||||
"verifying with osquery and retrieving the disk encryption key. This may take up to one hour."
|
||||
: "The host acknowledged the MDM command to install the configuration profile. Fleet is " +
|
||||
"verifying with osquery.",
|
||||
},
|
||||
failed: {
|
||||
statusText: "Failed",
|
||||
@ -58,9 +80,15 @@ const PROFILE_DISPLAY_CONFIG: ProfileDisplayConfig = {
|
||||
pending: {
|
||||
statusText: "Removing enforcement (pending)",
|
||||
iconName: "pending-partial",
|
||||
tooltip: "Enforcement will be removed when the host comes online.",
|
||||
tooltip: (innerProps) =>
|
||||
innerProps.isDiskEncryptionProfile
|
||||
? "The host will receive the MDM command to remove the disk encryption profile when the " +
|
||||
"host comes online."
|
||||
: "The host will receive the MDM command to remove the configuration profile when the host " +
|
||||
"comes online.",
|
||||
},
|
||||
action_required: null, // should not be reached
|
||||
verified: null, // should not be reached
|
||||
verifying: null, // should not be reached
|
||||
failed: {
|
||||
statusText: "Failed",
|
||||
@ -73,7 +101,7 @@ const PROFILE_DISPLAY_CONFIG: ProfileDisplayConfig = {
|
||||
interface IMacSettingStatusCellProps {
|
||||
status: MacSettingsTableStatusValue;
|
||||
operationType: MacMdmProfileOperationType;
|
||||
profileName?: string;
|
||||
profileName: string;
|
||||
}
|
||||
|
||||
const MacSettingStatusCell = ({
|
||||
@ -81,14 +109,17 @@ const MacSettingStatusCell = ({
|
||||
operationType,
|
||||
profileName = "",
|
||||
}: IMacSettingStatusCellProps): JSX.Element => {
|
||||
const options = PROFILE_DISPLAY_CONFIG[operationType]?.[status];
|
||||
// TODO: confirm this approach
|
||||
const diplayOption = PROFILE_DISPLAY_CONFIG[operationType]?.[status];
|
||||
|
||||
const isDeviceUser = window.location.pathname
|
||||
.toLowerCase()
|
||||
.includes("/device/");
|
||||
|
||||
if (options) {
|
||||
const { statusText, iconName, tooltip } = options;
|
||||
const isDiskEncryptionProfile =
|
||||
profileName === FLEET_FILEVAULT_PROFILE_DISPLAY_NAME;
|
||||
|
||||
if (diplayOption) {
|
||||
const { statusText, iconName, tooltip } = diplayOption;
|
||||
const tooltipId = uniqueId();
|
||||
return (
|
||||
<span className={baseClass}>
|
||||
@ -111,10 +142,19 @@ const MacSettingStatusCell = ({
|
||||
data-html
|
||||
>
|
||||
<span className="tooltip__tooltip-text">
|
||||
<TooltipContent
|
||||
innerContent={tooltip}
|
||||
innerProps={{ isDeviceUser, profileName }}
|
||||
/>
|
||||
{status !== "action_required" ? (
|
||||
<TooltipContent
|
||||
innerContent={tooltip}
|
||||
innerProps={{
|
||||
isDiskEncryptionProfile,
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<TooltipContent
|
||||
innerContent={tooltip}
|
||||
innerProps={{ isDeviceUser, profileName }}
|
||||
/>
|
||||
)}
|
||||
</span>
|
||||
</ReactTooltip>
|
||||
</>
|
||||
|
@ -40,7 +40,7 @@ interface IHostSummaryProps {
|
||||
toggleOSPolicyModal?: () => void;
|
||||
toggleMacSettingsModal?: () => void;
|
||||
toggleBootstrapPackageModal?: () => void;
|
||||
hostMacSettings?: IHostMacMdmProfile[];
|
||||
hostMdmProfiles?: IHostMacMdmProfile[];
|
||||
mdmName?: string;
|
||||
showRefetchSpinner: boolean;
|
||||
onRefetchHost: (
|
||||
@ -60,7 +60,7 @@ const HostSummary = ({
|
||||
toggleOSPolicyModal,
|
||||
toggleMacSettingsModal,
|
||||
toggleBootstrapPackageModal,
|
||||
hostMacSettings,
|
||||
hostMdmProfiles,
|
||||
mdmName,
|
||||
showRefetchSpinner,
|
||||
onRefetchHost,
|
||||
@ -155,6 +155,7 @@ const HostSummary = ({
|
||||
|
||||
const renderSummary = () => {
|
||||
const { status, id } = titleData;
|
||||
|
||||
return (
|
||||
<div className="info-flex">
|
||||
<div className="info-flex__item info-flex__item--title">
|
||||
@ -178,11 +179,11 @@ const HostSummary = ({
|
||||
{titleData.platform === "darwin" &&
|
||||
isPremiumTier &&
|
||||
mdmName === "Fleet" && // show if 1 - host is enrolled in Fleet MDM, and
|
||||
hostMacSettings &&
|
||||
hostMacSettings.length > 0 && ( // 2 - host has at least one setting (profile) enforced
|
||||
hostMdmProfiles &&
|
||||
hostMdmProfiles.length > 0 && ( // 2 - host has at least one setting (profile) enforced
|
||||
<HostSummaryIndicator title="macOS settings">
|
||||
<MacSettingsIndicator
|
||||
profiles={hostMacSettings}
|
||||
profiles={hostMdmProfiles}
|
||||
onClick={toggleMacSettingsModal}
|
||||
/>
|
||||
</HostSummaryIndicator>
|
||||
|
@ -9,7 +9,7 @@ import { IconNames } from "components/icons";
|
||||
|
||||
const baseClass = "mac-settings-indicator";
|
||||
|
||||
type MacSettingsStatus = "Failing" | "Verifying" | "Pending";
|
||||
type MacProfileStatus = "Failed" | "Verifying" | "Pending" | "Verified";
|
||||
|
||||
interface IStatusDisplayOption {
|
||||
iconName: Extract<
|
||||
@ -18,35 +18,53 @@ interface IStatusDisplayOption {
|
||||
>;
|
||||
tooltipText: string;
|
||||
}
|
||||
type StatusDisplayOptions = Record<MacSettingsStatus, IStatusDisplayOption>;
|
||||
type StatusDisplayOptions = Record<MacProfileStatus, IStatusDisplayOption>;
|
||||
|
||||
const STATUS_DISPLAY_OPTIONS: StatusDisplayOptions = {
|
||||
Verified: {
|
||||
iconName: "success",
|
||||
tooltipText:
|
||||
"The host installed all configuration profiles. Fleet verified with osquery.",
|
||||
},
|
||||
Verifying: {
|
||||
iconName: "success-partial",
|
||||
tooltipText: "Host applied the latest settings",
|
||||
tooltipText:
|
||||
"The hosts acknowledged all MDM commands to install configuration profiles. Fleet is verifying " +
|
||||
"the profiles are installed with osquery.",
|
||||
},
|
||||
Pending: {
|
||||
iconName: "pending-partial",
|
||||
tooltipText: "Host will apply the latest settings when it comes online",
|
||||
tooltipText:
|
||||
"The host will receive MDM commands to install configuration profiles when the host come online.",
|
||||
},
|
||||
Failing: {
|
||||
Failed: {
|
||||
iconName: "error",
|
||||
tooltipText:
|
||||
"Host failed to apply the latest settings. Click to view error(s).",
|
||||
"Host failed to install configuration profiles. Click to view error(s).",
|
||||
},
|
||||
};
|
||||
|
||||
const getMacSettingsStatus = (
|
||||
hostMacSettings?: IHostMacMdmProfile[]
|
||||
): MacSettingsStatus => {
|
||||
const statuses = hostMacSettings?.map((setting) => setting.status);
|
||||
if (statuses?.includes("failed")) {
|
||||
return "Failing";
|
||||
/**
|
||||
* Returns the displayed status of the macOS settings field based on the
|
||||
* profile statuses.
|
||||
* If any profile has a status of "failed", the status will be displayed as "Failed" and
|
||||
* continues to fall through to "Pending" and "Verifying" if any profiles have those statuses.
|
||||
* Finally if all profiles have a status of "verified", the status will be displayed as "Verified".
|
||||
*/
|
||||
const getMacProfileStatus = (
|
||||
hostMacSettings: IHostMacMdmProfile[]
|
||||
): MacProfileStatus => {
|
||||
const statuses = hostMacSettings.map((setting) => setting.status);
|
||||
if (statuses.includes("failed")) {
|
||||
return "Failed";
|
||||
}
|
||||
if (statuses?.includes("pending")) {
|
||||
if (statuses.includes("pending")) {
|
||||
return "Pending";
|
||||
}
|
||||
return "Verifying";
|
||||
if (statuses.includes("verifying")) {
|
||||
return "Verifying";
|
||||
}
|
||||
return "Verified";
|
||||
};
|
||||
|
||||
interface IMacSettingsIndicatorProps {
|
||||
@ -57,14 +75,13 @@ const MacSettingsIndicator = ({
|
||||
profiles,
|
||||
onClick,
|
||||
}: IMacSettingsIndicatorProps): JSX.Element => {
|
||||
const macSettingsStatus = getMacSettingsStatus(profiles);
|
||||
const macProfileStatus = getMacProfileStatus(profiles);
|
||||
|
||||
const iconName = STATUS_DISPLAY_OPTIONS[macSettingsStatus].iconName;
|
||||
const tooltipText = STATUS_DISPLAY_OPTIONS[macSettingsStatus].tooltipText;
|
||||
const statusDisplayOption = STATUS_DISPLAY_OPTIONS[macProfileStatus];
|
||||
|
||||
return (
|
||||
<span className={`${baseClass} info-flex__data`}>
|
||||
<Icon name={iconName} />
|
||||
<Icon name={statusDisplayOption.iconName} />
|
||||
<span
|
||||
className="tooltip tooltip__tooltip-icon"
|
||||
data-tip
|
||||
@ -76,7 +93,7 @@ const MacSettingsIndicator = ({
|
||||
variant="text-link"
|
||||
className={`${baseClass}__button`}
|
||||
>
|
||||
{macSettingsStatus}
|
||||
{macProfileStatus}
|
||||
</Button>
|
||||
</span>
|
||||
<ReactTooltip
|
||||
@ -86,7 +103,9 @@ const MacSettingsIndicator = ({
|
||||
id={`${baseClass}-tooltip`}
|
||||
data-html
|
||||
>
|
||||
<span className="tooltip__tooltip-text">{tooltipText}</span>
|
||||
<span className="tooltip__tooltip-text">
|
||||
{statusDisplayOption.tooltipText}
|
||||
</span>
|
||||
</ReactTooltip>
|
||||
</span>
|
||||
);
|
||||
|
@ -1,9 +1,12 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { FileVaultProfileStatus } from "interfaces/mdm";
|
||||
import { APP_CONTEXT_NO_TEAM_ID } from "interfaces/team";
|
||||
import sendRequest from "services";
|
||||
import endpoints from "utilities/endpoints";
|
||||
import { buildQueryStringFromParams } from "utilities/url";
|
||||
|
||||
export type IFileVaultSummaryResponse = Record<FileVaultProfileStatus, number>;
|
||||
|
||||
export interface IEulaMetadataResponse {
|
||||
name: string;
|
||||
token: string;
|
||||
|
Loading…
Reference in New Issue
Block a user