From 08485b3a5c3b149972fed33739c6d21d1fa4f69d Mon Sep 17 00:00:00 2001 From: RachelElysia <71795832+RachelElysia@users.noreply.github.com> Date: Mon, 25 Jul 2022 16:42:03 -0400 Subject: [PATCH] Sandbox UI: Homepage, CTA to add personal device (#6775) --- changes/issue-5911-sandbox-homepage | 1 + frontend/pages/Homepage/Homepage.tsx | 93 +++++++++++++++---- .../cards/ActivityFeed/ActivityFeed.tsx | 5 +- .../cards/WelcomeHost/WelcomeHost.tsx | 78 ++++++++++------ .../Homepage/cards/WelcomeHost/_styles.scss | 30 ++++-- 5 files changed, 146 insertions(+), 61 deletions(-) create mode 100644 changes/issue-5911-sandbox-homepage diff --git a/changes/issue-5911-sandbox-homepage b/changes/issue-5911-sandbox-homepage new file mode 100644 index 0000000000..07842fdad1 --- /dev/null +++ b/changes/issue-5911-sandbox-homepage @@ -0,0 +1 @@ +* Dashboard updates for app, Fleet Sandbox, and Fleet Preview \ No newline at end of file diff --git a/frontend/pages/Homepage/Homepage.tsx b/frontend/pages/Homepage/Homepage.tsx index 5367e7d337..8a5eec8e16 100644 --- a/frontend/pages/Homepage/Homepage.tsx +++ b/frontend/pages/Homepage/Homepage.tsx @@ -3,10 +3,15 @@ import { useQuery } from "react-query"; import { AppContext } from "context/app"; import { find } from "lodash"; +import { + IEnrollSecret, + IEnrollSecretsResponse, +} from "interfaces/enroll_secret"; import { IHostSummary, IHostSummaryPlatforms } from "interfaces/host_summary"; import { ILabelSummary } from "interfaces/label"; 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 teamsAPI, { ILoadTeamsResponse } from "services/entities/teams"; import sortUtils from "utilities/sort"; @@ -26,6 +31,7 @@ import WelcomeHost from "./cards/WelcomeHost"; import MDM from "./cards/MDM"; import Munki from "./cards/Munki"; import OperatingSystems from "./cards/OperatingSystems"; +import AddHostsModal from "../../components/AddHostsModal"; import ExternalURLIcon from "../../../assets/images/icon-external-url-12x12@2x.png"; const baseClass = "homepage"; @@ -34,9 +40,13 @@ const Homepage = (): JSX.Element => { const { config, currentTeam, + isGlobalAdmin, + isGlobalMaintainer, + isTeamAdmin, + isTeamMaintainer, isPremiumTier, isFreeTier, - isPreviewMode, + isSandboxMode, isOnGlobalTeam, setCurrentTeam, } = useContext(AppContext); @@ -54,25 +64,30 @@ const Homepage = (): JSX.Element => { const [showSoftwareUI, setShowSoftwareUI] = useState(false); const [showMunkiUI, setShowMunkiUI] = useState(false); 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 { data: teams } = useQuery( - ["teams"], - () => teamsAPI.loadAll(), - { - enabled: !!isPremiumTier, - select: (data: ILoadTeamsResponse) => - data.teams.sort((a, b) => sortUtils.caseInsensitiveAsc(a.name, b.name)), - onSuccess: (responseTeams) => { - if (!currentTeam && !isOnGlobalTeam && responseTeams.length) { - setCurrentTeam(responseTeams[0]); - } - }, - } - ); + const canEnrollHosts = + isGlobalAdmin || isGlobalMaintainer || isTeamAdmin || isTeamMaintainer; + const canEnrollGlobalHosts = isGlobalAdmin || isGlobalMaintainer; + + const { data: teams, isLoading: isLoadingTeams } = useQuery< + ILoadTeamsResponse, + Error, + ITeam[] + >(["teams"], () => teamsAPI.loadAll(), { + enabled: !!isPremiumTier, + select: (data: ILoadTeamsResponse) => + data.teams.sort((a, b) => sortUtils.caseInsensitiveAsc(a.name, b.name)), + onSuccess: (responseTeams) => { + if (!currentTeam && !isOnGlobalTeam && responseTeams.length) { + setCurrentTeam(responseTeams[0]); + } + }, + }); const { data: hostSummaryData, @@ -108,11 +123,28 @@ const Homepage = (): JSX.Element => { } ); + const { + isLoading: isGlobalSecretsLoading, + data: globalSecrets, + refetch: refetchGlobalSecrets, + } = useQuery( + ["global secrets"], + () => enrollSecretsAPI.getGlobalEnrollSecrets(), + { + enabled: !!canEnrollGlobalHosts, + select: (data: IEnrollSecretsResponse) => data.secrets, + } + ); + const handleTeamSelect = (teamId: number) => { const selectedTeam = find(teams, ["id", teamId]); setCurrentTeam(selectedTeam); }; + const toggleAddHostsModal = () => { + setShowAddHostsModal(!showAddHostsModal); + }; + const HostsSummaryCard = useInfoCard({ title: "Hosts", action: { @@ -156,11 +188,20 @@ const Homepage = (): JSX.Element => { const WelcomeHostCard = useInfoCard({ title: "Welcome to Fleet", - children: , + showTitle: true, + children: ( + + ), }); const LearnFleetCard = useInfoCard({ title: "Learn how to use Fleet", + showTitle: true, children: , }); @@ -252,16 +293,14 @@ const Homepage = (): JSX.Element => { const allLayout = () => (
- {isPreviewMode && ( + {hostSummaryData && hostSummaryData?.totals_hosts_count < 2 && ( <> {WelcomeHostCard} {LearnFleetCard} )} {SoftwareCard} - {!isPreviewMode && !currentTeam && isOnGlobalTeam && ( - <>{ActivityFeedCard} - )} + {!currentTeam && isOnGlobalTeam && <>{ActivityFeedCard}}
); @@ -289,6 +328,19 @@ const Homepage = (): JSX.Element => { } }; + const renderAddHostsModal = () => { + const enrollSecret = globalSecrets?.[0].secret; + return ( + + ); + }; + return (
@@ -336,6 +388,7 @@ const Homepage = (): JSX.Element => {
{renderCards()} + {showAddHostsModal && renderAddHostsModal()}
); diff --git a/frontend/pages/Homepage/cards/ActivityFeed/ActivityFeed.tsx b/frontend/pages/Homepage/cards/ActivityFeed/ActivityFeed.tsx index 1a6b65f756..07f083c24c 100644 --- a/frontend/pages/Homepage/cards/ActivityFeed/ActivityFeed.tsx +++ b/frontend/pages/Homepage/cards/ActivityFeed/ActivityFeed.tsx @@ -145,11 +145,10 @@ const ActivityFeed = ({ return (

- This is the start of your Fleet activities. + Fleet has not recorded any activity.

- Did you recently edit your queries, update your packs, or run a live - query? Try again in a few seconds as the system catches up. + Try editing a query, updating your policies, or running a live query.

); diff --git a/frontend/pages/Homepage/cards/WelcomeHost/WelcomeHost.tsx b/frontend/pages/Homepage/cards/WelcomeHost/WelcomeHost.tsx index 25938e1766..aa34c46da5 100644 --- a/frontend/pages/Homepage/cards/WelcomeHost/WelcomeHost.tsx +++ b/frontend/pages/Homepage/cards/WelcomeHost/WelcomeHost.tsx @@ -24,12 +24,20 @@ interface IHostResponse { host: IHost; } +interface IWelcomeHostCardProps { + totalsHostsCount: number; + toggleAddHostsModal: (showAddHostsModal: boolean) => void; +} + const baseClass = "welcome-host"; const HOST_ID = 1; const policyPass = "pass"; const policyFail = "fail"; -const WelcomeHost = (): JSX.Element => { +const WelcomeHost = ({ + totalsHostsCount, + toggleAddHostsModal, +}: IWelcomeHostCardProps): JSX.Element => { const { renderFlash } = useContext(NotificationContext); const [refetchStartTime, setRefetchStartTime] = useState(null); const [currentPolicyShown, setCurrentPolicyShown] = useState(); @@ -129,7 +137,6 @@ const WelcomeHost = (): JSX.Element => { return (
-

Adding your device to Fleet

@@ -137,6 +144,26 @@ const WelcomeHost = (): JSX.Element => { } if (loadingHostError) { + return ( +
+
+

Add your personal device to assess the security of your device.

+

+ In Fleet, laptops, workstations, and servers are referred to as + "hosts." +

+ +
+
+ ); + } + + if (totalsHostsCount === 1 && host && host.status === "offline") { return (
@@ -194,7 +221,7 @@ const WelcomeHost = (): JSX.Element => { ); } - if (host) { + if (totalsHostsCount === 1 && host && host.status === "online") { return (
@@ -204,53 +231,48 @@ const WelcomeHost = (): JSX.Element => { {host.hostname} -

- Your device is successully connected to this local preview of - Fleet. -

+

Your host is successfully connected to Fleet.

- Fleet already ran the following checks to assess the security of + Fleet already ran the following policies to assess the security of your device:{" "}

- {host.policies?.slice(0, 10).map((p) => { + {host.policies?.slice(0, 3).map((p) => { if (p.response) { return ( -
-
- {p.response} - {p.name} -
- -
+
+ ); } return null; })} - {host.policies?.length > 10 && ( + {host.policies?.length > 3 && ( - Go to Host details to see all checks + Go to Host details to see all policies )}
-

- Resolved a failing check? Refetch your device information to verify. -

+

Resolved a failing policy? Refetch your host vitals to verify.