2022-02-08 05:03:01 +00:00
|
|
|
import React, { useContext, useState } from "react";
|
2021-10-19 18:13:18 +00:00
|
|
|
import { useQuery } from "react-query";
|
|
|
|
import { AppContext } from "context/app";
|
|
|
|
import { find } from "lodash";
|
|
|
|
|
2021-11-12 14:27:05 +00:00
|
|
|
import hostSummaryAPI from "services/entities/host_summary";
|
2021-10-19 18:13:18 +00:00
|
|
|
import teamsAPI from "services/entities/teams";
|
2021-11-12 14:27:05 +00:00
|
|
|
import { IHostSummary, IHostSummaryPlatforms } from "interfaces/host_summary";
|
2022-04-05 20:04:00 +00:00
|
|
|
import { IOsqueryPlatform } from "interfaces/platform";
|
2021-11-12 14:27:05 +00:00
|
|
|
import { ITeam } from "interfaces/team";
|
2021-12-01 23:37:33 +00:00
|
|
|
import sortUtils from "utilities/sort";
|
2022-02-08 05:03:01 +00:00
|
|
|
import { PLATFORM_DROPDOWN_OPTIONS } from "utilities/constants";
|
2021-10-19 18:13:18 +00:00
|
|
|
|
|
|
|
import TeamsDropdown from "components/TeamsDropdown";
|
2022-04-07 16:08:00 +00:00
|
|
|
import Spinner from "components/Spinner"; // @ts-ignore
|
2022-02-08 05:03:01 +00:00
|
|
|
import Dropdown from "components/forms/fields/Dropdown";
|
|
|
|
import useInfoCard from "./components/InfoCard";
|
2021-11-12 14:27:05 +00:00
|
|
|
import HostsStatus from "./cards/HostsStatus";
|
2021-10-26 19:47:34 +00:00
|
|
|
import HostsSummary from "./cards/HostsSummary";
|
|
|
|
import ActivityFeed from "./cards/ActivityFeed";
|
|
|
|
import Software from "./cards/Software";
|
|
|
|
import LearnFleet from "./cards/LearnFleet";
|
|
|
|
import WelcomeHost from "./cards/WelcomeHost";
|
2022-02-08 05:03:01 +00:00
|
|
|
import MDM from "./cards/MDM";
|
|
|
|
import Munki from "./cards/Munki";
|
2022-04-05 20:04:00 +00:00
|
|
|
import OperatingSystems from "./cards/OperatingSystems";
|
2022-02-08 05:03:01 +00:00
|
|
|
import ExternalURLIcon from "../../../assets/images/icon-external-url-12x12@2x.png";
|
2021-10-19 18:13:18 +00:00
|
|
|
|
|
|
|
interface ITeamsResponse {
|
|
|
|
teams: ITeam[];
|
|
|
|
}
|
2021-07-12 17:15:47 +00:00
|
|
|
|
2021-07-26 20:04:35 +00:00
|
|
|
const baseClass = "homepage";
|
2021-07-12 17:15:47 +00:00
|
|
|
|
2021-07-26 20:04:35 +00:00
|
|
|
const Homepage = (): JSX.Element => {
|
2021-10-26 19:47:34 +00:00
|
|
|
const {
|
|
|
|
config,
|
|
|
|
currentTeam,
|
|
|
|
isPremiumTier,
|
2021-12-07 02:04:40 +00:00
|
|
|
isFreeTier,
|
2021-10-26 19:47:34 +00:00
|
|
|
isPreviewMode,
|
2021-12-01 23:37:33 +00:00
|
|
|
isOnGlobalTeam,
|
2021-10-26 19:47:34 +00:00
|
|
|
setCurrentTeam,
|
|
|
|
} = useContext(AppContext);
|
2021-10-19 18:13:18 +00:00
|
|
|
|
2022-02-08 05:03:01 +00:00
|
|
|
const [selectedPlatform, setSelectedPlatform] = useState<string>("");
|
2021-11-12 14:27:05 +00:00
|
|
|
const [totalCount, setTotalCount] = useState<string | undefined>();
|
|
|
|
const [macCount, setMacCount] = useState<string>("0");
|
|
|
|
const [windowsCount, setWindowsCount] = useState<string>("0");
|
|
|
|
const [onlineCount, setOnlineCount] = useState<string | undefined>();
|
|
|
|
const [offlineCount, setOfflineCount] = useState<string | undefined>();
|
2022-01-13 17:12:54 +00:00
|
|
|
const [showActivityFeedTitle, setShowActivityFeedTitle] = useState<boolean>(
|
|
|
|
false
|
|
|
|
);
|
|
|
|
const [showSoftwareUI, setShowSoftwareUI] = useState<boolean>(false);
|
2022-02-08 05:03:01 +00:00
|
|
|
const [showMunkiUI, setShowMunkiUI] = useState<boolean>(false);
|
|
|
|
const [showMDMUI, setShowMDMUI] = useState<boolean>(false);
|
2022-04-05 20:04:00 +00:00
|
|
|
const [showOperatingSystemsUI, setShowOperatingSystemsUI] = useState<boolean>(
|
|
|
|
false
|
|
|
|
);
|
2022-01-13 17:12:54 +00:00
|
|
|
const [showHostsUI, setShowHostsUI] = useState<boolean>(false); // Hides UI on first load only
|
2021-10-19 18:13:18 +00:00
|
|
|
|
2021-12-07 02:04:40 +00:00
|
|
|
const { data: teams } = useQuery<ITeamsResponse, Error, ITeam[]>(
|
|
|
|
["teams"],
|
|
|
|
() => teamsAPI.loadAll(),
|
|
|
|
{
|
|
|
|
enabled: !!isPremiumTier,
|
|
|
|
select: (data: ITeamsResponse) =>
|
|
|
|
data.teams.sort((a, b) => sortUtils.caseInsensitiveAsc(a.name, b.name)),
|
|
|
|
onSuccess: (responseTeams) => {
|
|
|
|
if (!currentTeam && !isOnGlobalTeam && responseTeams.length) {
|
|
|
|
setCurrentTeam(responseTeams[0]);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
);
|
2021-10-19 18:13:18 +00:00
|
|
|
|
2022-02-08 05:03:01 +00:00
|
|
|
const { data: hostSummaryData, isFetching: isHostSummaryFetching } = useQuery<
|
|
|
|
IHostSummary,
|
|
|
|
Error,
|
|
|
|
IHostSummary
|
|
|
|
>(
|
|
|
|
["host summary", currentTeam, selectedPlatform],
|
|
|
|
() =>
|
|
|
|
hostSummaryAPI.getSummary({
|
|
|
|
teamId: currentTeam?.id,
|
|
|
|
platform: selectedPlatform,
|
|
|
|
}),
|
2021-11-12 14:27:05 +00:00
|
|
|
{
|
|
|
|
select: (data: IHostSummary) => data,
|
2022-02-14 22:11:12 +00:00
|
|
|
onSuccess: (data: IHostSummary) => {
|
2021-11-12 14:27:05 +00:00
|
|
|
setOnlineCount(data.online_count.toLocaleString("en-US"));
|
|
|
|
setOfflineCount(data.offline_count.toLocaleString("en-US"));
|
|
|
|
const macHosts = data.platforms?.find(
|
|
|
|
(platform: IHostSummaryPlatforms) => platform.platform === "darwin"
|
|
|
|
) || { platform: "darwin", hosts_count: 0 };
|
|
|
|
setMacCount(macHosts.hosts_count.toLocaleString("en-US"));
|
|
|
|
const windowsHosts = data.platforms?.find(
|
|
|
|
(platform: IHostSummaryPlatforms) => platform.platform === "windows"
|
|
|
|
) || { platform: "windows", hosts_count: 0 };
|
|
|
|
setWindowsCount(windowsHosts.hosts_count.toLocaleString("en-US"));
|
2022-01-13 17:12:54 +00:00
|
|
|
setShowHostsUI(true);
|
2021-11-12 14:27:05 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2022-02-08 05:03:01 +00:00
|
|
|
const handleTeamSelect = (teamId: number) => {
|
|
|
|
const selectedTeam = find(teams, ["id", teamId]);
|
|
|
|
setCurrentTeam(selectedTeam);
|
|
|
|
};
|
|
|
|
|
|
|
|
const HostsSummaryCard = useInfoCard({
|
|
|
|
title: "Hosts",
|
|
|
|
action: {
|
|
|
|
type: "link",
|
|
|
|
text: "View all hosts",
|
|
|
|
},
|
|
|
|
total_host_count: (() => {
|
|
|
|
if (!isHostSummaryFetching) {
|
|
|
|
if (totalCount) {
|
|
|
|
return totalCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
|
|
hostSummaryData?.totals_hosts_count.toLocaleString("en-US") ||
|
|
|
|
undefined
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return undefined;
|
|
|
|
})(),
|
|
|
|
showTitle: true,
|
|
|
|
children: (
|
|
|
|
<HostsSummary
|
|
|
|
currentTeamId={currentTeam?.id}
|
|
|
|
macCount={macCount}
|
|
|
|
windowsCount={windowsCount}
|
|
|
|
isLoadingHostsSummary={isHostSummaryFetching}
|
|
|
|
showHostsUI={showHostsUI}
|
|
|
|
selectedPlatform={selectedPlatform}
|
|
|
|
setTotalCount={setTotalCount}
|
|
|
|
/>
|
|
|
|
),
|
|
|
|
});
|
|
|
|
|
|
|
|
const HostsStatusCard = useInfoCard({
|
|
|
|
title: "",
|
|
|
|
children: (
|
|
|
|
<HostsStatus
|
|
|
|
onlineCount={onlineCount}
|
|
|
|
offlineCount={offlineCount}
|
|
|
|
isLoadingHosts={isHostSummaryFetching}
|
|
|
|
showHostsUI={showHostsUI}
|
|
|
|
/>
|
|
|
|
),
|
|
|
|
});
|
|
|
|
|
|
|
|
const WelcomeHostCard = useInfoCard({
|
|
|
|
title: "Welcome to Fleet",
|
|
|
|
children: <WelcomeHost />,
|
|
|
|
});
|
|
|
|
|
|
|
|
const LearnFleetCard = useInfoCard({
|
|
|
|
title: "Learn how to use Fleet",
|
|
|
|
children: <LearnFleet />,
|
|
|
|
});
|
|
|
|
|
|
|
|
const ActivityFeedCard = useInfoCard({
|
|
|
|
title: "Activity",
|
|
|
|
showTitle: showActivityFeedTitle,
|
|
|
|
children: (
|
|
|
|
<ActivityFeed setShowActivityFeedTitle={setShowActivityFeedTitle} />
|
|
|
|
),
|
|
|
|
});
|
|
|
|
|
|
|
|
const SoftwareCard = useInfoCard({
|
|
|
|
title: "Software",
|
|
|
|
action: {
|
|
|
|
type: "link",
|
|
|
|
text: "View all software",
|
|
|
|
to: "software",
|
|
|
|
},
|
|
|
|
showTitle: showSoftwareUI,
|
|
|
|
children: (
|
|
|
|
<Software
|
|
|
|
currentTeamId={currentTeam?.id}
|
|
|
|
setShowSoftwareUI={setShowSoftwareUI}
|
|
|
|
showSoftwareUI={showSoftwareUI}
|
|
|
|
/>
|
|
|
|
),
|
|
|
|
});
|
|
|
|
|
|
|
|
const MunkiCard = useInfoCard({
|
|
|
|
title: "Munki versions",
|
|
|
|
showTitle: showMunkiUI,
|
|
|
|
description: (
|
|
|
|
<p>
|
|
|
|
Munki is a tool for managing software on macOS devices.{" "}
|
|
|
|
<a
|
|
|
|
target="_blank"
|
|
|
|
rel="noreferrer noopener"
|
|
|
|
href="https://www.munki.org/munki/"
|
|
|
|
>
|
|
|
|
Learn about Munki <img src={ExternalURLIcon} alt="" />
|
|
|
|
</a>
|
|
|
|
</p>
|
|
|
|
),
|
|
|
|
children: (
|
|
|
|
<Munki
|
|
|
|
setShowMunkiUI={setShowMunkiUI}
|
|
|
|
showMunkiUI={showMunkiUI}
|
|
|
|
currentTeamId={currentTeam?.id}
|
|
|
|
/>
|
|
|
|
),
|
|
|
|
});
|
|
|
|
|
|
|
|
const MDMCard = useInfoCard({
|
|
|
|
title: "Mobile device management (MDM) enrollment",
|
|
|
|
showTitle: showMDMUI,
|
|
|
|
description: (
|
|
|
|
<p>
|
|
|
|
MDM is used to manage configuration on macOS devices.{" "}
|
|
|
|
<a
|
|
|
|
target="_blank"
|
|
|
|
rel="noreferrer noopener"
|
|
|
|
href="https://support.apple.com/guide/deployment/intro-to-mdm-depc0aadd3fe/web"
|
|
|
|
>
|
|
|
|
Learn about MDM <img src={ExternalURLIcon} alt="" />
|
|
|
|
</a>
|
|
|
|
</p>
|
|
|
|
),
|
|
|
|
children: (
|
|
|
|
<MDM
|
|
|
|
setShowMDMUI={setShowMDMUI}
|
|
|
|
showMDMUI={showMDMUI}
|
|
|
|
currentTeamId={currentTeam?.id}
|
|
|
|
/>
|
|
|
|
),
|
|
|
|
});
|
|
|
|
|
2022-04-05 20:04:00 +00:00
|
|
|
const OperatingSystemsCard = useInfoCard({
|
|
|
|
title: "Operating systems",
|
|
|
|
showTitle: showOperatingSystemsUI,
|
|
|
|
children: (
|
|
|
|
<OperatingSystems
|
|
|
|
currentTeamId={currentTeam?.id}
|
|
|
|
selectedPlatform={selectedPlatform as IOsqueryPlatform}
|
|
|
|
setShowOperatingSystemsUI={setShowOperatingSystemsUI}
|
|
|
|
showOperatingSystemsUI={showOperatingSystemsUI}
|
|
|
|
/>
|
|
|
|
),
|
|
|
|
});
|
|
|
|
|
2022-02-08 05:03:01 +00:00
|
|
|
const allLayout = () => (
|
|
|
|
<div className={`${baseClass}__section`}>
|
|
|
|
{isPreviewMode && (
|
|
|
|
<>
|
|
|
|
{WelcomeHostCard}
|
|
|
|
{LearnFleetCard}
|
|
|
|
</>
|
|
|
|
)}
|
|
|
|
{SoftwareCard}
|
|
|
|
{!isPreviewMode && !currentTeam && isOnGlobalTeam && (
|
|
|
|
<>{ActivityFeedCard}</>
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
|
|
|
|
const macOSLayout = () => (
|
|
|
|
<div className={`${baseClass}__section`}>
|
2022-04-05 20:04:00 +00:00
|
|
|
{OperatingSystemsCard}
|
2022-02-08 05:03:01 +00:00
|
|
|
{MunkiCard}
|
|
|
|
{MDMCard}
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
|
|
|
|
const windowsLayout = () => null;
|
|
|
|
const linuxLayout = () => null;
|
|
|
|
|
|
|
|
const renderCards = () => {
|
|
|
|
switch (selectedPlatform) {
|
|
|
|
case "darwin":
|
|
|
|
return macOSLayout();
|
|
|
|
case "windows":
|
|
|
|
return windowsLayout();
|
|
|
|
case "linux":
|
|
|
|
return linuxLayout();
|
|
|
|
default:
|
|
|
|
return allLayout();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-07-12 17:15:47 +00:00
|
|
|
return (
|
|
|
|
<div className={baseClass}>
|
2021-12-01 23:37:33 +00:00
|
|
|
<div className={`${baseClass}__wrapper body-wrap`}>
|
2022-02-08 05:03:01 +00:00
|
|
|
<div className={`${baseClass}__header`}>
|
|
|
|
<div className={`${baseClass}__text`}>
|
|
|
|
<div className={`${baseClass}__title`}>
|
2022-04-07 16:08:00 +00:00
|
|
|
{isFreeTier && <h1>{config?.org_info.org_name}</h1>}
|
2022-02-08 05:03:01 +00:00
|
|
|
{isPremiumTier &&
|
|
|
|
teams &&
|
|
|
|
(teams.length > 1 || isOnGlobalTeam) && (
|
|
|
|
<TeamsDropdown
|
|
|
|
selectedTeamId={currentTeam?.id || 0}
|
|
|
|
currentUserTeams={teams || []}
|
|
|
|
onChange={(newSelectedValue: number) =>
|
|
|
|
handleTeamSelect(newSelectedValue)
|
|
|
|
}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
{isPremiumTier &&
|
|
|
|
!isOnGlobalTeam &&
|
|
|
|
teams &&
|
|
|
|
teams.length === 1 && <h1>{teams[0].name}</h1>}
|
2021-12-01 23:37:33 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
2021-07-12 17:15:47 +00:00
|
|
|
</div>
|
2022-02-08 05:03:01 +00:00
|
|
|
<div className={`${baseClass}__platforms`}>
|
|
|
|
<span>Platform: </span>
|
|
|
|
<Dropdown
|
|
|
|
value={selectedPlatform}
|
|
|
|
className={`${baseClass}__platform_dropdown`}
|
|
|
|
options={PLATFORM_DROPDOWN_OPTIONS}
|
|
|
|
searchable={false}
|
|
|
|
onChange={(value: string) => setSelectedPlatform(value)}
|
|
|
|
/>
|
|
|
|
</div>
|
2022-01-13 17:12:54 +00:00
|
|
|
<div className="host-sections">
|
|
|
|
<>
|
2022-02-08 05:03:01 +00:00
|
|
|
{isHostSummaryFetching && (
|
2022-01-13 17:12:54 +00:00
|
|
|
<div className="spinner">
|
|
|
|
<Spinner />
|
|
|
|
</div>
|
|
|
|
)}
|
2022-02-08 05:03:01 +00:00
|
|
|
<div className={`${baseClass}__section`}>{HostsSummaryCard}</div>
|
|
|
|
<div className={`${baseClass}__section`}>{HostsStatusCard}</div>
|
2022-01-13 17:12:54 +00:00
|
|
|
</>
|
2021-10-26 19:47:34 +00:00
|
|
|
</div>
|
2022-02-08 05:03:01 +00:00
|
|
|
{renderCards()}
|
2021-11-15 23:42:51 +00:00
|
|
|
</div>
|
2021-07-12 17:15:47 +00:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2021-07-26 20:04:35 +00:00
|
|
|
export default Homepage;
|