From 7f6a42e4ac2d1f2d2fb6492ec6d9b8bf2dbd953a Mon Sep 17 00:00:00 2001 From: RachelElysia <71795832+RachelElysia@users.noreply.github.com> Date: Tue, 21 Feb 2023 09:16:38 -0500 Subject: [PATCH] Fleet UI: Undetermined public ip tooltip (#9907) --- changes/9857-fix-public-ip-and-add-docs | 3 +- frontend/components/CustomLink/CustomLink.tsx | 9 ++-- .../AppleBMTermsMessage.tsx | 2 +- .../StatusIndicator/StatusIndicator.tsx | 3 +- .../DataTable/PillCell/PillCell.tsx | 3 +- .../PlatformCell/PlatformCell.tests.tsx | 3 +- .../QuerySidePanel/QuerySidePanel.tsx | 2 +- .../UsersTable/UsersTableConfig.tsx | 5 +- .../hosts/ManageHostsPage/HostTableConfig.tsx | 37 ++++++++++++- .../pages/hosts/ManageHostsPage/_styles.scss | 3 +- .../pages/hosts/details/cards/About/About.tsx | 54 +++++++++++++++++-- .../details/cards/HostSummary/HostSummary.tsx | 5 +- .../ManageQueriesPage/ManageQueriesPage.tsx | 3 +- .../SoftwareDetailsPage.tsx | 5 +- frontend/styles/global/_global.scss | 6 +++ frontend/utilities/helpers.ts | 7 +-- 16 files changed, 124 insertions(+), 26 deletions(-) diff --git a/changes/9857-fix-public-ip-and-add-docs b/changes/9857-fix-public-ip-and-add-docs index 787f821d32..6ebcd9e61b 100644 --- a/changes/9857-fix-public-ip-and-add-docs +++ b/changes/9857-fix-public-ip-and-add-docs @@ -1 +1,2 @@ -* Only set public IPs on the `host.public_ip` field and add documentation on how to properly configure the deployment to ingest correct public IPs from enrolled devices. +- Only set public IPs on the `host.public_ip` field and add documentation on how to properly configure the deployment to ingest correct public IPs from enrolled devices. +- Add tooltip with link to UI when Public IP address cannot be determined diff --git a/frontend/components/CustomLink/CustomLink.tsx b/frontend/components/CustomLink/CustomLink.tsx index b6857528ac..a17d3db161 100644 --- a/frontend/components/CustomLink/CustomLink.tsx +++ b/frontend/components/CustomLink/CustomLink.tsx @@ -2,6 +2,7 @@ import React from "react"; import Icon from "components/Icon"; import classnames from "classnames"; +import { Colors } from "styles/var/colors"; interface ICustomLinkProps { url: string; @@ -10,7 +11,7 @@ interface ICustomLinkProps { newTab?: boolean; /** Icon wraps on new line with last word */ multiline?: boolean; - black?: boolean; + iconColor?: Colors; } const baseClass = "custom-link"; @@ -21,7 +22,7 @@ const CustomLink = ({ className, newTab = false, multiline = false, - black = false, + iconColor = "core-fleet-blue", }: ICustomLinkProps): JSX.Element => { const customLinkClass = classnames(baseClass, className); @@ -39,7 +40,7 @@ const CustomLink = ({ )} @@ -51,7 +52,7 @@ const CustomLink = ({ )} diff --git a/frontend/components/MDM/AppleBMTermsMessage/AppleBMTermsMessage.tsx b/frontend/components/MDM/AppleBMTermsMessage/AppleBMTermsMessage.tsx index f7d53dbb92..c65a6da595 100644 --- a/frontend/components/MDM/AppleBMTermsMessage/AppleBMTermsMessage.tsx +++ b/frontend/components/MDM/AppleBMTermsMessage/AppleBMTermsMessage.tsx @@ -28,7 +28,7 @@ const AppleBMTermsMessage = () => { text="Go to ABM" className={`${baseClass}__new-tab`} newTab - black + iconColor="core-fleet-black" /> ); diff --git a/frontend/components/StatusIndicator/StatusIndicator.tsx b/frontend/components/StatusIndicator/StatusIndicator.tsx index d71c32a0cd..81e4b2c3b9 100644 --- a/frontend/components/StatusIndicator/StatusIndicator.tsx +++ b/frontend/components/StatusIndicator/StatusIndicator.tsx @@ -1,6 +1,7 @@ import React from "react"; import classnames from "classnames"; import ReactTooltip from "react-tooltip"; +import { DEFAULT_EMPTY_CELL_VALUE } from "utilities/constants"; interface IStatusIndicatorProps { value: string; @@ -11,7 +12,7 @@ interface IStatusIndicatorProps { } const generateClassTag = (rawValue: string): string => { - if (rawValue === "---") { + if (rawValue === DEFAULT_EMPTY_CELL_VALUE) { return "indeterminate"; } return rawValue.replace(" ", "-").toLowerCase(); diff --git a/frontend/components/TableContainer/DataTable/PillCell/PillCell.tsx b/frontend/components/TableContainer/DataTable/PillCell/PillCell.tsx index 727fa70637..528858b357 100644 --- a/frontend/components/TableContainer/DataTable/PillCell/PillCell.tsx +++ b/frontend/components/TableContainer/DataTable/PillCell/PillCell.tsx @@ -96,8 +96,7 @@ const PillCell = ({ {indicator} { render(); const icons = screen.queryAllByTestId("icon"); - const emptyText = screen.queryByText("---"); + const emptyText = screen.queryByText(DEFAULT_EMPTY_CELL_VALUE); expect(icons).toHaveLength(0); expect(emptyText).toBeInTheDocument(); diff --git a/frontend/components/side_panels/QuerySidePanel/QuerySidePanel.tsx b/frontend/components/side_panels/QuerySidePanel/QuerySidePanel.tsx index df65b9dd3c..60b31ba85d 100644 --- a/frontend/components/side_panels/QuerySidePanel/QuerySidePanel.tsx +++ b/frontend/components/side_panels/QuerySidePanel/QuerySidePanel.tsx @@ -6,6 +6,7 @@ import { osqueryTableNames } from "utilities/osquery_tables"; // @ts-ignore import Dropdown from "components/forms/fields/Dropdown"; import FleetMarkdown from "components/FleetMarkdown"; +import CustomLink from "components/CustomLink"; import QueryTableColumns from "./QueryTableColumns"; import QueryTablePlatforms from "./QueryTablePlatforms"; @@ -15,7 +16,6 @@ import CloseIcon from "../../../../assets/images/icon-close-black-50-8x8@2x.png" import QueryTableExample from "./QueryTableExample"; import QueryTableNotes from "./QueryTableNotes"; import EventedTableTag from "./EventedTableTag"; -import CustomLink from "components/CustomLink"; interface IQuerySidePanel { selectedOsqueryTable: IOsQueryTable; diff --git a/frontend/pages/admin/UserManagementPage/components/UsersTable/UsersTableConfig.tsx b/frontend/pages/admin/UserManagementPage/components/UsersTable/UsersTableConfig.tsx index ca6603f528..8c2b52f445 100644 --- a/frontend/pages/admin/UserManagementPage/components/UsersTable/UsersTableConfig.tsx +++ b/frontend/pages/admin/UserManagementPage/components/UsersTable/UsersTableConfig.tsx @@ -7,6 +7,7 @@ import { IInvite } from "interfaces/invite"; import { IUser } from "interfaces/user"; import { IDropdownOption } from "interfaces/dropdownOption"; import { generateRole, generateTeam, greyCell } from "utilities/helpers"; +import { DEFAULT_EMPTY_CELL_VALUE } from "utilities/constants"; import DropdownCell from "../../../../../components/TableContainer/DataTable/DropdownCell"; interface IHeaderProps { @@ -193,7 +194,7 @@ const enhanceUserData = ( ): IUserTableData[] => { return users.map((user) => { return { - name: user.name || "---", + name: user.name || DEFAULT_EMPTY_CELL_VALUE, status: generateStatus("user", user), email: user.email, teams: generateTeam(user.teams, user.global_role), @@ -212,7 +213,7 @@ const enhanceUserData = ( const enhanceInviteData = (invites: IInvite[]): IUserTableData[] => { return invites.map((invite) => { return { - name: invite.name || "---", + name: invite.name || DEFAULT_EMPTY_CELL_VALUE, status: generateStatus("invite", invite), email: invite.email, teams: generateTeam(invite.teams, invite.global_role), diff --git a/frontend/pages/hosts/ManageHostsPage/HostTableConfig.tsx b/frontend/pages/hosts/ManageHostsPage/HostTableConfig.tsx index 8c8df11d97..1a81e564d1 100644 --- a/frontend/pages/hosts/ManageHostsPage/HostTableConfig.tsx +++ b/frontend/pages/hosts/ManageHostsPage/HostTableConfig.tsx @@ -16,6 +16,7 @@ import TextCell from "components/TableContainer/DataTable/TextCell/TextCell"; import TruncatedTextCell from "components/TableContainer/DataTable/TruncatedTextCell"; import TooltipWrapper from "components/TooltipWrapper"; import HumanTimeDiffWithDateTip from "components/HumanTimeDiffWithDateTip"; +import CustomLink from "components/CustomLink"; import { humanHostMemory, humanHostLastRestart, @@ -28,6 +29,7 @@ import { ITeamSummary } from "interfaces/team"; import { IUser } from "interfaces/user"; import PATHS from "router/paths"; import permissionUtils from "utilities/permissions"; +import { DEFAULT_EMPTY_CELL_VALUE } from "utilities/constants"; import getHostStatusTooltipText from "../helpers"; interface IGetToggleAllRowsSelectedProps { @@ -424,7 +426,40 @@ const allHostTableHeaders: IDataColumn[] = [ /> ), accessor: "public_ip", - Cell: (cellProps: ICellProps) => , + Cell: (cellProps: ICellProps) => { + if (cellProps.cell.value) { + return ; + } + return ( + <> + + {DEFAULT_EMPTY_CELL_VALUE} + + + Public IP address could not be +
determined.{" "} + +
+ + ); + }, }, { title: "Last fetched", diff --git a/frontend/pages/hosts/ManageHostsPage/_styles.scss b/frontend/pages/hosts/ManageHostsPage/_styles.scss index cf891645b7..cfb3746c25 100644 --- a/frontend/pages/hosts/ManageHostsPage/_styles.scss +++ b/frontend/pages/hosts/ManageHostsPage/_styles.scss @@ -193,7 +193,8 @@ .device_mapping__cell, .mdm_enrollment_status__cell, - .mdm_server_url__cell { + .mdm_server_url__cell, + .public_ip__cell { .text-cell { display: inline; } diff --git a/frontend/pages/hosts/details/cards/About/About.tsx b/frontend/pages/hosts/details/cards/About/About.tsx index 6bc64cf9f2..091999ab9b 100644 --- a/frontend/pages/hosts/details/cards/About/About.tsx +++ b/frontend/pages/hosts/details/cards/About/About.tsx @@ -3,9 +3,14 @@ import React from "react"; import ReactTooltip from "react-tooltip"; import HumanTimeDiffWithDateTip from "components/HumanTimeDiffWithDateTip"; import TooltipWrapper from "components/TooltipWrapper"; +import CustomLink from "components/CustomLink"; + import { IHostMdmData, IMunkiData, IDeviceUser } from "interfaces/host"; import { humanHostLastRestart } from "utilities/helpers"; -import { MDM_STATUS_TOOLTIP } from "utilities/constants"; +import { + DEFAULT_EMPTY_CELL_VALUE, + MDM_STATUS_TOOLTIP, +} from "utilities/constants"; interface IAboutProps { aboutData: { [key: string]: any }; @@ -21,6 +26,41 @@ const About = ({ munki, mdm, }: IAboutProps): JSX.Element => { + const renderPublicIp = () => { + if (aboutData.public_ip !== DEFAULT_EMPTY_CELL_VALUE) { + return aboutData.public_ip; + } + return ( + <> + + {aboutData.public_ip} + + + Public IP address could not be +
determined.{" "} + +
+ + ); + }; + const renderSerialAndIPs = () => { return ( <> @@ -34,7 +74,7 @@ const About = ({
Public IP address - {aboutData.public_ip} + {renderPublicIp()}
); @@ -45,7 +85,9 @@ const About = ({ <>
Munki version - {munki.version || "---"} + + {munki.version || DEFAULT_EMPTY_CELL_VALUE} +
) : null; @@ -70,7 +112,9 @@ const About = ({
MDM server URL - {mdm.server_url || "---"} + + {mdm.server_url || DEFAULT_EMPTY_CELL_VALUE} +
); @@ -108,7 +152,7 @@ const About = ({
) : ( - deviceMapping[0].email || "---" + deviceMapping[0].email || DEFAULT_EMPTY_CELL_VALUE )} diff --git a/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx b/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx index d0fc99c864..07ad382220 100644 --- a/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx +++ b/frontend/pages/hosts/details/cards/HostSummary/HostSummary.tsx @@ -7,6 +7,7 @@ import Button from "components/buttons/Button"; import DiskSpaceGraph from "components/DiskSpaceGraph"; import HumanTimeDiffWithDateTip from "components/HumanTimeDiffWithDateTip"; import { humanHostMemory, wrapFleetHelper } from "utilities/helpers"; +import { DEFAULT_EMPTY_CELL_VALUE } from "utilities/constants"; import getHostStatusTooltipText from "pages/hosts/helpers"; import StatusIndicator from "components/StatusIndicator"; import IssueIcon from "../../../../../../assets/images/icon-issue-fleet-black-50-16x16@2x.png"; @@ -212,7 +213,9 @@ const HostSummary = ({

- {deviceUser ? "My device" : titleData.display_name || "---"} + {deviceUser + ? "My device" + : titleData.display_name || DEFAULT_EMPTY_CELL_VALUE}

diff --git a/frontend/pages/queries/ManageQueriesPage/ManageQueriesPage.tsx b/frontend/pages/queries/ManageQueriesPage/ManageQueriesPage.tsx index f6b95e8733..a48818abb7 100644 --- a/frontend/pages/queries/ManageQueriesPage/ManageQueriesPage.tsx +++ b/frontend/pages/queries/ManageQueriesPage/ManageQueriesPage.tsx @@ -17,6 +17,7 @@ import { IOsqueryPlatform } from "interfaces/platform"; import { IQuery, IFleetQueriesResponse } from "interfaces/query"; import fleetQueriesAPI from "services/entities/queries"; import PATHS from "router/paths"; +import { DEFAULT_EMPTY_CELL_VALUE } from "utilities/constants"; import checkPlatformCompatibility from "utilities/sql_tools"; import Button from "components/buttons/Button"; // @ts-ignore @@ -67,7 +68,7 @@ const PLATFORM_FILTER_OPTIONS = [ const getPlatforms = (queryString: string): Array => { const { platforms } = checkPlatformCompatibility(queryString); - return platforms || ["---"]; + return platforms || [DEFAULT_EMPTY_CELL_VALUE]; }; const enhanceQuery = (q: IQuery) => { diff --git a/frontend/pages/software/SoftwareDetailsPage/SoftwareDetailsPage.tsx b/frontend/pages/software/SoftwareDetailsPage/SoftwareDetailsPage.tsx index 0b00f6141b..01531b5863 100644 --- a/frontend/pages/software/SoftwareDetailsPage/SoftwareDetailsPage.tsx +++ b/frontend/pages/software/SoftwareDetailsPage/SoftwareDetailsPage.tsx @@ -12,6 +12,7 @@ import { import softwareAPI from "services/entities/software"; import hostCountAPI from "services/entities/host_count"; +import { DEFAULT_EMPTY_CELL_VALUE } from "utilities/constants"; import Spinner from "components/Spinner"; import BackLink from "components/BackLink"; import MainContent from "components/MainContent"; @@ -96,7 +97,9 @@ const SoftwareDetailsPage = ({

Hosts - {hostCount || "---"} + + {hostCount || DEFAULT_EMPTY_CELL_VALUE} +
diff --git a/frontend/styles/global/_global.scss b/frontend/styles/global/_global.scss index 0c900164ac..371500580d 100644 --- a/frontend/styles/global/_global.scss +++ b/frontend/styles/global/_global.scss @@ -47,6 +47,12 @@ a { text-decoration: none; } +.__react_component_tooltip { + a { + color: $core-white; + } +} + .body-wrap { padding: $pad-xlarge; border-radius: 3px; diff --git a/frontend/utilities/helpers.ts b/frontend/utilities/helpers.ts index 6c7a976a58..0e4af7537f 100644 --- a/frontend/utilities/helpers.ts +++ b/frontend/utilities/helpers.ts @@ -38,6 +38,7 @@ import { IUser } from "interfaces/user"; import stringUtils from "utilities/strings"; import sortUtils from "utilities/sort"; import { + DEFAULT_EMPTY_CELL_VALUE, DEFAULT_GRAVATAR_LINK, DEFAULT_GRAVATAR_LINK_DARK, PLATFORM_LABEL_DISPLAY_TYPES, @@ -575,7 +576,7 @@ export const humanHostLastRestart = ( if ( !detailUpdatedAt || !uptime || - detailUpdatedAt === "---" || + detailUpdatedAt === DEFAULT_EMPTY_CELL_VALUE || detailUpdatedAt < "2016-07-28T00:00:00Z" || typeof uptime !== "number" ) { @@ -825,7 +826,7 @@ export const normalizeEmptyValues = ( if ((Number.isFinite(value) && value !== 0) || !isEmpty(value)) { Object.assign(result, { [key]: value }); } else { - Object.assign(result, { [key]: "---" }); + Object.assign(result, { [key]: DEFAULT_EMPTY_CELL_VALUE }); } return result; }, @@ -837,7 +838,7 @@ export const wrapFleetHelper = ( helperFn: (value: any) => string, // TODO: replace any with unknown and improve type narrowing by callers value: string ): string => { - return value === "---" ? value : helperFn(value); + return value === DEFAULT_EMPTY_CELL_VALUE ? value : helperFn(value); }; export default {