diff --git a/frontend/pages/admin/AppSettingsPage/_styles.scss b/frontend/pages/admin/AppSettingsPage/_styles.scss
index 4eeecb2ddf..df4d585b10 100644
--- a/frontend/pages/admin/AppSettingsPage/_styles.scss
+++ b/frontend/pages/admin/AppSettingsPage/_styles.scss
@@ -49,6 +49,7 @@
&__section {
@include clearfix;
margin: 0 0 $pad-large;
+ animation: fade-in 200ms ease-out;
.upcaret::after {
content: url("../assets/images/icon-collapse-black-16x16@2x.png");
@@ -75,7 +76,7 @@
font-size: $medium;
font-weight: $regular;
color: $core-fleet-black;
- border-bottom: solid 1px $ui-fleet-blue-15;
+ border-bottom: solid 1px $ui-fleet-black-10;
margin: 0 0 $pad-xxlarge;
@media (min-width: $break-990) {
@@ -198,7 +199,7 @@
border-radius: 20%;
height: 120px;
width: 120px;
- border: 1px solid $ui-fleet-blue-15;
+ border: 1px solid $ui-fleet-black-10;
background-color: $ui-light-grey;
position: relative;
bottom: -20px;
diff --git a/frontend/pages/admin/IntegrationsPage/cards/Integrations/Integrations.tsx b/frontend/pages/admin/IntegrationsPage/cards/Integrations/Integrations.tsx
index dea60d91ef..d1dc28ad6a 100644
--- a/frontend/pages/admin/IntegrationsPage/cards/Integrations/Integrations.tsx
+++ b/frontend/pages/admin/IntegrationsPage/cards/Integrations/Integrations.tsx
@@ -12,6 +12,7 @@ import {
IIntegrations,
} from "interfaces/integration";
import { IApiError } from "interfaces/errors";
+import { IEmptyTableProps } from "interfaces/empty_table";
import Button from "components/buttons/Button";
// @ts-ignore
@@ -20,6 +21,7 @@ import configAPI from "services/entities/config";
import TableContainer from "components/TableContainer";
import TableDataError from "components/DataError";
+import EmptyTable from "components/EmptyTable";
import CustomLink from "components/CustomLink";
import AddIntegrationModal from "./components/AddIntegrationModal";
@@ -41,7 +43,7 @@ const BAD_REQUEST_ERROR =
const UNKNOWN_ERROR =
"We experienced an error when attempting to connect. Please try again later.";
-const Integrations = () => {
+const Integrations = (): JSX.Element => {
const { renderFlash } = useContext(NotificationContext);
const [showAddIntegrationModal, setShowAddIntegrationModal] = useState(false);
@@ -361,35 +363,33 @@ const Integrations = () => {
}
};
- const NoIntegrationsComponent = () => {
- return (
-
- );
+ const emptyState = () => {
+ const emptyIntegrations: IEmptyTableProps = {
+ iconName: "empty-integrations",
+ header: "Set up integrations",
+ info:
+ "Create tickets automatically when Fleet detects new software vulnerabilities or hosts failing policies.",
+ additionalInfo: (
+ <>
+ Want to learn more?
+
+ ),
+ };
+ return emptyIntegrations;
};
const tableHeaders = generateTableHeaders(onActionSelection);
@@ -399,6 +399,10 @@ const Integrations = () => {
return (
Ticket Destinations
+
+ Add or edit integrations to create tickets when Fleet detects new
+ vulnerabilities.
+
{loadingIntegrationsError ? (
) : (
@@ -413,7 +417,15 @@ const Integrations = () => {
actionButtonVariant={"brand"}
onActionButtonClick={toggleAddIntegrationModal}
resultsTitle={"integrations"}
- emptyComponent={NoIntegrationsComponent}
+ emptyComponent={() =>
+ EmptyTable({
+ iconName: emptyState().iconName,
+ header: emptyState().header,
+ info: emptyState().info,
+ additionalInfo: emptyState().additionalInfo,
+ primaryButton: emptyState().primaryButton,
+ })
+ }
showMarkAllPages={false}
isAllPagesSelected={false}
disablePagination
diff --git a/frontend/pages/admin/IntegrationsPage/cards/Integrations/_styles.scss b/frontend/pages/admin/IntegrationsPage/cards/Integrations/_styles.scss
index e673705c12..7490a34df6 100644
--- a/frontend/pages/admin/IntegrationsPage/cards/Integrations/_styles.scss
+++ b/frontend/pages/admin/IntegrationsPage/cards/Integrations/_styles.scss
@@ -6,7 +6,7 @@
font-size: $medium;
font-weight: $regular;
color: $core-fleet-black;
- border-bottom: solid 1px $ui-fleet-blue-15;
+ border-bottom: solid 1px $ui-fleet-black-10;
margin: 0 0 $pad-xxlarge;
@media (min-width: $break-990) {
@@ -14,6 +14,16 @@
}
}
+ &__page-description {
+ font-size: $x-small;
+ color: $core-fleet-black;
+ width: 100%;
+
+ @media (min-width: $break-990) {
+ width: 60%;
+ }
+ }
+
.table-container {
@media (min-width: $break-990) {
max-width: 65%;
diff --git a/frontend/pages/admin/IntegrationsPage/cards/Mdm/_styles.scss b/frontend/pages/admin/IntegrationsPage/cards/Mdm/_styles.scss
index d634668b68..197a248f73 100644
--- a/frontend/pages/admin/IntegrationsPage/cards/Mdm/_styles.scss
+++ b/frontend/pages/admin/IntegrationsPage/cards/Mdm/_styles.scss
@@ -13,7 +13,7 @@
font-size: $medium;
font-weight: $regular;
color: $core-fleet-black;
- border-bottom: solid 1px $ui-fleet-blue-15;
+ border-bottom: solid 1px $ui-fleet-black-10;
margin: 0 0 $pad-xxlarge;
}
diff --git a/frontend/pages/admin/TeamManagementPage/TeamDetailsWrapper/MembersPage/MembersPage.tsx b/frontend/pages/admin/TeamManagementPage/TeamDetailsWrapper/MembersPage/MembersPage.tsx
index 64529f9c2d..9765445434 100644
--- a/frontend/pages/admin/TeamManagementPage/TeamDetailsWrapper/MembersPage/MembersPage.tsx
+++ b/frontend/pages/admin/TeamManagementPage/TeamDetailsWrapper/MembersPage/MembersPage.tsx
@@ -1,11 +1,13 @@
import React, { useCallback, useContext, useState } from "react";
import { useQuery } from "react-query";
+import { IconNames } from "components/icons";
import { NotificationContext } from "context/notification";
import PATHS from "router/paths";
import { IApiError } from "interfaces/errors";
import { IUser, IUserFormErrors } from "interfaces/user";
import { INewMembersBody, ITeam } from "interfaces/team";
+import { IEmptyTableProps } from "interfaces/empty_table";
import { Link } from "react-router";
import { AppContext } from "context/app";
import usersAPI from "services/entities/users";
@@ -15,6 +17,7 @@ import teamsAPI, { ILoadTeamsResponse } from "services/entities/teams";
import Button from "components/buttons/Button";
import TableContainer from "components/TableContainer";
import TableDataError from "components/DataError";
+import EmptyTable from "components/EmptyTable";
import CreateUserModal from "pages/admin/UserManagementPage/components/CreateUserModal";
import { DEFAULT_CREATE_USER_ERRORS } from "utilities/constants";
import EditUserModal from "../../../UserManagementPage/components/EditUserModal";
@@ -339,51 +342,41 @@ const MembersPage = ({
}
};
- const NoMembersComponent = useCallback(() => {
- return (
-
-
-
- {searchString === "" ? (
- <>
-
This team doesn't have any members yet.
-
- Expecting to see new team members listed here? Try again in a
- few seconds as the system catches up.
-
- {isGlobalAdmin && (
-
- Add member
-
- )}
- {isTeamAdmin && (
-
- Create user
-
- )}
- >
- ) : (
- <>
-
We couldn’t find any members.
-
- Expecting to see members? Try again in a few seconds as the
- system catches up.
-
- >
- )}
-
-
-
- );
- }, [searchString, toggleAddUserModal]);
+ const emptyState = () => {
+ const emptyMembers: IEmptyTableProps = {
+ iconName: "empty-members",
+ header: "This team doesn't have any members yet.",
+ info:
+ "Expecting to see new team members listed here? Try again in a few seconds as the system catches up.",
+ };
+ if (searchString !== "") {
+ delete emptyMembers.iconName;
+ emptyMembers.header = "We couldn’t find any members.";
+ emptyMembers.info =
+ "Expecting to see members? Try again in a few seconds as the system catches up.";
+ } else if (isGlobalAdmin) {
+ emptyMembers.primaryButton = (
+
+ Add member
+
+ );
+ } else if (isTeamAdmin) {
+ emptyMembers.primaryButton = (
+
+ Create user
+
+ );
+ }
+ return emptyMembers;
+ };
const tableHeaders = generateTableHeaders(onActionSelection);
@@ -417,7 +410,14 @@ const MembersPage = ({
hideActionButton={memberIds.length === 0 && searchString === ""}
onQueryChange={({ searchQuery }) => setSearchString(searchQuery)}
inputPlaceHolder={"Search"}
- emptyComponent={NoMembersComponent}
+ emptyComponent={() =>
+ EmptyTable({
+ iconName: emptyState().iconName,
+ header: emptyState().header,
+ info: emptyState().info,
+ primaryButton: emptyState().primaryButton,
+ })
+ }
showMarkAllPages={false}
isAllPagesSelected={false}
searchable={memberIds.length > 0 || searchString !== ""}
diff --git a/frontend/pages/admin/TeamManagementPage/TeamDetailsWrapper/MembersPage/_styles.scss b/frontend/pages/admin/TeamManagementPage/TeamDetailsWrapper/MembersPage/_styles.scss
index 3316cc31c9..96e77ae4f7 100644
--- a/frontend/pages/admin/TeamManagementPage/TeamDetailsWrapper/MembersPage/_styles.scss
+++ b/frontend/pages/admin/TeamManagementPage/TeamDetailsWrapper/MembersPage/_styles.scss
@@ -24,7 +24,7 @@
@media (min-width: $break-1400) {
.role__header {
- border-right: 1px solid $ui-fleet-blue-15;
+ border-right: 1px solid $ui-fleet-black-10;
}
}
}
@@ -45,75 +45,3 @@
}
}
}
-
-.no-members {
- display: flex;
- flex-direction: column;
- align-items: center;
- margin-top: $pad-xxxlarge;
-
- h1 {
- font-size: $large;
- font-weight: $regular;
- line-height: normal;
- letter-spacing: normal;
- color: $core-fleet-black;
- }
-
- h2 {
- font-size: $small;
- font-weight: $bold;
- margin: 0 0 $pad-large;
- line-height: 20px;
- color: $core-fleet-black;
- }
-
- ul {
- margin: 0;
- padding: 0;
- color: $core-fleet-black;
- list-style: none;
-
- li {
- &::before {
- content: "•";
- color: $core-vibrant-blue;
- margin-right: $pad-medium;
- }
- }
- }
-
- &__inner {
- display: flex;
- flex-direction: row;
-
- h1 {
- font-size: $small;
- font-weight: $bold;
- margin-bottom: $pad-medium;
- }
-
- img {
- width: 176px;
- margin-right: $pad-xlarge;
- }
-
- p {
- color: $core-fleet-black;
- font-weight: $regular;
- font-size: $x-small;
- margin: 0;
- margin-bottom: $pad-large;
- }
-
- .no-filter-results {
- display: flex;
- flex-direction: column;
- width: 350px;
- }
- }
-
- &__inner-text {
- width: 350px;
- }
-}
diff --git a/frontend/pages/admin/TeamManagementPage/TeamDetailsWrapper/MembersPage/components/AutocompleteDropdown/_styles.scss b/frontend/pages/admin/TeamManagementPage/TeamDetailsWrapper/MembersPage/components/AutocompleteDropdown/_styles.scss
index 0592741577..762a32ab2e 100644
--- a/frontend/pages/admin/TeamManagementPage/TeamDetailsWrapper/MembersPage/components/AutocompleteDropdown/_styles.scss
+++ b/frontend/pages/admin/TeamManagementPage/TeamDetailsWrapper/MembersPage/components/AutocompleteDropdown/_styles.scss
@@ -1,6 +1,6 @@
.autocomplete-dropdown {
.Select {
- border: solid 1px $ui-fleet-blue-15;
+ border: solid 1px $ui-fleet-black-10;
border-radius: 4px;
&:hover,
diff --git a/frontend/pages/admin/TeamManagementPage/TeamManagementPage.tsx b/frontend/pages/admin/TeamManagementPage/TeamManagementPage.tsx
index bfc6eba35b..90da0f2cad 100644
--- a/frontend/pages/admin/TeamManagementPage/TeamManagementPage.tsx
+++ b/frontend/pages/admin/TeamManagementPage/TeamManagementPage.tsx
@@ -1,4 +1,5 @@
import React, { useState, useCallback, useContext } from "react";
+import { IconNames } from "components/icons";
import { useQuery } from "react-query";
import { useErrorHandler } from "react-error-boundary";
@@ -6,6 +7,7 @@ import { NotificationContext } from "context/notification";
import { AppContext } from "context/app";
import { ITeam } from "interfaces/team";
import { IApiError } from "interfaces/errors";
+import { IEmptyTableProps } from "interfaces/empty_table";
import teamsAPI, {
ILoadTeamsResponse,
ITeamFormData,
@@ -14,6 +16,7 @@ import teamsAPI, {
import Button from "components/buttons/Button";
import TableContainer from "components/TableContainer";
import TableDataError from "components/DataError";
+import EmptyTable from "components/EmptyTable";
import CustomLink from "components/CustomLink";
import CreateTeamModal from "./components/CreateTeamModal";
@@ -197,35 +200,35 @@ const TeamManagementPage = (): JSX.Element => {
}
};
- const NoTeamsComponent = () => {
- return (
-
-
-
-
Set up team permissions
-
- Keep your organization organized and efficient by ensuring every
- user has the correct access to the right hosts.
-
-
- Want to learn more?
-
-
-
- Create team
-
-
-
-
- );
+ const emptyState = () => {
+ const emptyTeams: IEmptyTableProps = {
+ iconName: "empty-teams",
+ header: "Set up team permissions",
+ info:
+ "Keep your organization organized and efficient by ensuring every user has the correct access to the right hosts.",
+ additionalInfo: (
+ <>
+ {" "}
+ Want to learn more?
+
+ >
+ ),
+ primaryButton: (
+
+ Create team
+
+ ),
+ };
+
+ return emptyTeams;
};
const tableHeaders = generateTableHeaders(onActionSelection);
@@ -252,7 +255,15 @@ const TeamManagementPage = (): JSX.Element => {
onActionButtonClick={toggleCreateTeamModal}
onQueryChange={onQueryChange}
resultsTitle={"teams"}
- emptyComponent={NoTeamsComponent}
+ emptyComponent={() =>
+ EmptyTable({
+ iconName: "empty-teams",
+ header: emptyState().header,
+ info: emptyState().info,
+ additionalInfo: emptyState().additionalInfo,
+ primaryButton: emptyState().primaryButton,
+ })
+ }
showMarkAllPages={false}
isAllPagesSelected={false}
searchable={teams && teams.length > 0 && searchString !== ""}
diff --git a/frontend/pages/admin/TeamManagementPage/_styles.scss b/frontend/pages/admin/TeamManagementPage/_styles.scss
index 0fb34c1fa5..f8b12eac5b 100644
--- a/frontend/pages/admin/TeamManagementPage/_styles.scss
+++ b/frontend/pages/admin/TeamManagementPage/_styles.scss
@@ -38,75 +38,3 @@
}
}
}
-
-.no-teams {
- display: flex;
- flex-direction: column;
- align-items: center;
- margin-top: $pad-xxxlarge;
-
- h1 {
- font-size: $large;
- font-weight: $regular;
- line-height: normal;
- letter-spacing: normal;
- color: $core-fleet-black;
- }
-
- h2 {
- font-size: $small;
- font-weight: $bold;
- margin: 0 0 $pad-large;
- line-height: 20px;
- color: $core-fleet-black;
- }
-
- ul {
- margin: 0;
- padding: 0;
- color: $core-fleet-black;
- list-style: none;
-
- li {
- &::before {
- content: "•";
- color: $core-vibrant-blue;
- margin-right: $pad-medium;
- }
- }
- }
-
- &__inner {
- display: flex;
- flex-direction: row;
-
- h1 {
- font-size: $small;
- font-weight: $bold;
- margin-bottom: $pad-medium;
- }
-
- img {
- width: 176px;
- margin-right: $pad-xlarge;
- }
-
- p {
- color: $core-fleet-black;
- font-weight: $regular;
- font-size: $x-small;
- margin: 0;
- margin-bottom: $pad-large;
- }
-
- .no-filter-results {
- display: flex;
- flex-direction: column;
- width: 350px;
- }
- }
-
- &__inner-text {
- width: 350px;
- }
-}
diff --git a/frontend/pages/admin/UserManagementPage/_styles.scss b/frontend/pages/admin/UserManagementPage/_styles.scss
index 46a5063044..b4730838e3 100644
--- a/frontend/pages/admin/UserManagementPage/_styles.scss
+++ b/frontend/pages/admin/UserManagementPage/_styles.scss
@@ -3,6 +3,7 @@
font-size: $x-small;
color: $core-fleet-black;
@include sticky-settings-description;
+ padding-bottom: $pad-medium;
}
&__sandbox-demo-message {
diff --git a/frontend/pages/admin/UserManagementPage/components/EmptyUsers/EmptyUsers.tsx b/frontend/pages/admin/UserManagementPage/components/EmptyUsers/EmptyUsers.tsx
deleted file mode 100644
index 05438cca72..0000000000
--- a/frontend/pages/admin/UserManagementPage/components/EmptyUsers/EmptyUsers.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-/**
- * Component when there is no host results found in a search
- */
-import React from "react";
-
-const baseClass = "empty-users";
-
-const EmptyUsers = (): JSX.Element => {
- return (
-
-
-
-
No users match the current criteria.
-
- Expecting to see users? Try again in a few seconds as the system
- catches up.
-
-
-
-
- );
-};
-
-export default EmptyUsers;
diff --git a/frontend/pages/admin/UserManagementPage/components/EmptyUsers/_styles.scss b/frontend/pages/admin/UserManagementPage/components/EmptyUsers/_styles.scss
deleted file mode 100644
index abf7cc4a31..0000000000
--- a/frontend/pages/admin/UserManagementPage/components/EmptyUsers/_styles.scss
+++ /dev/null
@@ -1,35 +0,0 @@
-.empty-users {
- display: flex;
- flex-direction: column;
- align-items: center;
- margin-top: $pad-xxxlarge;
-
- &__inner {
- display: flex;
- flex-direction: row;
-
- h1 {
- font-size: $small;
- font-weight: $bold;
- margin-bottom: $pad-medium;
- }
-
- img {
- width: 176px;
- margin-right: $pad-xlarge;
- }
-
- p {
- color: $core-fleet-black;
- font-weight: $regular;
- font-size: $x-small;
- margin: 0;
- }
- }
-
- &__empty-filter-results {
- display: flex;
- flex-direction: column;
- width: 350px;
- }
-}
diff --git a/frontend/pages/admin/UserManagementPage/components/EmptyUsers/index.ts b/frontend/pages/admin/UserManagementPage/components/EmptyUsers/index.ts
deleted file mode 100644
index 28df7b7cca..0000000000
--- a/frontend/pages/admin/UserManagementPage/components/EmptyUsers/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from "./EmptyUsers";
diff --git a/frontend/pages/admin/UserManagementPage/components/SelectedTeamsForm/_styles.scss b/frontend/pages/admin/UserManagementPage/components/SelectedTeamsForm/_styles.scss
index 9c99fe8ecf..0ce4d44c04 100644
--- a/frontend/pages/admin/UserManagementPage/components/SelectedTeamsForm/_styles.scss
+++ b/frontend/pages/admin/UserManagementPage/components/SelectedTeamsForm/_styles.scss
@@ -1,5 +1,5 @@
.selected-teams-form {
- border: 1px solid $ui-fleet-blue-15;
+ border: 1px solid $ui-fleet-black-10;
border-radius: $border-radius;
background-color: $ui-off-white;
padding: $pad-medium;
diff --git a/frontend/pages/admin/UserManagementPage/components/UsersTable/UsersTable.tsx b/frontend/pages/admin/UserManagementPage/components/UsersTable/UsersTable.tsx
index c294b0fc4a..374931eee6 100644
--- a/frontend/pages/admin/UserManagementPage/components/UsersTable/UsersTable.tsx
+++ b/frontend/pages/admin/UserManagementPage/components/UsersTable/UsersTable.tsx
@@ -16,11 +16,11 @@ import teamsAPI, { ILoadTeamsResponse } from "services/entities/teams";
import usersAPI from "services/entities/users";
import invitesAPI from "services/entities/invites";
+import { DEFAULT_CREATE_USER_ERRORS } from "utilities/constants";
import TableContainer, { ITableQueryData } from "components/TableContainer";
import TableDataError from "components/DataError";
import Modal from "components/Modal";
-import { DEFAULT_CREATE_USER_ERRORS } from "utilities/constants";
-import EmptyUsers from "../EmptyUsers";
+import EmptyTable from "components/EmptyTable";
import { generateTableHeaders, combineDataSets } from "./UsersTableConfig";
import DeleteUserModal from "../DeleteUserModal";
import ResetPasswordModal from "../ResetPasswordModal";
@@ -520,6 +520,12 @@ const UsersTable = ({ router }: IUsersTableProps): JSX.Element => {
tableData = combineUsersAndInvites(users, invites, currentUser?.id);
}
+ const emptyState = {
+ header: "No users match the current criteria.",
+ info:
+ "Expecting to see users? Try again in a few seconds as the system catches up.",
+ };
+
return (
<>
{/* TODO: find a way to move these controls into the table component */}
@@ -537,7 +543,7 @@ const UsersTable = ({ router }: IUsersTableProps): JSX.Element => {
onActionButtonClick={toggleCreateUserModal}
onQueryChange={onTableQueryChange}
resultsTitle={"users"}
- emptyComponent={EmptyUsers}
+ emptyComponent={() => EmptyTable(emptyState)}
searchable
showMarkAllPages={false}
isAllPagesSelected={false}
diff --git a/frontend/pages/hosts/ManageHostsPage/HostTableConfig.tsx b/frontend/pages/hosts/ManageHostsPage/HostTableConfig.tsx
index 5f41c73180..5dd007e54f 100644
--- a/frontend/pages/hosts/ManageHostsPage/HostTableConfig.tsx
+++ b/frontend/pages/hosts/ManageHostsPage/HostTableConfig.tsx
@@ -14,11 +14,11 @@ import LinkCell from "components/TableContainer/DataTable/LinkCell/LinkCell";
import StatusIndicator from "components/StatusIndicator";
import TextCell from "components/TableContainer/DataTable/TextCell/TextCell";
import TooltipWrapper from "components/TooltipWrapper";
+import HumanTimeDiffWithDateTip from "components/HumanTimeDiffWithDateTip";
import {
humanHostMemory,
humanHostLastRestart,
humanHostLastSeen,
- humanHostDetailUpdated,
hostTeamName,
} from "utilities/helpers";
import { IConfig } from "interfaces/config";
@@ -361,8 +361,8 @@ const allHostTableHeaders: IDataColumn[] = [
accessor: "detail_updated_at",
Cell: (cellProps: ICellProps) => (
),
},
@@ -387,7 +387,10 @@ const allHostTableHeaders: IDataColumn[] = [
},
accessor: "seen_time",
Cell: (cellProps: ICellProps) => (
-
+
),
},
{
@@ -414,7 +417,12 @@ const allHostTableHeaders: IDataColumn[] = [
const { uptime, detail_updated_at } = cellProps.row.original;
return (
-
+
);
},
},
diff --git a/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx b/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx
index e9942c9a7d..c6dab52701 100644
--- a/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx
+++ b/frontend/pages/hosts/ManageHostsPage/ManageHostsPage.tsx
@@ -1,4 +1,5 @@
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";
@@ -42,6 +43,8 @@ import {
import { IPolicy, IStoredPolicyResponse } from "interfaces/policy";
import { ISoftware } from "interfaces/software";
import { ITeam } from "interfaces/team";
+import { IEmptyTableProps } from "interfaces/empty_table";
+
import sortUtils from "utilities/sort";
import {
HOSTS_SEARCH_BOX_PLACEHOLDER,
@@ -59,6 +62,7 @@ import { IActionButtonProps } from "components/TableContainer/DataTable/ActionBu
import TeamsDropdown from "components/TeamsDropdown";
import Spinner from "components/Spinner";
import MainContent from "components/MainContent";
+import EmptyTable from "components/EmptyTable";
import { getValidatedTeamId } from "utilities/helpers";
import {
@@ -78,8 +82,6 @@ import DeleteSecretModal from "../../../components/EnrollSecrets/DeleteSecretMod
import SecretEditorModal from "../../../components/EnrollSecrets/SecretEditorModal";
import AddHostsModal from "../../../components/AddHostsModal";
import EnrollSecretModal from "../../../components/EnrollSecrets/EnrollSecretModal";
-import NoHosts from "./components/NoHosts";
-import EmptyHosts from "./components/EmptyHosts";
import PoliciesFilter from "./components/PoliciesFilter";
// @ts-ignore
import EditColumnsModal from "./components/EditColumnsModal/EditColumnsModal";
@@ -1679,12 +1681,41 @@ const ManageHostsPage = ({
osVersion
);
+ const emptyState = () => {
+ const emptyHosts: IEmptyTableProps = {
+ iconName: "empty-hosts",
+ header: "Devices will show up here once they’re added to Fleet.",
+ info:
+ "Expecting to see devices? Try again in a few seconds as the system catches up.",
+ };
+ if (includesNameCardFilter) {
+ delete emptyHosts.iconName;
+ emptyHosts.header = "No hosts match the current criteria";
+ emptyHosts.info =
+ "Expecting to see new hosts? Try again in a few seconds as the system catches up.";
+ }
+ if (canEnrollHosts) {
+ emptyHosts.header = "Add your devices to Fleet";
+ emptyHosts.info = "Generate an installer to add your own devices.";
+ emptyHosts.primaryButton = (
+
+ Add hosts
+
+ );
+ }
+ return emptyHosts;
+ };
+
return (
-
+ <>
+ {EmptyTable({
+ iconName: emptyState().iconName,
+ header: emptyState().header,
+ info: emptyState().info,
+ additionalInfo: emptyState().additionalInfo,
+ primaryButton: emptyState().primaryButton,
+ })}
+ >
);
}
@@ -1706,6 +1737,21 @@ const ManageHostsPage = ({
currentTeam
);
+ const emptyState = () => {
+ const emptyHosts: IEmptyTableProps = {
+ header: "No hosts match the current criteria",
+ info:
+ "Expecting to see new hosts? Try again in a few seconds as the system catches up.",
+ };
+ if (isLastPage) {
+ emptyHosts.header = "No more hosts to display";
+ emptyHosts.info =
+ "Expecting to see more hosts? Try again in a few seconds as the system catches up.";
+ }
+
+ return emptyHosts;
+ };
+
return (
+ EmptyTable({
+ header: emptyState().header,
+ info: emptyState().info,
+ })
+ }
customControl={renderCustomControls}
onActionButtonClick={toggleEditColumnsModal}
onPrimarySelectActionClick={onDeleteHostsClick}
diff --git a/frontend/pages/hosts/ManageHostsPage/components/CustomLabelGroupHeading/_styles.scss b/frontend/pages/hosts/ManageHostsPage/components/CustomLabelGroupHeading/_styles.scss
index f39bfe91b3..0fa641a929 100644
--- a/frontend/pages/hosts/ManageHostsPage/components/CustomLabelGroupHeading/_styles.scss
+++ b/frontend/pages/hosts/ManageHostsPage/components/CustomLabelGroupHeading/_styles.scss
@@ -37,7 +37,7 @@
width: 100%;
line-height: 1.5;
background-color: $ui-light-grey;
- border: solid 1px $ui-fleet-blue-15;
+ border: solid 1px $ui-fleet-black-10;
border-radius: 4px;
font-size: $small;
padding: $pad-xsmall 12px $pad-xsmall 42px;
diff --git a/frontend/pages/hosts/ManageHostsPage/components/EmptyHosts/EmptyHosts.tsx b/frontend/pages/hosts/ManageHostsPage/components/EmptyHosts/EmptyHosts.tsx
deleted file mode 100644
index 5cecc1a3b9..0000000000
--- a/frontend/pages/hosts/ManageHostsPage/components/EmptyHosts/EmptyHosts.tsx
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * Component when there is no host results found in a search
- */
-import React from "react";
-
-const baseClass = "empty-hosts";
-
-interface IEmptyHostsProps {
- pageIndex: number;
-}
-
-const EmptyHosts = ({ pageIndex }: IEmptyHostsProps): JSX.Element => {
- return (
-
-
-
-
- {pageIndex !== 0
- ? "No more hosts to display"
- : "No hosts match the current criteria"}
-
-
- Expecting to see {pageIndex !== 0 ? "more" : "new"} hosts? Try again
- in a few seconds as the system catches up
-
-
-
-
- );
-};
-
-export default EmptyHosts;
diff --git a/frontend/pages/hosts/ManageHostsPage/components/EmptyHosts/_styles.scss b/frontend/pages/hosts/ManageHostsPage/components/EmptyHosts/_styles.scss
deleted file mode 100644
index a533a1b8f9..0000000000
--- a/frontend/pages/hosts/ManageHostsPage/components/EmptyHosts/_styles.scss
+++ /dev/null
@@ -1,35 +0,0 @@
-.empty-hosts {
- display: flex;
- flex-direction: column;
- align-items: center;
- margin-top: $pad-xxxlarge;
-
- &__inner {
- display: flex;
- flex-direction: row;
-
- h1 {
- font-size: $small;
- font-weight: $bold;
- margin-bottom: $pad-medium;
- }
-
- img {
- width: 176px;
- margin-right: $pad-xlarge;
- }
-
- p {
- color: $core-fleet-black;
- font-weight: $regular;
- font-size: $x-small;
- margin: 0;
- }
- }
-
- &__empty-filter-results {
- display: flex;
- flex-direction: column;
- width: 350px;
- }
-}
diff --git a/frontend/pages/hosts/ManageHostsPage/components/EmptyHosts/index.ts b/frontend/pages/hosts/ManageHostsPage/components/EmptyHosts/index.ts
deleted file mode 100644
index 5bbf093b04..0000000000
--- a/frontend/pages/hosts/ManageHostsPage/components/EmptyHosts/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from "./EmptyHosts";
diff --git a/frontend/pages/hosts/ManageHostsPage/components/LabelFilterSelect/_styles.scss b/frontend/pages/hosts/ManageHostsPage/components/LabelFilterSelect/_styles.scss
index 5c64c67658..16d3de610f 100644
--- a/frontend/pages/hosts/ManageHostsPage/components/LabelFilterSelect/_styles.scss
+++ b/frontend/pages/hosts/ManageHostsPage/components/LabelFilterSelect/_styles.scss
@@ -11,7 +11,7 @@
}
.label-filter-select__control {
- border: 1px solid $ui-fleet-blue-15;
+ border: 1px solid $ui-fleet-black-10;
background-color: $ui-light-grey;
border-radius: $border-radius;
height: 40px;
@@ -67,6 +67,7 @@
width: 300px;
margin-top: 0;
z-index: 2;
+ animation: fade-in 150ms ease-out;
}
.label-filter-select__menu-list {
diff --git a/frontend/pages/hosts/ManageHostsPage/components/NoHosts/NoHosts.tsx b/frontend/pages/hosts/ManageHostsPage/components/NoHosts/NoHosts.tsx
deleted file mode 100644
index 690f7fc457..0000000000
--- a/frontend/pages/hosts/ManageHostsPage/components/NoHosts/NoHosts.tsx
+++ /dev/null
@@ -1,70 +0,0 @@
-/**
- * Component when there is no hosts set up in fleet
- */
-import React from "react";
-import Button from "components/buttons/Button";
-
-import RoboDogImage from "../../../../../../assets/images/robo-dog-176x144@2x.png";
-
-interface INoHostsProps {
- toggleAddHostsModal: () => void;
- canEnrollHosts?: boolean;
- includesNameCardFilter?: boolean;
-}
-
-const baseClass = "no-hosts";
-
-const NoHosts = ({
- toggleAddHostsModal,
- canEnrollHosts,
- includesNameCardFilter,
-}: INoHostsProps): JSX.Element => {
- const renderContent = () => {
- if (includesNameCardFilter) {
- return (
-
-
No hosts match the current criteria
-
- Expecting to see new hosts? Try again in a few seconds as the system
- catches up.
-
-
- );
- }
-
- if (canEnrollHosts) {
- return (
-
-
Add your devices to Fleet
-
Generate an installer to add your own devices.
-
-
- Add hosts
-
-
-
- );
- }
-
- return (
-
-
Devices will show up here once they’re added to Fleet.
-
- Expecting to see devices? Try again in a few seconds as the system
- catches up.
-
-
- );
- };
-
- return (
-
-
- {!includesNameCardFilter &&
}
- {renderContent()}
-
-
- );
-};
-
-export default NoHosts;
diff --git a/frontend/pages/hosts/ManageHostsPage/components/NoHosts/_styles.scss b/frontend/pages/hosts/ManageHostsPage/components/NoHosts/_styles.scss
deleted file mode 100644
index 332f763b91..0000000000
--- a/frontend/pages/hosts/ManageHostsPage/components/NoHosts/_styles.scss
+++ /dev/null
@@ -1,79 +0,0 @@
-.no-hosts {
- display: flex;
- flex-direction: column;
- align-items: center;
- margin-top: $pad-xxxlarge;
-
- h1 {
- font-size: $large;
- font-weight: $regular;
- line-height: normal;
- letter-spacing: normal;
- color: $core-fleet-black;
- }
-
- h2 {
- font-size: $x-small;
- font-weight: $bold;
- margin: 0 0 $pad-large;
- line-height: 20px;
- color: $core-fleet-black;
- }
-
- ul {
- margin: 0;
- padding: 0;
- color: $core-fleet-black;
- list-style: none;
-
- li {
- &::before {
- content: "•";
- color: $core-vibrant-blue;
- margin-right: $pad-medium;
- }
- }
- }
-
- p {
- color: $core-fleet-black;
- font-weight: $regular;
- font-size: $x-small;
- margin: 0;
- }
-
- &__inner {
- display: flex;
- flex-direction: row;
-
- h1 {
- font-size: $small;
- font-weight: $bold;
- margin-bottom: $pad-medium;
- }
-
- img {
- width: 176px;
- margin-right: $pad-xlarge;
- }
-
- .no-filter-results {
- display: flex;
- flex-direction: column;
- width: 350px;
- }
- }
-
- .host-pagination__pager-wrap {
- margin-top: $pad-medium;
- }
-
- &__no-hosts-contact {
- text-align: left;
- margin-top: $pad-large;
- }
-
- &__no-hosts-button {
- margin-top: $pad-large;
- }
-}
diff --git a/frontend/pages/hosts/ManageHostsPage/components/NoHosts/index.ts b/frontend/pages/hosts/ManageHostsPage/components/NoHosts/index.ts
deleted file mode 100644
index a02c59638c..0000000000
--- a/frontend/pages/hosts/ManageHostsPage/components/NoHosts/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from "./NoHosts";
diff --git a/frontend/pages/hosts/details/DeviceUserPage/_styles.scss b/frontend/pages/hosts/details/DeviceUserPage/_styles.scss
index db025dc4e9..9a6c524f49 100644
--- a/frontend/pages/hosts/details/DeviceUserPage/_styles.scss
+++ b/frontend/pages/hosts/details/DeviceUserPage/_styles.scss
@@ -30,7 +30,7 @@
flex-direction: column;
background-color: $core-white;
border-radius: 16px;
- border: 1px solid $ui-fleet-blue-15;
+ border: 1px solid $ui-fleet-black-10;
padding: $pad-xxlarge;
box-shadow: 0px 3px 0px rgba(226, 228, 234, 0.4);
@@ -335,7 +335,7 @@
}
&__wrapper {
- border: solid 1px $ui-fleet-blue-15;
+ border: solid 1px $ui-fleet-black-10;
border-radius: 6px;
margin-top: $pad-small;
overflow: scroll;
diff --git a/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx b/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx
index b9932e3086..ddf55c0d61 100644
--- a/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx
+++ b/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx
@@ -682,9 +682,7 @@ const HostDetailsPage = ({
diff --git a/frontend/pages/hosts/details/HostDetailsPage/_styles.scss b/frontend/pages/hosts/details/HostDetailsPage/_styles.scss
index d66102c79f..4e1831ecf9 100644
--- a/frontend/pages/hosts/details/HostDetailsPage/_styles.scss
+++ b/frontend/pages/hosts/details/HostDetailsPage/_styles.scss
@@ -18,7 +18,7 @@
flex-direction: column;
background-color: $core-white;
border-radius: 16px;
- border: 1px solid $ui-fleet-blue-15;
+ border: 1px solid $ui-fleet-black-10;
padding: $pad-xxlarge;
box-shadow: 0px 3px 0px rgba(226, 228, 234, 0.4);
diff --git a/frontend/pages/hosts/details/cards/About/About.tsx b/frontend/pages/hosts/details/cards/About/About.tsx
index 13c5a496d4..5d2884823d 100644
--- a/frontend/pages/hosts/details/cards/About/About.tsx
+++ b/frontend/pages/hosts/details/cards/About/About.tsx
@@ -1,9 +1,10 @@
import React from "react";
import ReactTooltip from "react-tooltip";
+import HumanTimeDiffWithDateTip from "components/HumanTimeDiffWithDateTip";
import { IHostMdmData, IMunkiData, IDeviceUser } from "interfaces/host";
-import { humanHostLastRestart, humanHostEnrolled } from "utilities/helpers";
+import { humanHostLastRestart } from "utilities/helpers";
interface IAboutProps {
aboutData: { [key: string]: any };
@@ -18,7 +19,6 @@ const About = ({
deviceMapping,
munki,
mdm,
- wrapFleetHelper,
}: IAboutProps): JSX.Element => {
const renderSerialAndIPs = () => {
return (
@@ -143,7 +143,6 @@ const About = ({
);
@@ -194,7 +200,16 @@ const ScheduleTable = ({
primarySelectActionButtonVariant="text-icon"
primarySelectActionButtonIcon="remove"
primarySelectActionButtonText={"Remove"}
- emptyComponent={NoScheduledQueries}
+ emptyComponent={() =>
+ EmptyTable({
+ iconName: emptyState().iconName,
+ header: emptyState().header,
+ info: emptyState().info,
+ additionalInfo: emptyState().additionalInfo,
+ primaryButton: emptyState().primaryButton,
+ secondaryButton: emptyState().secondaryButton,
+ })
+ }
isClientSidePagination
/>