mirror of
https://github.com/empayre/fleet.git
synced 2024-11-06 08:55:24 +00:00
Fleet UI: MDM pending hosts (#9427)
This commit is contained in:
parent
a1ccbf4c3b
commit
c467aaad73
1
changes/8878-pending-hosts-ui
Normal file
1
changes/8878-pending-hosts-ui
Normal file
@ -0,0 +1 @@
|
||||
- Fleet Premium shows pending hosts on the dashboard and manage host page
|
@ -32,6 +32,8 @@ const DEFAULT_HOST_MOCK: IHost = {
|
||||
hardware_version: "",
|
||||
hardware_serial: "",
|
||||
computer_name: "9b20fc72a247",
|
||||
mdm_enrollment_status: "Off",
|
||||
mdm_server_url: "https://www.example.com/1",
|
||||
public_ip: "",
|
||||
primary_ip: "172.23.0.3",
|
||||
primary_mac: "02:42:ac:17:00:03",
|
||||
|
@ -3,7 +3,7 @@ import { IMacadminsResponse } from "interfaces/host";
|
||||
const DEFAULT_MAC_ADMINS_MOCK: IMacadminsResponse = {
|
||||
macadmins: {
|
||||
mobile_device_management: {
|
||||
enrollment_status: "Enrolled (manual)",
|
||||
enrollment_status: "On (manual)",
|
||||
server_url: "https://kandji.com/2",
|
||||
name: "Kandji",
|
||||
id: 11,
|
||||
|
@ -24,7 +24,7 @@ const EmptyTable = ({
|
||||
</div>
|
||||
)}
|
||||
<div className={`${baseClass}__inner`}>
|
||||
{header && <h2>{header}</h2>}
|
||||
{header && <h3>{header}</h3>}
|
||||
{info && <p>{info}</p>}
|
||||
{additionalInfo && <p>{additionalInfo}</p>}
|
||||
</div>
|
||||
|
@ -13,8 +13,8 @@
|
||||
flex-direction: column;
|
||||
gap: $pad-small; // 4px from header to info text
|
||||
|
||||
h2,
|
||||
h2 a {
|
||||
h3,
|
||||
h3 a {
|
||||
text-align: center;
|
||||
font-size: $small;
|
||||
font-weight: $bold;
|
||||
|
@ -42,7 +42,7 @@
|
||||
}
|
||||
&__tip-text {
|
||||
width: max-content;
|
||||
max-width: 341px;
|
||||
max-width: 360px;
|
||||
padding: 6px;
|
||||
color: $core-white;
|
||||
background-color: $core-fleet-blue;
|
||||
@ -58,6 +58,7 @@
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
line-height: 1.375;
|
||||
white-space: initial;
|
||||
|
||||
// invisible block to cover space so
|
||||
// hover state can continue from text to bubble
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from "react";
|
||||
import PATHS from "router/paths";
|
||||
import { Link, browserHistory } from "react-router";
|
||||
import { Link } from "react-router";
|
||||
import classnames from "classnames";
|
||||
|
||||
import Icon from "components/Icon";
|
||||
|
@ -7,6 +7,7 @@ import softwareInterface, { ISoftware } from "./software";
|
||||
import hostQueryResult from "./campaign";
|
||||
import queryStatsInterface, { IQueryStats } from "./query_stats";
|
||||
import { ILicense } from "./config";
|
||||
import { MdmStatus } from "./mdm";
|
||||
|
||||
export default PropTypes.shape({
|
||||
created_at: PropTypes.string,
|
||||
@ -202,7 +203,8 @@ export interface IHost {
|
||||
users: IHostUser[];
|
||||
device_users?: IDeviceUser[];
|
||||
munki?: IMunkiData;
|
||||
mdm?: IHostMdmData;
|
||||
mdm_enrollment_status: MdmStatus;
|
||||
mdm_server_url: string;
|
||||
policies: IHostPolicy[];
|
||||
query_results?: unknown[];
|
||||
geolocation?: IGeoLocation;
|
||||
|
@ -13,8 +13,17 @@ export interface IMdmAppleBm {
|
||||
renew_date: string;
|
||||
}
|
||||
|
||||
export interface IMdmEnrollmentCardData {
|
||||
status: "On (manual)" | "On (automatic)" | "Off";
|
||||
export const MDM_STATUS = {
|
||||
"On (manual)": "manual",
|
||||
"On (automatic)": "automatic",
|
||||
Off: "unenrolled",
|
||||
Pending: "pending",
|
||||
};
|
||||
|
||||
export type MdmStatus = keyof typeof MDM_STATUS;
|
||||
|
||||
export interface IMdmStatusCardData {
|
||||
status: MdmStatus;
|
||||
hosts: number;
|
||||
}
|
||||
|
||||
@ -22,6 +31,7 @@ export interface IMdmAggregateStatus {
|
||||
enrolled_manual_hosts_count: number;
|
||||
enrolled_automated_hosts_count: number;
|
||||
unenrolled_hosts_count: number;
|
||||
pending_hosts_count?: number;
|
||||
}
|
||||
|
||||
export interface IMdmSolution {
|
||||
@ -31,15 +41,16 @@ export interface IMdmSolution {
|
||||
hosts_count: number;
|
||||
}
|
||||
|
||||
interface IMdmEnrollementStatus {
|
||||
interface IMdmStatus {
|
||||
enrolled_manual_hosts_count: number;
|
||||
enrolled_automated_hosts_count: number;
|
||||
unenrolled_hosts_count: number;
|
||||
pending_hosts_count?: number;
|
||||
hosts_count: number;
|
||||
}
|
||||
|
||||
export interface IMdmSummaryResponse {
|
||||
counts_updated_at: string;
|
||||
mobile_device_management_enrollment_status: IMdmEnrollementStatus;
|
||||
mobile_device_management_enrollment_status: IMdmStatus;
|
||||
mobile_device_management_solution: IMdmSolution[] | null;
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ import {
|
||||
IMunkiVersionsAggregate,
|
||||
} from "interfaces/macadmins";
|
||||
import {
|
||||
IMdmEnrollmentCardData,
|
||||
IMdmStatusCardData,
|
||||
IMdmSolution,
|
||||
IMdmSummaryResponse,
|
||||
} from "interfaces/mdm";
|
||||
@ -113,9 +113,7 @@ const DashboardPage = ({
|
||||
const [showAddHostsModal, setShowAddHostsModal] = useState(false);
|
||||
const [showOperatingSystemsUI, setShowOperatingSystemsUI] = useState(false);
|
||||
const [showHostsUI, setShowHostsUI] = useState(false); // Hides UI on first load only
|
||||
const [mdmEnrollmentData, setMdmEnrollmentData] = useState<
|
||||
IMdmEnrollmentCardData[]
|
||||
>([]);
|
||||
const [mdmStatusData, setMdmStatusData] = useState<IMdmStatusCardData[]>([]);
|
||||
const [mdmSolutions, setMdmSolutions] = useState<IMdmSolution[] | null>([]);
|
||||
|
||||
const [munkiIssuesData, setMunkiIssuesData] = useState<
|
||||
@ -293,6 +291,7 @@ const DashboardPage = ({
|
||||
enrolled_manual_hosts_count,
|
||||
enrolled_automated_hosts_count,
|
||||
unenrolled_hosts_count,
|
||||
pending_hosts_count,
|
||||
hosts_count,
|
||||
} = mobile_device_management_enrollment_status;
|
||||
|
||||
@ -307,7 +306,7 @@ const DashboardPage = ({
|
||||
whatToRetrieve={"MDM information"}
|
||||
/>
|
||||
);
|
||||
setMdmEnrollmentData([
|
||||
const statusData: IMdmStatusCardData[] = [
|
||||
{
|
||||
status: "On (manual)",
|
||||
hosts: enrolled_manual_hosts_count,
|
||||
@ -317,7 +316,13 @@ const DashboardPage = ({
|
||||
hosts: enrolled_automated_hosts_count,
|
||||
},
|
||||
{ status: "Off", hosts: unenrolled_hosts_count },
|
||||
]);
|
||||
];
|
||||
isPremiumTier &&
|
||||
statusData.push({
|
||||
status: "Pending",
|
||||
hosts: pending_hosts_count || 0,
|
||||
});
|
||||
setMdmStatusData(statusData);
|
||||
setMdmSolutions(mobile_device_management_solution);
|
||||
setShowMdmCard(true);
|
||||
},
|
||||
@ -552,13 +557,13 @@ const DashboardPage = ({
|
||||
titleDetail: mdmTitleDetail,
|
||||
showTitle: !isMacAdminsFetching,
|
||||
description: (
|
||||
<p>MDM can be used to manage configuration on your workstations.</p>
|
||||
<p>MDM is used to change settings and install software on your hosts.</p>
|
||||
),
|
||||
children: (
|
||||
<Mdm
|
||||
isFetching={isMdmFetching}
|
||||
error={errorMdm}
|
||||
mdmEnrollmentData={mdmEnrollmentData}
|
||||
mdmStatusData={mdmStatusData}
|
||||
mdmSolutions={mdmSolutions}
|
||||
selectedPlatformLabelId={selectedPlatformLabelId}
|
||||
/>
|
||||
|
@ -12,7 +12,7 @@ describe("MDM Card", () => {
|
||||
<MDM
|
||||
error={null}
|
||||
isFetching={false}
|
||||
mdmEnrollmentData={[]}
|
||||
mdmStatusData={[]}
|
||||
mdmSolutions={[
|
||||
createMockMdmSolution(),
|
||||
createMockMdmSolution({ id: 2 }),
|
||||
@ -28,16 +28,17 @@ describe("MDM Card", () => {
|
||||
<MDM
|
||||
error={null}
|
||||
isFetching={false}
|
||||
mdmEnrollmentData={[
|
||||
mdmStatusData={[
|
||||
{ status: "On (automatic)", hosts: 10 },
|
||||
{ status: "On (manual)", hosts: 5 },
|
||||
{ status: "Off", hosts: 1 },
|
||||
{ status: "Pending", hosts: 3 },
|
||||
]}
|
||||
mdmSolutions={[]}
|
||||
/>
|
||||
);
|
||||
|
||||
await user.click(screen.getByRole("tab", { name: "Enrollment" }));
|
||||
await user.click(screen.getByRole("tab", { name: "Status" }));
|
||||
|
||||
expect(
|
||||
screen.getByRole("row", {
|
||||
@ -54,5 +55,10 @@ describe("MDM Card", () => {
|
||||
name: /Off(.*?)1 host/i,
|
||||
})
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole("row", {
|
||||
name: /Pending(.*?)3 host/i,
|
||||
})
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
@ -1,67 +1,67 @@
|
||||
import React, { useState } from "react";
|
||||
import { Tab, Tabs, TabList, TabPanel } from "react-tabs";
|
||||
|
||||
import { IMdmEnrollmentCardData, IMdmSolution } from "interfaces/mdm";
|
||||
import { IMdmStatusCardData, IMdmSolution } from "interfaces/mdm";
|
||||
|
||||
import TabsWrapper from "components/TabsWrapper";
|
||||
import TableContainer from "components/TableContainer";
|
||||
import Spinner from "components/Spinner";
|
||||
import TableDataError from "components/DataError";
|
||||
import EmptyTable from "components/EmptyTable";
|
||||
import CustomLink from "components/CustomLink";
|
||||
|
||||
import {
|
||||
generateSolutionsTableHeaders,
|
||||
generateSolutionsDataSet,
|
||||
} from "./MDMSolutionsTableConfig";
|
||||
import {
|
||||
generateEnrollmentTableHeaders,
|
||||
generateEnrollmentDataSet,
|
||||
} from "./MDMEnrollmentTableConfig";
|
||||
generateStatusTableHeaders,
|
||||
generateStatusDataSet,
|
||||
} from "./MDMStatusTableConfig";
|
||||
|
||||
interface IMdmCardProps {
|
||||
error: Error | null;
|
||||
isFetching: boolean;
|
||||
mdmEnrollmentData: IMdmEnrollmentCardData[];
|
||||
mdmStatusData: IMdmStatusCardData[];
|
||||
mdmSolutions: IMdmSolution[] | null;
|
||||
selectedPlatformLabelId?: number;
|
||||
}
|
||||
|
||||
const DEFAULT_SORT_DIRECTION = "desc";
|
||||
const SOLUTIONS_DEFAULT_SORT_HEADER = "hosts_count";
|
||||
const ENROLLMENT_DEFAULT_SORT_DIRECTION = "asc";
|
||||
const ENROLLMENT_DEFAULT_SORT_HEADER = "status";
|
||||
const STATUS_DEFAULT_SORT_DIRECTION = "asc";
|
||||
const STATUS_DEFAULT_SORT_HEADER = "status";
|
||||
const PAGE_SIZE = 8;
|
||||
const baseClass = "home-mdm";
|
||||
|
||||
const EmptyMdmEnrollment = (): JSX.Element => (
|
||||
<div className={`${baseClass}__empty-mdm`}>
|
||||
<h1>Unable to detect MDM enrollment</h1>
|
||||
<p>
|
||||
To see MDM versions, deploy
|
||||
<a
|
||||
href="https://fleetdm.com/docs/using-fleet/adding-hosts#osquery-installer"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Fleet's osquery installer
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
const EmptyMdmStatus = (): JSX.Element => (
|
||||
<EmptyTable
|
||||
header="Unable to detect MDM enrollment"
|
||||
info={
|
||||
<>
|
||||
To see MDM versions, deploy
|
||||
<CustomLink
|
||||
url="https://fleetdm.com/docs/using-fleet/adding-hosts#osquery-installer"
|
||||
newTab
|
||||
text="Fleet's osquery installer"
|
||||
/>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
||||
const EmptyMdmSolutions = (): JSX.Element => (
|
||||
<div className={`${baseClass}__empty-mdm`}>
|
||||
<h1>No MDM solutions detected</h1>
|
||||
<p>
|
||||
This report is updated every hour to protect the performance of your
|
||||
devices.
|
||||
</p>
|
||||
</div>
|
||||
<EmptyTable
|
||||
header="No MDM solutions detected"
|
||||
info="This report is updated every hour to protect the performance of your
|
||||
devices."
|
||||
/>
|
||||
);
|
||||
|
||||
const Mdm = ({
|
||||
isFetching,
|
||||
error,
|
||||
mdmEnrollmentData,
|
||||
mdmStatusData,
|
||||
mdmSolutions,
|
||||
selectedPlatformLabelId,
|
||||
}: IMdmCardProps): JSX.Element => {
|
||||
@ -72,13 +72,13 @@ const Mdm = ({
|
||||
};
|
||||
|
||||
const solutionsTableHeaders = generateSolutionsTableHeaders();
|
||||
const enrollmentTableHeaders = generateEnrollmentTableHeaders();
|
||||
const statusTableHeaders = generateStatusTableHeaders();
|
||||
const solutionsDataSet = generateSolutionsDataSet(
|
||||
mdmSolutions,
|
||||
selectedPlatformLabelId
|
||||
);
|
||||
const enrollmentDataSet = generateEnrollmentDataSet(
|
||||
mdmEnrollmentData,
|
||||
const statusDataSet = generateStatusDataSet(
|
||||
mdmStatusData,
|
||||
selectedPlatformLabelId
|
||||
);
|
||||
|
||||
@ -97,7 +97,7 @@ const Mdm = ({
|
||||
<Tabs selectedIndex={navTabIndex} onSelect={onTabChange}>
|
||||
<TabList>
|
||||
<Tab>Solutions</Tab>
|
||||
<Tab>Enrollment</Tab>
|
||||
<Tab>Status</Tab>
|
||||
</TabList>
|
||||
<TabPanel>
|
||||
{error ? (
|
||||
@ -126,14 +126,14 @@ const Mdm = ({
|
||||
<TableDataError card />
|
||||
) : (
|
||||
<TableContainer
|
||||
columns={enrollmentTableHeaders}
|
||||
data={enrollmentDataSet}
|
||||
columns={statusTableHeaders}
|
||||
data={statusDataSet}
|
||||
isLoading={isFetching}
|
||||
defaultSortHeader={ENROLLMENT_DEFAULT_SORT_HEADER}
|
||||
defaultSortDirection={ENROLLMENT_DEFAULT_SORT_DIRECTION}
|
||||
defaultSortHeader={STATUS_DEFAULT_SORT_HEADER}
|
||||
defaultSortDirection={STATUS_DEFAULT_SORT_DIRECTION}
|
||||
hideActionButton
|
||||
resultsTitle={"MDM"}
|
||||
emptyComponent={EmptyMdmEnrollment}
|
||||
emptyComponent={EmptyMdmStatus}
|
||||
showMarkAllPages={false}
|
||||
isAllPagesSelected={false}
|
||||
disableCount
|
||||
|
@ -1,145 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
import { IMdmEnrollmentCardData } from "interfaces/mdm";
|
||||
|
||||
import TextCell from "components/TableContainer/DataTable/TextCell";
|
||||
import TooltipWrapper from "components/TooltipWrapper";
|
||||
import ViewAllHostsLink from "components/ViewAllHostsLink";
|
||||
|
||||
interface IMdmEnrollmentData extends IMdmEnrollmentCardData {
|
||||
selectedPlatformLabelId?: number;
|
||||
}
|
||||
|
||||
// NOTE: cellProps come from react-table
|
||||
// more info here https://react-table.tanstack.com/docs/api/useTable#cell-properties
|
||||
interface ICellProps {
|
||||
cell: {
|
||||
value: string;
|
||||
};
|
||||
row: {
|
||||
original: IMdmEnrollmentData;
|
||||
};
|
||||
}
|
||||
|
||||
interface IHeaderProps {
|
||||
column: {
|
||||
title: string;
|
||||
isSortedDesc: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
interface IStringCellProps extends ICellProps {
|
||||
cell: {
|
||||
value: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface IDataColumn {
|
||||
title: string;
|
||||
Header: ((props: IHeaderProps) => JSX.Element) | string;
|
||||
accessor: string;
|
||||
Cell: (props: ICellProps) => JSX.Element;
|
||||
disableHidden?: boolean;
|
||||
disableSortBy?: boolean;
|
||||
}
|
||||
|
||||
const enrollmentTableHeaders = [
|
||||
{
|
||||
title: "Status",
|
||||
Header: "Status",
|
||||
disableSortBy: true,
|
||||
accessor: "status",
|
||||
Cell: (cellProps: IStringCellProps) => {
|
||||
const tooltipText = (status: string): string => {
|
||||
if (status === "On (automatic)") {
|
||||
return `
|
||||
<span>
|
||||
Hosts automatically enrolled to an MDM solution <br />
|
||||
using Apple Automated Device Enrollment (DEP) <br />
|
||||
or Windows Autopilot. Administrators can block <br />
|
||||
users from unenrolling these hosts from MDM.
|
||||
</span>
|
||||
`;
|
||||
}
|
||||
return `
|
||||
<span>
|
||||
Hosts manually enrolled to an MDM solution. Users <br />
|
||||
can unenroll these hosts from MDM.
|
||||
</span>
|
||||
`;
|
||||
};
|
||||
|
||||
if (cellProps.cell.value === "Off") {
|
||||
return <TextCell value={cellProps.cell.value} />;
|
||||
}
|
||||
return (
|
||||
<span className="name-container">
|
||||
<TooltipWrapper tipContent={tooltipText(cellProps.cell.value)}>
|
||||
{cellProps.cell.value}
|
||||
</TooltipWrapper>
|
||||
</span>
|
||||
);
|
||||
},
|
||||
sortType: "caseInsensitive",
|
||||
},
|
||||
{
|
||||
title: "Hosts",
|
||||
Header: "Hosts",
|
||||
disableSortBy: true,
|
||||
accessor: "hosts",
|
||||
Cell: (cellProps: ICellProps) => <TextCell value={cellProps.cell.value} />,
|
||||
},
|
||||
{
|
||||
title: "",
|
||||
Header: "",
|
||||
disableSortBy: true,
|
||||
disableGlobalFilter: true,
|
||||
accessor: "linkToFilteredHosts",
|
||||
Cell: (cellProps: IStringCellProps) => {
|
||||
const statusParam = () => {
|
||||
switch (cellProps.row.original.status) {
|
||||
case "On (automatic)":
|
||||
return "automatic";
|
||||
case "On (manual)":
|
||||
return "manual";
|
||||
default:
|
||||
return "unenrolled";
|
||||
}
|
||||
};
|
||||
return (
|
||||
<ViewAllHostsLink
|
||||
queryParams={{ mdm_enrollment_status: statusParam() }}
|
||||
className="mdm-solution-link"
|
||||
platformLabelId={cellProps.row.original.selectedPlatformLabelId}
|
||||
/>
|
||||
);
|
||||
},
|
||||
disableHidden: true,
|
||||
},
|
||||
];
|
||||
|
||||
export const generateEnrollmentTableHeaders = (): IDataColumn[] => {
|
||||
return enrollmentTableHeaders;
|
||||
};
|
||||
|
||||
const enhanceEnrollmentData = (
|
||||
enrollmentData: IMdmEnrollmentCardData[],
|
||||
selectedPlatformLabelId?: number
|
||||
): IMdmEnrollmentData[] => {
|
||||
return Object.values(enrollmentData).map((data) => {
|
||||
return {
|
||||
...data,
|
||||
selectedPlatformLabelId,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
export const generateEnrollmentDataSet = (
|
||||
enrollmentData: IMdmEnrollmentCardData[] | null,
|
||||
selectedPlatformLabelId?: number
|
||||
): IMdmEnrollmentData[] => {
|
||||
if (!enrollmentData) {
|
||||
return [];
|
||||
}
|
||||
return [...enhanceEnrollmentData(enrollmentData, selectedPlatformLabelId)];
|
||||
};
|
115
frontend/pages/DashboardPage/cards/MDM/MDMStatusTableConfig.tsx
Normal file
115
frontend/pages/DashboardPage/cards/MDM/MDMStatusTableConfig.tsx
Normal file
@ -0,0 +1,115 @@
|
||||
import React from "react";
|
||||
|
||||
import { IMdmStatusCardData, MDM_STATUS } from "interfaces/mdm";
|
||||
|
||||
import TextCell from "components/TableContainer/DataTable/TextCell";
|
||||
import TooltipWrapper from "components/TooltipWrapper";
|
||||
import ViewAllHostsLink from "components/ViewAllHostsLink";
|
||||
import { MDM_STATUS_TOOLTIP } from "utilities/constants";
|
||||
|
||||
interface IMdmStatusData extends IMdmStatusCardData {
|
||||
selectedPlatformLabelId?: number;
|
||||
}
|
||||
|
||||
// NOTE: cellProps come from react-table
|
||||
// more info here https://react-table.tanstack.com/docs/api/useTable#cell-properties
|
||||
interface ICellProps {
|
||||
cell: {
|
||||
value: string;
|
||||
};
|
||||
row: {
|
||||
original: IMdmStatusData;
|
||||
};
|
||||
}
|
||||
|
||||
interface IHeaderProps {
|
||||
column: {
|
||||
title: string;
|
||||
isSortedDesc: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
interface IStringCellProps extends ICellProps {
|
||||
cell: {
|
||||
value: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface IDataColumn {
|
||||
title: string;
|
||||
Header: ((props: IHeaderProps) => JSX.Element) | string;
|
||||
accessor: string;
|
||||
Cell: (props: ICellProps) => JSX.Element;
|
||||
disableHidden?: boolean;
|
||||
disableSortBy?: boolean;
|
||||
}
|
||||
|
||||
const statusTableHeaders = [
|
||||
{
|
||||
title: "Status",
|
||||
Header: "Status",
|
||||
disableSortBy: true,
|
||||
accessor: "status",
|
||||
Cell: (cellProps: IStringCellProps) => (
|
||||
<TooltipWrapper
|
||||
position="top"
|
||||
tipContent={MDM_STATUS_TOOLTIP[cellProps.cell.value]}
|
||||
>
|
||||
{cellProps.cell.value}
|
||||
</TooltipWrapper>
|
||||
),
|
||||
sortType: "hasLength",
|
||||
},
|
||||
{
|
||||
title: "Hosts",
|
||||
Header: "Hosts",
|
||||
disableSortBy: true,
|
||||
accessor: "hosts",
|
||||
Cell: (cellProps: ICellProps) => <TextCell value={cellProps.cell.value} />,
|
||||
},
|
||||
{
|
||||
title: "",
|
||||
Header: "",
|
||||
disableSortBy: true,
|
||||
disableGlobalFilter: true,
|
||||
accessor: "linkToFilteredHosts",
|
||||
Cell: (cellProps: IStringCellProps) => {
|
||||
return (
|
||||
<ViewAllHostsLink
|
||||
queryParams={{
|
||||
mdm_enrollment_status: MDM_STATUS[cellProps.row.original.status],
|
||||
}}
|
||||
className="mdm-solution-link"
|
||||
platformLabelId={cellProps.row.original.selectedPlatformLabelId}
|
||||
/>
|
||||
);
|
||||
},
|
||||
disableHidden: true,
|
||||
},
|
||||
];
|
||||
|
||||
export const generateStatusTableHeaders = (): IDataColumn[] => {
|
||||
return statusTableHeaders;
|
||||
};
|
||||
|
||||
const enhanceStatusData = (
|
||||
statusData: IMdmStatusCardData[],
|
||||
selectedPlatformLabelId?: number
|
||||
): IMdmStatusData[] => {
|
||||
return Object.values(statusData).map((data) => {
|
||||
return {
|
||||
...data,
|
||||
selectedPlatformLabelId,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
export const generateStatusDataSet = (
|
||||
statusData: IMdmStatusCardData[] | null,
|
||||
selectedPlatformLabelId?: number
|
||||
): IMdmStatusData[] => {
|
||||
if (!statusData) {
|
||||
return [];
|
||||
}
|
||||
return [...enhanceStatusData(statusData, selectedPlatformLabelId)];
|
||||
};
|
@ -5,23 +5,7 @@
|
||||
.component__tabs-wrapper .table-container__header {
|
||||
display: none;
|
||||
}
|
||||
&__empty-mdm {
|
||||
width: 364px;
|
||||
margin: $pad-large auto 0;
|
||||
|
||||
h1 {
|
||||
font-size: $small;
|
||||
font-weight: $bold;
|
||||
margin-bottom: $pad-medium;
|
||||
}
|
||||
|
||||
p {
|
||||
color: $core-fleet-black;
|
||||
font-weight: $regular;
|
||||
font-size: $x-small;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
.data-table-block {
|
||||
.data-table__table {
|
||||
table-layout: fixed;
|
||||
|
@ -10,6 +10,9 @@ import TabsWrapper from "components/TabsWrapper";
|
||||
import TableContainer from "components/TableContainer";
|
||||
import Spinner from "components/Spinner";
|
||||
import TableDataError from "components/DataError";
|
||||
import EmptyTable from "components/EmptyTable";
|
||||
import CustomLink from "components/CustomLink";
|
||||
|
||||
import munkiVersionsTableHeaders from "./MunkiVersionsTableConfig";
|
||||
import munkiIssuesTableHeaders from "./MunkiIssuesTableConfig";
|
||||
|
||||
@ -25,33 +28,6 @@ const DEFAULT_SORT_HEADER = "hosts_count";
|
||||
const PAGE_SIZE = 8;
|
||||
const baseClass = "home-munki";
|
||||
|
||||
const EmptyMunkiIssues = (): JSX.Element => (
|
||||
<div className={`${baseClass}__empty-munki`}>
|
||||
<h2>No Munki issues detected</h2>
|
||||
<p>
|
||||
This report is updated every hour to protect the performance of your
|
||||
devices.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
const EmptyMunkiVersions = (): JSX.Element => (
|
||||
<div className={`${baseClass}__empty-munki`}>
|
||||
<h2>Unable to detect Munki versions</h2>
|
||||
<p>
|
||||
To see Munki versions, deploy
|
||||
<a
|
||||
href="https://fleetdm.com/docs/using-fleet/adding-hosts#osquery-installer"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Fleet's osquery installer
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
const Munki = ({
|
||||
errorMacAdmins,
|
||||
isMacAdminsFetching,
|
||||
@ -93,7 +69,13 @@ const Munki = ({
|
||||
defaultSortDirection={DEFAULT_SORT_DIRECTION}
|
||||
hideActionButton
|
||||
resultsTitle={"Munki"}
|
||||
emptyComponent={EmptyMunkiIssues}
|
||||
emptyComponent={() => (
|
||||
<EmptyTable
|
||||
header="No Munki issues detected"
|
||||
info="This report is updated every hour to protect the performance of your
|
||||
devices."
|
||||
/>
|
||||
)}
|
||||
showMarkAllPages={false}
|
||||
isAllPagesSelected={false}
|
||||
isClientSidePagination
|
||||
@ -116,7 +98,22 @@ const Munki = ({
|
||||
defaultSortDirection={DEFAULT_SORT_DIRECTION}
|
||||
hideActionButton
|
||||
resultsTitle={"Munki"}
|
||||
emptyComponent={EmptyMunkiVersions}
|
||||
emptyComponent={() => (
|
||||
<EmptyTable
|
||||
header="Unable to detect Munki versions"
|
||||
info={
|
||||
<>
|
||||
To see Munki versions, deploy
|
||||
<CustomLink
|
||||
url="https://fleetdm.com/docs/using-fleet/adding-hosts#osquery-installer"
|
||||
text="Fleet's osquery installer"
|
||||
newTab
|
||||
/>
|
||||
.
|
||||
</>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
showMarkAllPages={false}
|
||||
isAllPagesSelected={false}
|
||||
isClientSidePagination
|
||||
|
@ -8,22 +8,6 @@
|
||||
.component__tabs-wrapper .table-container__header {
|
||||
display: none;
|
||||
}
|
||||
&__empty-munki {
|
||||
margin: $pad-medium auto 0;
|
||||
|
||||
h2 {
|
||||
font-size: $small;
|
||||
font-weight: $bold;
|
||||
margin-bottom: $pad-medium;
|
||||
}
|
||||
|
||||
p {
|
||||
color: $core-fleet-black;
|
||||
font-weight: $regular;
|
||||
font-size: $x-small;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
.data-table-block {
|
||||
.data-table__table {
|
||||
table-layout: fixed;
|
||||
|
@ -19,6 +19,7 @@ import Spinner from "components/Spinner";
|
||||
import TableDataError from "components/DataError";
|
||||
import LastUpdatedText from "components/LastUpdatedText";
|
||||
import CustomLink from "components/CustomLink";
|
||||
import EmptyTable from "components/EmptyTable";
|
||||
|
||||
import generateTableHeaders from "./OperatingSystemsTableConfig";
|
||||
|
||||
@ -37,15 +38,13 @@ const PAGE_SIZE = 8;
|
||||
const baseClass = "operating-systems";
|
||||
|
||||
const EmptyOperatingSystems = (platform: ISelectedPlatform): JSX.Element => (
|
||||
<div className={`${baseClass}__empty-os`}>
|
||||
<h1>{`No${
|
||||
<EmptyTable
|
||||
header={`No${
|
||||
` ${PLATFORM_DISPLAY_NAMES[platform]}` || ""
|
||||
} operating systems detected.`}</h1>
|
||||
<p>
|
||||
{`Did you add ${`${PLATFORM_DISPLAY_NAMES[platform]} ` || ""}hosts to
|
||||
} operating systems detected.`}
|
||||
info={`Did you add ${`${PLATFORM_DISPLAY_NAMES[platform]} ` || ""}hosts to
|
||||
Fleet? Try again in about an hour as the system catches up.`}
|
||||
</p>
|
||||
</div>
|
||||
/>
|
||||
);
|
||||
|
||||
const OperatingSystems = ({
|
||||
|
@ -2,23 +2,6 @@
|
||||
margin-top: $pad-large;
|
||||
position: relative;
|
||||
|
||||
&__empty-os {
|
||||
margin: 0 auto;
|
||||
|
||||
h1 {
|
||||
font-size: $small;
|
||||
font-weight: $bold;
|
||||
margin-bottom: $pad-medium;
|
||||
}
|
||||
|
||||
p {
|
||||
color: $core-fleet-black;
|
||||
font-weight: $regular;
|
||||
font-size: $x-small;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.data-table__wrapper {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
@ -188,7 +188,7 @@ const Mdm = (): JSX.Element => {
|
||||
<>
|
||||
<div className={`${baseClass}__section-description`}>
|
||||
Connect Fleet to your Apple Business Manager account to
|
||||
automatically enroll macOS hosts to Fleet when they’re first
|
||||
automatically enroll macOS hosts to Fleet when they're first
|
||||
unboxed.
|
||||
</div>
|
||||
<div className={`${baseClass}__section-instructions`}>
|
||||
@ -204,7 +204,7 @@ const Mdm = (): JSX.Element => {
|
||||
newTab
|
||||
/>
|
||||
<br />
|
||||
If your organization doesn’t have an account, select{" "}
|
||||
If your organization doesn't have an account, select{" "}
|
||||
<b>Enroll now</b>.
|
||||
</p>
|
||||
<p>
|
||||
|
@ -151,16 +151,45 @@ const allHostTableHeaders: IDataColumn[] = [
|
||||
/>
|
||||
),
|
||||
accessor: "display_name",
|
||||
Cell: (cellProps: ICellProps) => (
|
||||
<LinkCell
|
||||
value={cellProps.cell.value}
|
||||
path={PATHS.HOST_DETAILS(cellProps.row.original.id)}
|
||||
title={lastSeenTime(
|
||||
cellProps.row.original.status,
|
||||
cellProps.row.original.seen_time
|
||||
)}
|
||||
/>
|
||||
),
|
||||
Cell: (cellProps: ICellProps) => {
|
||||
if (cellProps.row.original.mdm_enrollment_status === "Pending") {
|
||||
return (
|
||||
<>
|
||||
<span
|
||||
className="text-cell"
|
||||
data-tip
|
||||
data-for={`host__${cellProps.row.original.id}`}
|
||||
>
|
||||
{cellProps.cell.value}
|
||||
</span>
|
||||
<ReactTooltip
|
||||
effect="solid"
|
||||
backgroundColor="#3e4771"
|
||||
id={`host__${cellProps.row.original.id}`}
|
||||
data-html
|
||||
>
|
||||
<span className={`tooltip__tooltip-text`}>
|
||||
This host was ordered using <br />
|
||||
Apple Business Manager <br />
|
||||
(ABM). You can't see host <br />
|
||||
vitals until it's unboxed and <br />
|
||||
automatically enrolls to Fleet.
|
||||
</span>
|
||||
</ReactTooltip>
|
||||
</>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<LinkCell
|
||||
value={cellProps.cell.value}
|
||||
path={PATHS.HOST_DETAILS(cellProps.row.original.id)}
|
||||
title={lastSeenTime(
|
||||
cellProps.row.original.status,
|
||||
cellProps.row.original.seen_time
|
||||
)}
|
||||
/>
|
||||
);
|
||||
},
|
||||
disableHidden: true,
|
||||
},
|
||||
{
|
||||
@ -337,6 +366,53 @@ const allHostTableHeaders: IDataColumn[] = [
|
||||
accessor: "primary_ip",
|
||||
Cell: (cellProps: ICellProps) => <TextCell value={cellProps.cell.value} />,
|
||||
},
|
||||
{
|
||||
title: "MDM status",
|
||||
Header: (): JSX.Element => {
|
||||
const titleWithToolTip = (
|
||||
<TooltipWrapper
|
||||
tipContent={`
|
||||
The MDM server that updates settings on the host.<br/>
|
||||
To filter by MDM server URL, head to the Dashboard page.
|
||||
`}
|
||||
>
|
||||
MDM Status
|
||||
</TooltipWrapper>
|
||||
);
|
||||
return <HeaderCell value={titleWithToolTip} disableSortBy />;
|
||||
},
|
||||
disableSortBy: true,
|
||||
accessor: "mdm_enrollment_status",
|
||||
Cell: (cellProps: ICellProps) => {
|
||||
if (cellProps.cell.value)
|
||||
return <TextCell value={cellProps.cell.value} />;
|
||||
return <span className="text-muted">---</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "MDM server URL",
|
||||
Header: (): JSX.Element => {
|
||||
const titleWithToolTip = (
|
||||
<TooltipWrapper
|
||||
tipContent={`
|
||||
Settings can be updated remotely on hosts with MDM turned on.<br/>
|
||||
To filter by MDM status, head to the Dashboard page.
|
||||
`}
|
||||
>
|
||||
MDM server URL
|
||||
</TooltipWrapper>
|
||||
);
|
||||
return <HeaderCell value={titleWithToolTip} disableSortBy />;
|
||||
},
|
||||
disableSortBy: true,
|
||||
accessor: "mdm_server_url",
|
||||
Cell: (cellProps: ICellProps) => {
|
||||
if (cellProps.cell.value) {
|
||||
return <TextCell value={cellProps.cell.value} />;
|
||||
}
|
||||
return <span className="text-muted">---</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "Public IP address",
|
||||
Header: (cellProps: IHeaderProps) => (
|
||||
@ -499,6 +575,8 @@ const defaultHiddenColumns = [
|
||||
"primary_mac",
|
||||
"public_ip",
|
||||
"cpu_type",
|
||||
"mdm_server_url",
|
||||
"mdm_enrollment_status",
|
||||
"memory",
|
||||
"uptime",
|
||||
"uuid",
|
||||
@ -531,7 +609,11 @@ const generateAvailableTableHeaders = (
|
||||
}
|
||||
// skip over column headers that are not shown in free admin/maintainer
|
||||
} else if (permissionUtils.isFreeTier(config)) {
|
||||
if (currentColumn.accessor === "team_name") {
|
||||
if (
|
||||
currentColumn.accessor === "team_name" ||
|
||||
currentColumn.accessor === "mdm_server_url" ||
|
||||
currentColumn.accessor === "mdm_enrollment_status"
|
||||
) {
|
||||
return columns;
|
||||
}
|
||||
} else if (
|
||||
|
@ -1,9 +1,8 @@
|
||||
import React, { useState, useContext, useEffect, useCallback } from "react";
|
||||
import { IconNames } from "components/icons";
|
||||
import { useQuery } from "react-query";
|
||||
import { InjectedRouter, Params } from "react-router/lib/Router";
|
||||
import { RouteProps } from "react-router/lib/Route";
|
||||
import { find, isEmpty, isEqual, omit } from "lodash";
|
||||
import { find, isEmpty, isEqual, omit, invert } from "lodash";
|
||||
import { format } from "date-fns";
|
||||
import FileSaver from "file-saver";
|
||||
|
||||
@ -35,7 +34,7 @@ import {
|
||||
import { IHost } from "interfaces/host";
|
||||
import { ILabel } from "interfaces/label";
|
||||
import { IMunkiIssuesAggregate } from "interfaces/macadmins";
|
||||
import { IMdmSolution } from "interfaces/mdm";
|
||||
import { IMdmSolution, MDM_STATUS } from "interfaces/mdm";
|
||||
import {
|
||||
formatOperatingSystemDisplayName,
|
||||
IOperatingSystemVersion,
|
||||
@ -1157,8 +1156,8 @@ const ManageHostsPage = ({
|
||||
: `${name || ""}`
|
||||
);
|
||||
const TooltipDescription = (
|
||||
<span className={`tooltip__tooltip-text`}>
|
||||
{`Hosts with ${formatOperatingSystemDisplayName(name_only || name)}`},
|
||||
<span className="tooltip__tooltip-text">
|
||||
Hosts with {formatOperatingSystemDisplayName(name_only || name)},
|
||||
<br />
|
||||
{version && `${version} installed`}
|
||||
</span>
|
||||
@ -1218,7 +1217,7 @@ const ManageHostsPage = ({
|
||||
const label = name ? `${name} ${server_url}` : `${server_url}`;
|
||||
|
||||
const TooltipDescription = (
|
||||
<span className={`tooltip__tooltip-text`}>
|
||||
<span className="tooltip__tooltip-text">
|
||||
Host enrolled
|
||||
{name !== "Unknown" && ` to ${name}`}
|
||||
<br /> at {server_url}
|
||||
@ -1237,54 +1236,52 @@ const ManageHostsPage = ({
|
||||
const renderMDMEnrollmentFilterBlock = () => {
|
||||
if (!mdmEnrollmentStatus) return null;
|
||||
|
||||
let label: string;
|
||||
switch (mdmEnrollmentStatus) {
|
||||
case "automatic":
|
||||
label = "MDM status: On (automatic)";
|
||||
break;
|
||||
case "manual":
|
||||
label = "MDM status: On (manual)";
|
||||
break;
|
||||
default:
|
||||
label = "MDM status: Off";
|
||||
}
|
||||
const label = `MDM status: ${invert(MDM_STATUS)[mdmEnrollmentStatus]}`;
|
||||
|
||||
let TooltipDescription: JSX.Element;
|
||||
switch (mdmEnrollmentStatus) {
|
||||
case "automatic":
|
||||
TooltipDescription = (
|
||||
<span className={`tooltip__tooltip-text`}>
|
||||
Hosts automatically enrolled in <br />
|
||||
an MDM solution using Apple <br />
|
||||
Automated Device Enrollment <br />
|
||||
(DEP) or Windows Autopilot. <br />
|
||||
Administrators can block users <br />
|
||||
from unenrolling these hosts <br />
|
||||
from MDM.
|
||||
</span>
|
||||
);
|
||||
break;
|
||||
case "manual":
|
||||
TooltipDescription = (
|
||||
<span className={`tooltip__tooltip-text`}>
|
||||
Hosts manually enrolled to an <br />
|
||||
MDM solution. Users can unenroll <br />
|
||||
these hosts from MDM.
|
||||
</span>
|
||||
);
|
||||
break;
|
||||
default:
|
||||
TooltipDescription = (
|
||||
<span className={`tooltip__tooltip-text`}>
|
||||
Hosts not enrolled to <br /> an MDM solution.
|
||||
</span>
|
||||
);
|
||||
}
|
||||
// More narrow tooltip than other MDM tooltip
|
||||
const MDM_STATUS_PILL_TOOLTIP: Record<string, JSX.Element> = {
|
||||
automatic: (
|
||||
<span className="tooltip__tooltip-text">
|
||||
MDM was turned on <br />
|
||||
automatically using Apple <br />
|
||||
Automated Device <br />
|
||||
Enrollment (DEP) or <br />
|
||||
Windows Autopilot. <br />
|
||||
Administrators can block <br />
|
||||
device users from turning
|
||||
<br /> MDM off.
|
||||
</span>
|
||||
),
|
||||
manual: (
|
||||
<span className="tooltip__tooltip-text">
|
||||
MDM was turned on <br />
|
||||
manually. Device users <br />
|
||||
can turn MDM off.
|
||||
</span>
|
||||
),
|
||||
unenrolled: (
|
||||
<span className="tooltip__tooltip-text">
|
||||
Hosts with MDM off <br />
|
||||
don't receive macOS <br />
|
||||
settings and macOS <br />
|
||||
update encouragement.
|
||||
</span>
|
||||
),
|
||||
pending: (
|
||||
<span className="tooltip__tooltip-text">
|
||||
Hosts ordered using Apple <br />
|
||||
Business Manager (ABM). <br />
|
||||
They will automatically enroll <br />
|
||||
to Fleet and turn on MDM <br />
|
||||
when they're unboxed.
|
||||
</span>
|
||||
),
|
||||
};
|
||||
|
||||
return (
|
||||
<FilterPill
|
||||
label={label}
|
||||
tooltipDescription={TooltipDescription}
|
||||
tooltipDescription={MDM_STATUS_PILL_TOOLTIP[mdmEnrollmentStatus]}
|
||||
onClear={handleClearMDMEnrollmentFilter}
|
||||
/>
|
||||
);
|
||||
@ -1296,7 +1293,7 @@ const ManageHostsPage = ({
|
||||
<FilterPill
|
||||
label={munkiIssueDetails.name}
|
||||
tooltipDescription={
|
||||
<span className={`tooltip__tooltip-text`}>
|
||||
<span className="tooltip__tooltip-text">
|
||||
Hosts that reported this Munki issue <br />
|
||||
the last time Munki ran on each host.
|
||||
</span>
|
||||
@ -1310,7 +1307,7 @@ const ManageHostsPage = ({
|
||||
|
||||
const renderLowDiskSpaceFilterBlock = () => {
|
||||
const TooltipDescription = (
|
||||
<span className={`tooltip__tooltip-text`}>
|
||||
<span className="tooltip__tooltip-text">
|
||||
Hosts that have {lowDiskSpaceHosts} GB or less <br />
|
||||
disk space available.
|
||||
</span>
|
||||
|
@ -191,7 +191,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
.device_mapping__cell {
|
||||
.device_mapping__cell,
|
||||
.mdm_enrollment_status__cell,
|
||||
.mdm_server_url__cell {
|
||||
.text-cell {
|
||||
display: inline;
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import CloseIcon from "../../../../../../assets/images/icon-close-vibrant-blue-1
|
||||
|
||||
interface IFilterPillProps {
|
||||
label: string;
|
||||
icon?: any; // TODO: figure out png image types
|
||||
icon?: string;
|
||||
tooltipDescription?: string | ReactNode;
|
||||
className?: string;
|
||||
onClear: () => void;
|
||||
|
@ -277,7 +277,7 @@ const DeviceUserPage = ({
|
||||
) : (
|
||||
<div className={`${baseClass} body-wrap`}>
|
||||
{host?.platform === "darwin" &&
|
||||
host?.mdm?.enrollment_status === "Unenrolled" && (
|
||||
host?.mdm_enrollment_status === "Off" && (
|
||||
<InfoBanner color="yellow" cta={turnOnMdmButton} pageLevel>
|
||||
Mobile device management (MDM) is off. MDM allows your
|
||||
organization to change settings and install software. This
|
||||
|
@ -630,7 +630,7 @@ const HostDetailsPage = ({
|
||||
<div className={`${baseClass}__wrapper`}>
|
||||
<div className={`${baseClass}__header-links`}>
|
||||
{host?.platform === "darwin" &&
|
||||
host?.mdm?.enrollment_status === "Unenrolled" && (
|
||||
host?.mdm_enrollment_status === "Off" && (
|
||||
<InfoBanner color="yellow" pageLevel>
|
||||
To change settings and install software, ask the end user to
|
||||
follow the <strong>Turn on MDM</strong> instructions on their{" "}
|
||||
|
@ -2,9 +2,10 @@ import React from "react";
|
||||
|
||||
import ReactTooltip from "react-tooltip";
|
||||
import HumanTimeDiffWithDateTip from "components/HumanTimeDiffWithDateTip";
|
||||
|
||||
import TooltipWrapper from "components/TooltipWrapper";
|
||||
import { IHostMdmData, IMunkiData, IDeviceUser } from "interfaces/host";
|
||||
import { humanHostLastRestart } from "utilities/helpers";
|
||||
import { MDM_STATUS_TOOLTIP } from "utilities/constants";
|
||||
|
||||
interface IAboutProps {
|
||||
aboutData: { [key: string]: any };
|
||||
@ -51,15 +52,20 @@ const About = ({
|
||||
};
|
||||
|
||||
const renderMdmData = () => {
|
||||
if (!mdm || mdm.enrollment_status === "Off") {
|
||||
if (!mdm) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<div className="info-grid__block">
|
||||
<span className="info-grid__header">MDM enrollment</span>
|
||||
<span className="info-grid__header">MDM status</span>
|
||||
<span className="info-grid__data">
|
||||
{mdm.enrollment_status || "---"}
|
||||
<TooltipWrapper
|
||||
position="bottom"
|
||||
tipContent={MDM_STATUS_TOOLTIP[mdm.enrollment_status]}
|
||||
>
|
||||
{mdm.enrollment_status}
|
||||
</TooltipWrapper>
|
||||
</span>
|
||||
</div>
|
||||
<div className="info-grid__block">
|
||||
|
@ -5,6 +5,7 @@ import { GITHUB_NEW_ISSUE_LINK } from "utilities/constants";
|
||||
|
||||
import TableContainer from "components/TableContainer";
|
||||
import CustomLink from "components/CustomLink";
|
||||
import EmptyTable from "components/EmptyTable";
|
||||
|
||||
import generateVulnTableHeaders from "./VulnTableConfig";
|
||||
|
||||
@ -18,19 +19,19 @@ interface IVulnerabilitiesProps {
|
||||
|
||||
const NoVulnsDetected = (): JSX.Element => {
|
||||
return (
|
||||
<div className={`${baseClass}__empty-vulnerabilities`}>
|
||||
<div className="empty-vulnerabilities__inner">
|
||||
<h1>No vulnerabilities detected for this software item.</h1>
|
||||
<p>
|
||||
<EmptyTable
|
||||
header="No vulnerabilities detected for this software item."
|
||||
info={
|
||||
<>
|
||||
Expecting to see vulnerabilities?{" "}
|
||||
<CustomLink
|
||||
url={GITHUB_NEW_ISSUE_LINK}
|
||||
text="File an issue on GitHub"
|
||||
newTab
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -57,24 +57,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.vulnerabilities__empty-vulnerabilities {
|
||||
.empty-vulnerabilities__inner {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
h1 {
|
||||
font-size: $small;
|
||||
font-weight: $bold;
|
||||
margin-bottom: $pad-medium;
|
||||
}
|
||||
|
||||
p {
|
||||
color: $core-fleet-black;
|
||||
font-weight: $regular;
|
||||
font-size: $x-small;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -209,6 +209,14 @@ export const VULNERABLE_DROPDOWN_OPTIONS = [
|
||||
},
|
||||
];
|
||||
|
||||
// Keys from API
|
||||
export const MDM_STATUS_TOOLTIP: Record<string, string> = {
|
||||
"On (automatic)": `<span>MDM was turned on automatically using Apple Automated Device Enrollment (DEP) or Windows Autopilot. Administrators can block end users from turning MDM off.</span>`,
|
||||
"On (manual)": `<span>MDM was turned on manually. End users can turn MDM off.</span>`,
|
||||
Off: `<span>Hosts with MDM off don't receive macOS <br /> settings and macOS update encouragement.</span>`,
|
||||
Pending: `<span>Hosts ordered via Apple Business Manager <br /> (ABM). These will automatically enroll to Fleet <br /> and turn on MDM when they're unboxed.</span>`,
|
||||
};
|
||||
|
||||
export const DEFAULT_CREATE_USER_ERRORS = {
|
||||
email: "",
|
||||
name: "",
|
||||
|
Loading…
Reference in New Issue
Block a user