From 6917331a1b25cd58652c243c0fbd30a5007cf480 Mon Sep 17 00:00:00 2001 From: RachelElysia <71795832+RachelElysia@users.noreply.github.com> Date: Tue, 26 Apr 2022 14:00:47 -0400 Subject: [PATCH] Host Details Page: Render better messaging for various empty states (#5294) --- ...-3124-better-empty-states-for-host-details | 1 + .../HostDetailsPage/HostDetailsPage.tsx | 17 +++- .../details/cards/EmptyState/EmptyState.tsx | 85 +++++++++++++++++++ .../EmptyUsers => EmptyState}/_styles.scss | 19 +++-- .../hosts/details/cards/EmptyState/index.ts | 1 + .../Software/EmptySoftware/EmptySoftware.tsx | 18 ---- .../cards/Software/EmptySoftware/_styles.scss | 54 ------------ .../cards/Software/EmptySoftware/index.ts | 1 - .../hosts/details/cards/Software/Software.tsx | 29 ++++--- .../cards/Users/EmptyUsers/EmptyUsers.tsx | 18 ---- .../details/cards/Users/EmptyUsers/index.ts | 1 - .../pages/hosts/details/cards/Users/Users.tsx | 54 ++++++------ 12 files changed, 162 insertions(+), 136 deletions(-) create mode 100644 changes/issue-3124-better-empty-states-for-host-details create mode 100644 frontend/pages/hosts/details/cards/EmptyState/EmptyState.tsx rename frontend/pages/hosts/details/cards/{Users/EmptyUsers => EmptyState}/_styles.scss (79%) create mode 100644 frontend/pages/hosts/details/cards/EmptyState/index.ts delete mode 100644 frontend/pages/hosts/details/cards/Software/EmptySoftware/EmptySoftware.tsx delete mode 100644 frontend/pages/hosts/details/cards/Software/EmptySoftware/_styles.scss delete mode 100644 frontend/pages/hosts/details/cards/Software/EmptySoftware/index.ts delete mode 100644 frontend/pages/hosts/details/cards/Users/EmptyUsers/EmptyUsers.tsx delete mode 100644 frontend/pages/hosts/details/cards/Users/EmptyUsers/index.ts diff --git a/changes/issue-3124-better-empty-states-for-host-details b/changes/issue-3124-better-empty-states-for-host-details new file mode 100644 index 0000000000..a255e99439 --- /dev/null +++ b/changes/issue-3124-better-empty-states-for-host-details @@ -0,0 +1 @@ +* Improve empty state messages on host details page \ No newline at end of file diff --git a/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx b/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx index 91eabc52de..e06c2a3387 100644 --- a/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx +++ b/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx @@ -9,12 +9,14 @@ import classnames from "classnames"; import { pick } from "lodash"; import PATHS from "router/paths"; +import configAPI from "services/entities/config"; import hostAPI from "services/entities/hosts"; import queryAPI from "services/entities/queries"; import teamAPI from "services/entities/teams"; import { AppContext } from "context/app"; import { PolicyContext } from "context/policy"; import { NotificationContext } from "context/notification"; +import { IConfig } from "interfaces/config"; import { IHost, IDeviceMappingResponse, @@ -204,6 +206,14 @@ const HostDetailsPage = ({ } ); + const { data: hostSettings } = useQuery< + IConfig, + Error, + { enable_host_users: boolean; enable_software_inventory: boolean } + >(["config"], () => configAPI.loadAll(), { + select: (data: IConfig) => data.host_settings, + }); + const refetchExtensions = () => { deviceMapping !== null && refetchDeviceMapping(); macadmins !== null && refetchMacadmins(); @@ -582,10 +592,15 @@ const HostDetailsPage = ({ usersState={usersState} isLoading={isLoadingHost} onUsersTableSearchChange={onUsersTableSearchChange} + hostUsersEnabled={hostSettings?.enable_host_users} /> - + { + const formalTitle = () => { + switch (title) { + case "software": + return "Software inventory"; + case "users": + return "User collection"; + default: + return "Data collection"; + } + }; + + switch (reason) { + case "empty-search": + return ( +
+
+
+

No {title} matched your search criteria.

+

Try a different search.

+
+
+
+ ); + case "disabled": + return ( +
+
+
+

{formalTitle()} has been disabled.

+

+ Check out the Fleet documentation for{" "} + + steps to enable this feature + External link + +

+
+
+
+ ); + default: + return ( +
+
+
+

+ Disable icon + No {title} collected from this host. +

+

+ Check out the Fleet documentation on{" "} + + how to troubleshoot{" "} + External link + +

+
+
+
+ ); + } +}; + +export default EmptyState; diff --git a/frontend/pages/hosts/details/cards/Users/EmptyUsers/_styles.scss b/frontend/pages/hosts/details/cards/EmptyState/_styles.scss similarity index 79% rename from frontend/pages/hosts/details/cards/Users/EmptyUsers/_styles.scss rename to frontend/pages/hosts/details/cards/EmptyState/_styles.scss index c712a62cb9..983741d53e 100644 --- a/frontend/pages/hosts/details/cards/Users/EmptyUsers/_styles.scss +++ b/frontend/pages/hosts/details/cards/EmptyState/_styles.scss @@ -1,23 +1,22 @@ -.empty-users { +.empty-state { display: flex; flex-direction: column; - align-items: center; - margin-top: 80px; - margin-bottom: 80px; + align-items: flex-start; + margin: 0; &__inner { display: flex; flex-direction: row; h1 { - font-size: $small; + font-size: $x-small; font-weight: $bold; margin-bottom: $pad-medium; } img { width: 176px; - margin-right: 34px; + margin-right: $pad-small; } p { @@ -36,13 +35,12 @@ font-size: $x-small; font-weight: $bold; text-decoration: none; - margin-left: $pad-xsmall; } img { width: 12px; height: 12px; - margin-left: 6px; + margin-left: 4px; } } @@ -52,3 +50,8 @@ width: 350px; } } + +.empty-search { + margin-top: $pad-small; + align-items: center; +} diff --git a/frontend/pages/hosts/details/cards/EmptyState/index.ts b/frontend/pages/hosts/details/cards/EmptyState/index.ts new file mode 100644 index 0000000000..af43732fb2 --- /dev/null +++ b/frontend/pages/hosts/details/cards/EmptyState/index.ts @@ -0,0 +1 @@ +export { default } from "./EmptyState"; diff --git a/frontend/pages/hosts/details/cards/Software/EmptySoftware/EmptySoftware.tsx b/frontend/pages/hosts/details/cards/Software/EmptySoftware/EmptySoftware.tsx deleted file mode 100644 index fe2d86c926..0000000000 --- a/frontend/pages/hosts/details/cards/Software/EmptySoftware/EmptySoftware.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from "react"; - -const baseClass = "empty-software"; - -const EmptySoftware = (): JSX.Element => { - return ( -
-
-
-

No software matched your search criteria.

-

Try a different search.

-
-
-
- ); -}; - -export default EmptySoftware; diff --git a/frontend/pages/hosts/details/cards/Software/EmptySoftware/_styles.scss b/frontend/pages/hosts/details/cards/Software/EmptySoftware/_styles.scss deleted file mode 100644 index c8cdef584c..0000000000 --- a/frontend/pages/hosts/details/cards/Software/EmptySoftware/_styles.scss +++ /dev/null @@ -1,54 +0,0 @@ -.empty-software { - display: flex; - flex-direction: column; - align-items: center; - margin-top: $pad-xxxlarge; - margin-bottom: $pad-xxxlarge; - - &__inner { - display: flex; - flex-direction: row; - - h1 { - font-size: $small; - font-weight: $bold; - margin-bottom: $pad-medium; - } - - img { - width: 176px; - margin-right: 34px; - } - - p { - color: $core-fleet-black; - font-weight: $regular; - font-size: $x-small; - margin: 0; - } - - p.learn-more { - margin-top: $pad-medium; - } - - a { - color: $core-vibrant-blue; - font-size: $x-small; - font-weight: $bold; - text-decoration: none; - margin-left: $pad-xsmall; - } - - img { - width: 12px; - height: 12px; - margin-left: 6px; - } - } - - &__empty-filter-results { - display: flex; - flex-direction: column; - width: 350px; - } -} diff --git a/frontend/pages/hosts/details/cards/Software/EmptySoftware/index.ts b/frontend/pages/hosts/details/cards/Software/EmptySoftware/index.ts deleted file mode 100644 index 441d2e042c..0000000000 --- a/frontend/pages/hosts/details/cards/Software/EmptySoftware/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./EmptySoftware"; diff --git a/frontend/pages/hosts/details/cards/Software/Software.tsx b/frontend/pages/hosts/details/cards/Software/Software.tsx index b7ba8d282d..233e0161c6 100644 --- a/frontend/pages/hosts/details/cards/Software/Software.tsx +++ b/frontend/pages/hosts/details/cards/Software/Software.tsx @@ -8,7 +8,7 @@ import { VULNERABLE_DROPDOWN_OPTIONS } from "utilities/constants"; import Dropdown from "components/forms/fields/Dropdown"; import TableContainer from "components/TableContainer"; -import EmptySoftware from "./EmptySoftware"; +import EmptyState from "../EmptyState"; import SoftwareVulnCount from "./SoftwareVulnCount"; import generateSoftwareTableHeaders from "./SoftwareTableConfig"; @@ -23,12 +23,14 @@ interface ISoftwareTableProps { isLoading: boolean; software: ISoftware[]; deviceUser?: boolean; + softwareInventoryEnabled?: boolean; } const SoftwareTable = ({ isLoading, software, deviceUser, + softwareInventoryEnabled, }: ISoftwareTableProps): JSX.Element => { const tableSoftware: ITableSoftware[] = software.map((s) => { return { @@ -76,6 +78,19 @@ const SoftwareTable = ({ const tableHeaders = generateSoftwareTableHeaders(deviceUser); + const EmptySoftwareSearch = () => ( + + ); + + if (!softwareInventoryEnabled) { + return ( +
+

Software

+ +
+ ); + } + return (

Software

@@ -101,7 +116,7 @@ const SoftwareTable = ({ } onQueryChange={onQueryChange} resultsTitle={"software items"} - emptyComponent={EmptySoftware} + emptyComponent={EmptySoftwareSearch} showMarkAllPages={false} isAllPagesSelected={false} searchable @@ -113,15 +128,7 @@ const SoftwareTable = ({ )} ) : ( -
-

- No installed software detected on this host. -

-

- Expecting to see software? Try again in a few seconds as the system - catches up. -

-
+ )}
); diff --git a/frontend/pages/hosts/details/cards/Users/EmptyUsers/EmptyUsers.tsx b/frontend/pages/hosts/details/cards/Users/EmptyUsers/EmptyUsers.tsx deleted file mode 100644 index d1a05d9f7f..0000000000 --- a/frontend/pages/hosts/details/cards/Users/EmptyUsers/EmptyUsers.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from "react"; - -const baseClass = "empty-users"; - -const EmptyUsers = (): JSX.Element => { - return ( -
-
-
-

No users matched your search criteria.

-

Try a different search.

-
-
-
- ); -}; - -export default EmptyUsers; diff --git a/frontend/pages/hosts/details/cards/Users/EmptyUsers/index.ts b/frontend/pages/hosts/details/cards/Users/EmptyUsers/index.ts deleted file mode 100644 index 28df7b7cca..0000000000 --- a/frontend/pages/hosts/details/cards/Users/EmptyUsers/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./EmptyUsers"; diff --git a/frontend/pages/hosts/details/cards/Users/Users.tsx b/frontend/pages/hosts/details/cards/Users/Users.tsx index c569a1f4e8..cbce0f226a 100644 --- a/frontend/pages/hosts/details/cards/Users/Users.tsx +++ b/frontend/pages/hosts/details/cards/Users/Users.tsx @@ -4,7 +4,7 @@ import { IHostUser } from "interfaces/host_users"; import TableContainer from "components/TableContainer"; import generateUsersTableHeaders from "./UsersTable/UsersTableConfig"; -import EmptyUsers from "./EmptyUsers"; +import EmptyState from "../EmptyState"; interface ISearchQueryData { searchQuery: string; @@ -19,6 +19,7 @@ interface IUsersProps { usersState: { username: string }[]; isLoading: boolean; onUsersTableSearchChange: (queryData: ISearchQueryData) => void; + hostUsersEnabled?: boolean; } const Users = ({ @@ -26,34 +27,19 @@ const Users = ({ usersState, isLoading, onUsersTableSearchChange, + hostUsersEnabled, }: IUsersProps): JSX.Element => { const tableHeaders = generateUsersTableHeaders(); - if (users) { + const EmptyUserSearch = () => ( + + ); + + if (!hostUsersEnabled) { return (

Users

- {users.length === 0 ? ( -

No users were detected on this host.

- ) : ( - - )} +
); } @@ -61,7 +47,27 @@ const Users = ({ return (

Users

-

No users were detected on this host.

+ {users?.length ? ( + + ) : ( + + )}
); };