mirror of
https://github.com/fleetdm/fleet
synced 2026-05-24 01:18:42 +00:00
Fleet UI: Munki title on homepage, hide entire card when no munki_versions installed on team/global (#7646)
This commit is contained in:
parent
7c0b47e568
commit
78ca68d13d
15 changed files with 170 additions and 167 deletions
|
|
@ -100,7 +100,6 @@ describe(
|
|||
cy.findByText(/fleet test/i).should("exist");
|
||||
cy.getAttached(".hosts-summary").should("exist");
|
||||
cy.getAttached(".hosts-status").should("exist");
|
||||
cy.getAttached(".home-munki").should("exist");
|
||||
cy.getAttached(".home-mdm").should("exist");
|
||||
// "get" because we expect it not to exist
|
||||
cy.get(".home-software").should("not.exist");
|
||||
|
|
|
|||
|
|
@ -92,7 +92,6 @@ describe(
|
|||
cy.findByText(/fleet test/i).should("exist");
|
||||
cy.getAttached(".hosts-summary").should("exist");
|
||||
cy.getAttached(".hosts-status").should("exist");
|
||||
cy.getAttached(".home-munki").should("exist");
|
||||
cy.getAttached(".home-mdm").should("exist");
|
||||
// "get" because we expect it not to exist
|
||||
cy.get(".home-software").should("not.exist");
|
||||
|
|
|
|||
|
|
@ -87,7 +87,6 @@ describe("Free tier - Observer user", () => {
|
|||
cy.findByText(/fleet test/i).should("exist");
|
||||
cy.getAttached(".hosts-summary").should("exist");
|
||||
cy.getAttached(".hosts-status").should("exist");
|
||||
cy.getAttached(".home-munki").should("exist");
|
||||
cy.getAttached(".home-mdm").should("exist");
|
||||
// "get" because we expect it not to exist
|
||||
cy.get(".home-software").should("not.exist");
|
||||
|
|
|
|||
|
|
@ -84,7 +84,6 @@ describe("Premium tier - Maintainer user", () => {
|
|||
cy.findByText(/all teams/i).should("exist");
|
||||
cy.getAttached(".hosts-summary").should("exist");
|
||||
cy.getAttached(".hosts-status").should("exist");
|
||||
cy.getAttached(".home-munki").should("exist");
|
||||
cy.getAttached(".home-mdm").should("exist");
|
||||
// "get" because we expect it not to exist
|
||||
cy.get(".home-software").should("not.exist");
|
||||
|
|
|
|||
|
|
@ -85,7 +85,6 @@ describe("Premium tier - Observer user", () => {
|
|||
cy.findByText(/all teams/i).should("exist");
|
||||
cy.getAttached(".hosts-summary").should("exist");
|
||||
cy.getAttached(".hosts-status").should("exist");
|
||||
cy.getAttached(".home-munki").should("exist");
|
||||
cy.getAttached(".home-mdm").should("exist");
|
||||
// "get" because we expect it not to exist
|
||||
cy.get(".home-software").should("not.exist");
|
||||
|
|
|
|||
|
|
@ -90,7 +90,6 @@ describe("Premium tier - Team Admin user", () => {
|
|||
cy.findByText(/apples/i).should("exist");
|
||||
cy.getAttached(".hosts-summary").should("exist");
|
||||
cy.getAttached(".hosts-status").should("exist");
|
||||
cy.getAttached(".home-munki").should("exist");
|
||||
cy.getAttached(".home-mdm").should("exist");
|
||||
// "get" because we expect it not to exist
|
||||
cy.get(".home-software").should("not.exist");
|
||||
|
|
|
|||
|
|
@ -85,7 +85,6 @@ describe("Premium tier - Team observer/maintainer user", () => {
|
|||
cy.findByText(/apples/i).should("exist");
|
||||
cy.getAttached(".hosts-summary").should("exist");
|
||||
cy.getAttached(".hosts-status").should("exist");
|
||||
cy.getAttached(".home-munki").should("exist");
|
||||
cy.getAttached(".home-mdm").should("exist");
|
||||
// "get" because we expect it not to exist
|
||||
cy.get(".home-software").should("not.exist");
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export interface IDataTableMDMFormat {
|
||||
export interface IDataTableMdmFormat {
|
||||
status: string;
|
||||
hosts: number;
|
||||
}
|
||||
|
|
@ -14,13 +14,13 @@ export interface IMunkiIssuesAggregate {
|
|||
type: "error" | "warning";
|
||||
hosts_count: number;
|
||||
}
|
||||
export interface IMDMAggregateStatus {
|
||||
export interface IMdmAggregateStatus {
|
||||
enrolled_manual_hosts_count: number;
|
||||
enrolled_automated_hosts_count: number;
|
||||
unenrolled_hosts_count: number;
|
||||
}
|
||||
|
||||
export interface IMDMSolution {
|
||||
export interface IMdmSolution {
|
||||
id: number;
|
||||
name: string | null;
|
||||
server_url: string;
|
||||
|
|
@ -32,7 +32,7 @@ export interface IMacadminAggregate {
|
|||
counts_updated_at: string;
|
||||
munki_versions: IMunkiVersionsAggregate[];
|
||||
munki_issues: IMunkiIssuesAggregate[];
|
||||
mobile_device_management_enrollment_status: IMDMAggregateStatus;
|
||||
mobile_device_management_solution: IMDMSolution[] | null;
|
||||
mobile_device_management_enrollment_status: IMdmAggregateStatus;
|
||||
mobile_device_management_solution: IMdmSolution[] | null;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,10 +9,18 @@ import {
|
|||
} from "interfaces/enroll_secret";
|
||||
import { IHostSummary, IHostSummaryPlatforms } from "interfaces/host_summary";
|
||||
import { ILabelSummary } from "interfaces/label";
|
||||
import {
|
||||
IDataTableMdmFormat,
|
||||
IMdmSolution,
|
||||
IMacadminAggregate,
|
||||
IMunkiIssuesAggregate,
|
||||
IMunkiVersionsAggregate,
|
||||
} from "interfaces/macadmins";
|
||||
import { IOsqueryPlatform } from "interfaces/platform";
|
||||
import { ITeam } from "interfaces/team";
|
||||
import enrollSecretsAPI from "services/entities/enroll_secret";
|
||||
import hostSummaryAPI from "services/entities/host_summary";
|
||||
import macadminsAPI from "services/entities/macadmins";
|
||||
import teamsAPI, { ILoadTeamsResponse } from "services/entities/teams";
|
||||
import sortUtils from "utilities/sort";
|
||||
import { PLATFORM_DROPDOWN_OPTIONS } from "utilities/constants";
|
||||
|
|
@ -22,6 +30,7 @@ import Spinner from "components/Spinner";
|
|||
// @ts-ignore
|
||||
import Dropdown from "components/forms/fields/Dropdown";
|
||||
import MainContent from "components/MainContent";
|
||||
import LastUpdatedText from "components/LastUpdatedText";
|
||||
import useInfoCard from "./components/InfoCard";
|
||||
import HostsStatus from "./cards/HostsStatus";
|
||||
import HostsSummary from "./cards/HostsSummary";
|
||||
|
|
@ -29,7 +38,7 @@ import ActivityFeed from "./cards/ActivityFeed";
|
|||
import Software from "./cards/Software";
|
||||
import LearnFleet from "./cards/LearnFleet";
|
||||
import WelcomeHost from "./cards/WelcomeHost";
|
||||
import MDM from "./cards/MDM";
|
||||
import Mdm from "./cards/MDM";
|
||||
import Munki from "./cards/Munki";
|
||||
import OperatingSystems from "./cards/OperatingSystems";
|
||||
import AddHostsModal from "../../components/AddHostsModal";
|
||||
|
|
@ -62,10 +71,28 @@ const Homepage = (): JSX.Element => {
|
|||
const [showActivityFeedTitle, setShowActivityFeedTitle] = useState(false);
|
||||
const [showSoftwareUI, setShowSoftwareUI] = useState(false);
|
||||
const [showMunkiUI, setShowMunkiUI] = useState(false);
|
||||
const [showMunkiCard, setShowMunkiCard] = useState(true);
|
||||
const [showMDMUI, setShowMDMUI] = useState(false);
|
||||
const [showAddHostsModal, setShowAddHostsModal] = useState(false);
|
||||
const [showOperatingSystemsUI, setShowOperatingSystemsUI] = useState(false);
|
||||
const [showHostsUI, setShowHostsUI] = useState(false); // Hides UI on first load only
|
||||
const [formattedMdmData, setFormattedMdmData] = useState<
|
||||
IDataTableMdmFormat[]
|
||||
>([]);
|
||||
const [mdmSolutions, setMdmSolutions] = useState<IMdmSolution[] | null>([]);
|
||||
|
||||
const [munkiIssuesData, setMunkiIssuesData] = useState<
|
||||
IMunkiIssuesAggregate[]
|
||||
>([]);
|
||||
const [munkiVersionsData, setMunkiVersionsData] = useState<
|
||||
IMunkiVersionsAggregate[]
|
||||
>([]);
|
||||
const [mdmTitleDetail, setMdmTitleDetail] = useState<
|
||||
JSX.Element | string | null
|
||||
>();
|
||||
const [munkiTitleDetail, setMunkiTitleDetail] = useState<
|
||||
JSX.Element | string | null
|
||||
>();
|
||||
|
||||
const canEnrollHosts =
|
||||
isGlobalAdmin || isGlobalMaintainer || isTeamAdmin || isTeamMaintainer;
|
||||
|
|
@ -147,6 +174,68 @@ const Homepage = (): JSX.Element => {
|
|||
}
|
||||
);
|
||||
|
||||
const { isFetching: isMacAdminsFetching, error: errorMacAdmins } = useQuery<
|
||||
IMacadminAggregate,
|
||||
Error
|
||||
>(
|
||||
["macAdmins", currentTeam?.id],
|
||||
() => macadminsAPI.loadAll(currentTeam?.id),
|
||||
{
|
||||
keepPreviousData: true,
|
||||
enabled: selectedPlatform === "darwin",
|
||||
onSuccess: (data) => {
|
||||
const {
|
||||
counts_updated_at: macadmins_counts_updated_at,
|
||||
mobile_device_management_enrollment_status,
|
||||
mobile_device_management_solution,
|
||||
} = data.macadmins;
|
||||
const {
|
||||
enrolled_manual_hosts_count,
|
||||
enrolled_automated_hosts_count,
|
||||
unenrolled_hosts_count,
|
||||
} = mobile_device_management_enrollment_status;
|
||||
|
||||
const {
|
||||
counts_updated_at: munki_counts_updated_at,
|
||||
munki_versions,
|
||||
munki_issues,
|
||||
} = data.macadmins;
|
||||
|
||||
setMdmTitleDetail(
|
||||
<LastUpdatedText
|
||||
lastUpdatedAt={macadmins_counts_updated_at}
|
||||
whatToRetrieve={"MDM enrollment"}
|
||||
/>
|
||||
);
|
||||
setFormattedMdmData([
|
||||
{
|
||||
status: "Enrolled (manual)",
|
||||
hosts: enrolled_manual_hosts_count,
|
||||
},
|
||||
{
|
||||
status: "Enrolled (automatic)",
|
||||
hosts: enrolled_automated_hosts_count,
|
||||
},
|
||||
{ status: "Unenrolled", hosts: unenrolled_hosts_count },
|
||||
]);
|
||||
setMdmSolutions(mobile_device_management_solution);
|
||||
setMunkiVersionsData(munki_versions);
|
||||
setMunkiIssuesData(munki_issues);
|
||||
setShowMunkiCard(!!munki_versions);
|
||||
setMunkiTitleDetail(
|
||||
<LastUpdatedText
|
||||
lastUpdatedAt={munki_counts_updated_at}
|
||||
whatToRetrieve={"Munki"}
|
||||
/>
|
||||
);
|
||||
},
|
||||
onError: () => {
|
||||
setShowMDMUI(true);
|
||||
setShowMunkiUI(true);
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const handleTeamSelect = (teamId: number) => {
|
||||
const selectedTeam = find(teams, ["id", teamId]);
|
||||
setCurrentTeam(selectedTeam);
|
||||
|
|
@ -242,8 +331,9 @@ const Homepage = (): JSX.Element => {
|
|||
});
|
||||
|
||||
const MunkiCard = useInfoCard({
|
||||
title: "Munki versions",
|
||||
showTitle: showMunkiUI,
|
||||
title: "Munki",
|
||||
titleDetail: munkiTitleDetail,
|
||||
showTitle: !isMacAdminsFetching,
|
||||
description: (
|
||||
<p>
|
||||
Munki is a tool for managing software on macOS devices.{" "}
|
||||
|
|
@ -259,16 +349,18 @@ const Homepage = (): JSX.Element => {
|
|||
),
|
||||
children: (
|
||||
<Munki
|
||||
setShowMunkiUI={setShowMunkiUI}
|
||||
showMunkiUI={showMunkiUI}
|
||||
currentTeamId={currentTeam?.id}
|
||||
errorMacAdmins={errorMacAdmins}
|
||||
isMacAdminsFetching={isMacAdminsFetching}
|
||||
munkiIssuesData={munkiIssuesData}
|
||||
munkiVersionsData={munkiVersionsData}
|
||||
/>
|
||||
),
|
||||
});
|
||||
|
||||
const MDMCard = useInfoCard({
|
||||
title: "Mobile device management (MDM)",
|
||||
showTitle: showMDMUI,
|
||||
titleDetail: mdmTitleDetail,
|
||||
showTitle: !isMacAdminsFetching,
|
||||
description: (
|
||||
<p>
|
||||
MDM is used to manage configuration on macOS devices.{" "}
|
||||
|
|
@ -283,10 +375,11 @@ const Homepage = (): JSX.Element => {
|
|||
</p>
|
||||
),
|
||||
children: (
|
||||
<MDM
|
||||
setShowMDMUI={setShowMDMUI}
|
||||
showMDMUI={showMDMUI}
|
||||
currentTeamId={currentTeam?.id}
|
||||
<Mdm
|
||||
isMacAdminsFetching={isMacAdminsFetching}
|
||||
errorMacAdmins={errorMacAdmins}
|
||||
formattedMdmData={formattedMdmData}
|
||||
mdmSolutions={mdmSolutions}
|
||||
/>
|
||||
),
|
||||
});
|
||||
|
|
@ -326,7 +419,9 @@ const Homepage = (): JSX.Element => {
|
|||
<>
|
||||
<div className={`${baseClass}__section`}>{OperatingSystemsCard}</div>
|
||||
<div className={`${baseClass}__section`}>{MDMCard}</div>
|
||||
<div className={`${baseClass}__section`}>{MunkiCard}</div>
|
||||
{showMunkiCard && (
|
||||
<div className={`${baseClass}__section`}>{MunkiCard}</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,30 +1,23 @@
|
|||
import React, { useState } from "react";
|
||||
import { useQuery } from "react-query";
|
||||
import { Tab, Tabs, TabList, TabPanel } from "react-tabs";
|
||||
|
||||
import macadminsAPI from "services/entities/macadmins";
|
||||
import {
|
||||
IMacadminAggregate,
|
||||
IDataTableMDMFormat,
|
||||
IMDMSolution,
|
||||
} from "interfaces/macadmins";
|
||||
import { IDataTableMdmFormat, IMdmSolution } from "interfaces/macadmins";
|
||||
|
||||
import TabsWrapper from "components/TabsWrapper";
|
||||
import TableContainer from "components/TableContainer";
|
||||
import Spinner from "components/Spinner";
|
||||
import TableDataError from "components/DataError";
|
||||
import LastUpdatedText from "components/LastUpdatedText";
|
||||
import {
|
||||
generateSolutionsTableHeaders,
|
||||
generateSolutionsDataSet,
|
||||
} from "./MDMSolutionsTableConfig";
|
||||
import generateEnrollmentTableHeaders from "./MDMEnrollmentTableConfig";
|
||||
|
||||
interface IMDMCardProps {
|
||||
showMDMUI: boolean;
|
||||
currentTeamId: number | undefined;
|
||||
setShowMDMUI: (showMDMTitle: boolean) => void;
|
||||
setTitleDetail?: (content: JSX.Element | string | null) => void;
|
||||
interface IMdmCardProps {
|
||||
errorMacAdmins: Error | null;
|
||||
isMacAdminsFetching: boolean;
|
||||
formattedMdmData: IDataTableMdmFormat[];
|
||||
mdmSolutions: IMdmSolution[] | null;
|
||||
}
|
||||
|
||||
const DEFAULT_SORT_DIRECTION = "desc";
|
||||
|
|
@ -34,7 +27,7 @@ const ENROLLMENT_DEFAULT_SORT_HEADER = "status";
|
|||
const PAGE_SIZE = 8;
|
||||
const baseClass = "home-mdm";
|
||||
|
||||
const EmptyMDMEnrollment = (): JSX.Element => (
|
||||
const EmptyMdmEnrollment = (): JSX.Element => (
|
||||
<div className={`${baseClass}__empty-mdm`}>
|
||||
<h1>Unable to detect MDM enrollment</h1>
|
||||
<p>
|
||||
|
|
@ -51,7 +44,7 @@ const EmptyMDMEnrollment = (): JSX.Element => (
|
|||
</div>
|
||||
);
|
||||
|
||||
const EmptyMDMSolutions = (): JSX.Element => (
|
||||
const EmptyMdmSolutions = (): JSX.Element => (
|
||||
<div className={`${baseClass}__empty-mdm`}>
|
||||
<h1>No MDM solutions detected</h1>
|
||||
<p>
|
||||
|
|
@ -61,60 +54,13 @@ const EmptyMDMSolutions = (): JSX.Element => (
|
|||
</div>
|
||||
);
|
||||
|
||||
const MDM = ({
|
||||
showMDMUI,
|
||||
currentTeamId,
|
||||
setShowMDMUI,
|
||||
setTitleDetail,
|
||||
}: IMDMCardProps): JSX.Element => {
|
||||
const Mdm = ({
|
||||
isMacAdminsFetching,
|
||||
errorMacAdmins,
|
||||
formattedMdmData,
|
||||
mdmSolutions,
|
||||
}: IMdmCardProps): JSX.Element => {
|
||||
const [navTabIndex, setNavTabIndex] = useState(0);
|
||||
const [formattedMDMData, setFormattedMDMData] = useState<
|
||||
IDataTableMDMFormat[]
|
||||
>([]);
|
||||
const [solutions, setSolutions] = useState<IMDMSolution[] | null>([]);
|
||||
|
||||
const { isFetching: isMDMFetching, error: errorMDM } = useQuery<
|
||||
IMacadminAggregate,
|
||||
Error
|
||||
>(["MDM", currentTeamId], () => macadminsAPI.loadAll(currentTeamId), {
|
||||
keepPreviousData: true,
|
||||
onSuccess: (data) => {
|
||||
const {
|
||||
counts_updated_at,
|
||||
mobile_device_management_enrollment_status,
|
||||
mobile_device_management_solution,
|
||||
} = data.macadmins;
|
||||
const {
|
||||
enrolled_manual_hosts_count,
|
||||
enrolled_automated_hosts_count,
|
||||
unenrolled_hosts_count,
|
||||
} = mobile_device_management_enrollment_status;
|
||||
|
||||
setShowMDMUI(true);
|
||||
setTitleDetail &&
|
||||
setTitleDetail(
|
||||
<LastUpdatedText
|
||||
lastUpdatedAt={counts_updated_at}
|
||||
whatToRetrieve={"MDM enrollment"}
|
||||
/>
|
||||
);
|
||||
setFormattedMDMData([
|
||||
{
|
||||
status: "Enrolled (manual)",
|
||||
hosts: enrolled_manual_hosts_count,
|
||||
},
|
||||
{
|
||||
status: "Enrolled (automatic)",
|
||||
hosts: enrolled_automated_hosts_count,
|
||||
},
|
||||
{ status: "Unenrolled", hosts: unenrolled_hosts_count },
|
||||
]);
|
||||
setSolutions(mobile_device_management_solution);
|
||||
},
|
||||
onError: () => {
|
||||
setShowMDMUI(true);
|
||||
},
|
||||
});
|
||||
|
||||
const onTabChange = (index: number) => {
|
||||
setNavTabIndex(index);
|
||||
|
|
@ -122,14 +68,14 @@ const MDM = ({
|
|||
|
||||
const solutionsTableHeaders = generateSolutionsTableHeaders();
|
||||
const enrollmentTableHeaders = generateEnrollmentTableHeaders();
|
||||
const solutionsDataSet = generateSolutionsDataSet(solutions);
|
||||
const solutionsDataSet = generateSolutionsDataSet(mdmSolutions);
|
||||
|
||||
// Renders opaque information as host information is loading
|
||||
const opacity = showMDMUI ? { opacity: 1 } : { opacity: 0 };
|
||||
const opacity = isMacAdminsFetching ? { opacity: 0 } : { opacity: 1 };
|
||||
|
||||
return (
|
||||
<div className={baseClass}>
|
||||
{!showMDMUI && (
|
||||
{isMacAdminsFetching && (
|
||||
<div className="spinner">
|
||||
<Spinner />
|
||||
</div>
|
||||
|
|
@ -142,18 +88,18 @@ const MDM = ({
|
|||
<Tab>Enrollment</Tab>
|
||||
</TabList>
|
||||
<TabPanel>
|
||||
{errorMDM ? (
|
||||
{errorMacAdmins ? (
|
||||
<TableDataError card />
|
||||
) : (
|
||||
<TableContainer
|
||||
columns={solutionsTableHeaders}
|
||||
data={solutionsDataSet}
|
||||
isLoading={isMDMFetching}
|
||||
isLoading={isMacAdminsFetching}
|
||||
defaultSortHeader={SOLUTIONS_DEFAULT_SORT_HEADER}
|
||||
defaultSortDirection={DEFAULT_SORT_DIRECTION}
|
||||
hideActionButton
|
||||
resultsTitle={"MDM"}
|
||||
emptyComponent={EmptyMDMSolutions}
|
||||
emptyComponent={EmptyMdmSolutions}
|
||||
showMarkAllPages={false}
|
||||
isAllPagesSelected={false}
|
||||
isClientSidePagination
|
||||
|
|
@ -164,18 +110,18 @@ const MDM = ({
|
|||
)}
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
{errorMDM ? (
|
||||
{errorMacAdmins ? (
|
||||
<TableDataError card />
|
||||
) : (
|
||||
<TableContainer
|
||||
columns={enrollmentTableHeaders}
|
||||
data={formattedMDMData}
|
||||
isLoading={isMDMFetching}
|
||||
data={formattedMdmData}
|
||||
isLoading={isMacAdminsFetching}
|
||||
defaultSortHeader={ENROLLMENT_DEFAULT_SORT_HEADER}
|
||||
defaultSortDirection={ENROLLMENT_DEFAULT_SORT_DIRECTION}
|
||||
hideActionButton
|
||||
resultsTitle={"MDM"}
|
||||
emptyComponent={EmptyMDMEnrollment}
|
||||
emptyComponent={EmptyMdmEnrollment}
|
||||
showMarkAllPages={false}
|
||||
isAllPagesSelected={false}
|
||||
disableCount
|
||||
|
|
@ -192,4 +138,4 @@ const MDM = ({
|
|||
);
|
||||
};
|
||||
|
||||
export default MDM;
|
||||
export default Mdm;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React from "react";
|
||||
import { Link } from "react-router";
|
||||
|
||||
import { IDataTableMDMFormat } from "interfaces/macadmins";
|
||||
import { IDataTableMdmFormat } from "interfaces/macadmins";
|
||||
|
||||
import PATHS from "router/paths";
|
||||
import TextCell from "components/TableContainer/DataTable/TextCell";
|
||||
|
|
@ -15,7 +15,7 @@ interface ICellProps {
|
|||
value: string;
|
||||
};
|
||||
row: {
|
||||
original: IDataTableMDMFormat;
|
||||
original: IDataTableMdmFormat;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React from "react";
|
||||
import { Link } from "react-router";
|
||||
|
||||
import { IMDMSolution } from "interfaces/macadmins";
|
||||
import { IMdmSolution } from "interfaces/macadmins";
|
||||
|
||||
import PATHS from "router/paths";
|
||||
import { greyCell } from "utilities/helpers";
|
||||
|
|
@ -16,7 +16,7 @@ interface ICellProps {
|
|||
value: string;
|
||||
};
|
||||
row: {
|
||||
original: IMDMSolution;
|
||||
original: IMdmSolution;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -98,7 +98,7 @@ export const generateSolutionsTableHeaders = (): IDataColumn[] => {
|
|||
return solutionsTableHeaders;
|
||||
};
|
||||
|
||||
const enhanceSolutionsData = (solutions: IMDMSolution[]): IMDMSolution[] => {
|
||||
const enhanceSolutionsData = (solutions: IMdmSolution[]): IMdmSolution[] => {
|
||||
return Object.values(solutions).map((solution) => {
|
||||
return {
|
||||
id: solution.id,
|
||||
|
|
@ -110,8 +110,8 @@ const enhanceSolutionsData = (solutions: IMDMSolution[]): IMDMSolution[] => {
|
|||
};
|
||||
|
||||
export const generateSolutionsDataSet = (
|
||||
solutions: IMDMSolution[] | null
|
||||
): IMDMSolution[] => {
|
||||
solutions: IMdmSolution[] | null
|
||||
): IMdmSolution[] => {
|
||||
if (!solutions) {
|
||||
return [];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,7 @@
|
|||
import React, { useState } from "react";
|
||||
import { useQuery } from "react-query";
|
||||
import { Tab, Tabs, TabList, TabPanel } from "react-tabs";
|
||||
|
||||
import macadminsAPI from "services/entities/macadmins";
|
||||
import {
|
||||
IMacadminAggregate,
|
||||
IMunkiIssuesAggregate,
|
||||
IMunkiVersionsAggregate,
|
||||
} from "interfaces/macadmins";
|
||||
|
|
@ -13,15 +10,14 @@ import TabsWrapper from "components/TabsWrapper";
|
|||
import TableContainer from "components/TableContainer";
|
||||
import Spinner from "components/Spinner";
|
||||
import TableDataError from "components/DataError";
|
||||
import LastUpdatedText from "components/LastUpdatedText";
|
||||
import munkiVersionsTableHeaders from "./MunkiVersionsTableConfig";
|
||||
import munkiIssuesTableHeaders from "./MunkiIssuesTableConfig";
|
||||
|
||||
interface IMunkiCardProps {
|
||||
showMunkiUI: boolean;
|
||||
currentTeamId: number | undefined;
|
||||
setShowMunkiUI: (showMunkiTitle: boolean) => void;
|
||||
setTitleDetail?: (content: JSX.Element | string | null) => void;
|
||||
errorMacAdmins: Error | null;
|
||||
isMacAdminsFetching: boolean;
|
||||
munkiIssuesData: IMunkiIssuesAggregate[];
|
||||
munkiVersionsData: IMunkiVersionsAggregate[];
|
||||
}
|
||||
|
||||
const DEFAULT_SORT_DIRECTION = "desc";
|
||||
|
|
@ -57,58 +53,23 @@ const EmptyMunkiVersions = (): JSX.Element => (
|
|||
);
|
||||
|
||||
const Munki = ({
|
||||
showMunkiUI,
|
||||
currentTeamId,
|
||||
setShowMunkiUI,
|
||||
setTitleDetail,
|
||||
errorMacAdmins,
|
||||
isMacAdminsFetching,
|
||||
munkiIssuesData,
|
||||
munkiVersionsData,
|
||||
}: IMunkiCardProps): JSX.Element => {
|
||||
const [navTabIndex, setNavTabIndex] = useState<number>(0);
|
||||
const [pageIndex, setPageIndex] = useState<number>(0);
|
||||
const [munkiIssuesData, setMunkiIssuesData] = useState<
|
||||
IMunkiIssuesAggregate[]
|
||||
>([]);
|
||||
const [munkiVersionsData, setMunkiVersionsData] = useState<
|
||||
IMunkiVersionsAggregate[]
|
||||
>([]);
|
||||
|
||||
const { isFetching: isMunkiFetching, error: errorMunki } = useQuery<
|
||||
IMacadminAggregate,
|
||||
Error
|
||||
>(["munki", currentTeamId], () => macadminsAPI.loadAll(currentTeamId), {
|
||||
keepPreviousData: true,
|
||||
onSuccess: (data) => {
|
||||
const {
|
||||
counts_updated_at,
|
||||
munki_versions,
|
||||
munki_issues,
|
||||
} = data.macadmins;
|
||||
|
||||
setMunkiVersionsData(munki_versions);
|
||||
setMunkiIssuesData(munki_issues);
|
||||
setShowMunkiUI(true);
|
||||
setTitleDetail &&
|
||||
setTitleDetail(
|
||||
<LastUpdatedText
|
||||
lastUpdatedAt={counts_updated_at}
|
||||
whatToRetrieve={"Munki versions"}
|
||||
/>
|
||||
);
|
||||
},
|
||||
onError: () => {
|
||||
setShowMunkiUI(true);
|
||||
},
|
||||
});
|
||||
|
||||
const onTabChange = (index: number) => {
|
||||
setNavTabIndex(index);
|
||||
};
|
||||
|
||||
// Renders opaque information as host information is loading
|
||||
const opacity = showMunkiUI ? { opacity: 1 } : { opacity: 0 };
|
||||
const opacity = isMacAdminsFetching ? { opacity: 0 } : { opacity: 1 };
|
||||
|
||||
return (
|
||||
<div className={baseClass}>
|
||||
{!showMunkiUI && (
|
||||
{isMacAdminsFetching && (
|
||||
<div className="spinner">
|
||||
<Spinner />
|
||||
</div>
|
||||
|
|
@ -121,13 +82,13 @@ const Munki = ({
|
|||
<Tab>Versions</Tab>
|
||||
</TabList>
|
||||
<TabPanel>
|
||||
{errorMunki ? (
|
||||
{errorMacAdmins ? (
|
||||
<TableDataError card />
|
||||
) : (
|
||||
<TableContainer
|
||||
columns={munkiIssuesTableHeaders}
|
||||
data={munkiIssuesData || []}
|
||||
isLoading={isMunkiFetching}
|
||||
isLoading={isMacAdminsFetching}
|
||||
defaultSortHeader={DEFAULT_SORT_HEADER}
|
||||
defaultSortDirection={DEFAULT_SORT_DIRECTION}
|
||||
hideActionButton
|
||||
|
|
@ -144,13 +105,13 @@ const Munki = ({
|
|||
)}
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
{errorMunki ? (
|
||||
{errorMacAdmins ? (
|
||||
<TableDataError card />
|
||||
) : (
|
||||
<TableContainer
|
||||
columns={munkiVersionsTableHeaders}
|
||||
data={munkiVersionsData || []}
|
||||
isLoading={isMunkiFetching}
|
||||
isLoading={isMacAdminsFetching}
|
||||
defaultSortHeader={DEFAULT_SORT_HEADER}
|
||||
defaultSortDirection={DEFAULT_SORT_DIRECTION}
|
||||
hideActionButton
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useState } from "react";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { Link } from "react-router";
|
||||
|
||||
import Button from "components/buttons/Button";
|
||||
|
|
@ -6,6 +6,7 @@ import LinkArrow from "../../../../../assets/images/icon-arrow-right-vibrant-blu
|
|||
|
||||
interface IInfoCardProps {
|
||||
title: string;
|
||||
titleDetail?: JSX.Element | string | null;
|
||||
description?: JSX.Element | string;
|
||||
children: React.ReactChild | React.ReactChild[];
|
||||
action?:
|
||||
|
|
@ -27,6 +28,7 @@ const baseClass = "homepage-info-card";
|
|||
|
||||
const useInfoCard = ({
|
||||
title,
|
||||
titleDetail: defaultTitleDetail,
|
||||
description: defaultDescription,
|
||||
children,
|
||||
action,
|
||||
|
|
@ -35,12 +37,18 @@ const useInfoCard = ({
|
|||
}: IInfoCardProps): JSX.Element => {
|
||||
const [actionLink, setActionURL] = useState<string | null>(null);
|
||||
const [titleDetail, setTitleDetail] = useState<JSX.Element | string | null>(
|
||||
null
|
||||
defaultTitleDetail || null
|
||||
);
|
||||
const [description, setDescription] = useState<JSX.Element | string | null>(
|
||||
defaultDescription || null
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (defaultTitleDetail) {
|
||||
setTitleDetail(defaultTitleDetail);
|
||||
}
|
||||
}, [defaultTitleDetail]);
|
||||
|
||||
const renderAction = () => {
|
||||
if (action) {
|
||||
if (action.type === "button") {
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ import {
|
|||
} from "interfaces/enroll_secret";
|
||||
import { IHost } from "interfaces/host";
|
||||
import { ILabel } from "interfaces/label";
|
||||
import { IMDMSolution, IMunkiIssuesAggregate } from "interfaces/macadmins";
|
||||
import { IMdmSolution, IMunkiIssuesAggregate } from "interfaces/macadmins";
|
||||
import {
|
||||
formatOperatingSystemDisplayName,
|
||||
IOperatingSystemVersion,
|
||||
|
|
@ -225,7 +225,7 @@ const ManageHostsPage = ({
|
|||
const [
|
||||
mdmSolutionDetails,
|
||||
setMDMSolutionDetails,
|
||||
] = useState<IMDMSolution | null>(null);
|
||||
] = useState<IMdmSolution | null>(null);
|
||||
const [
|
||||
munkiIssueDetails,
|
||||
setMunkiIssueDetails,
|
||||
|
|
|
|||
Loading…
Reference in a new issue