fix refetch button tooltip rendering on host details page (#34987)

**Related issue:** fixes #34840

This fixes the host details refetch button rendering. This includes:

1. refactoring to use TooltipWrapper component so that the styling of
the tip content is consistant
2. prioitise showing the host status tooltips over the offline tooltips.

- [x] Added/updated automated tests
- [x] QA'd all new/changed functionality manually
This commit is contained in:
Gabriel Hernandez 2025-10-31 14:21:47 +00:00 committed by GitHub
parent 924d676c57
commit b8f1a816aa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 51 additions and 46 deletions

View file

@ -1,5 +1,7 @@
import React from "react";
import { render, screen, fireEvent } from "@testing-library/react";
import { renderWithSetup } from "test/test-utils";
import HostHeader from "./HostHeader";
import { HostMdmDeviceStatusUIState } from "../../helpers";
@ -90,8 +92,8 @@ describe("HostHeader", () => {
expect(onRefetchHost).toHaveBeenCalled();
});
it("shows tooltip when host is offline", () => {
render(
it("shows tooltip when host is offline", async () => {
const { user } = renderWithSetup(
<HostHeader
summaryData={{ ...defaultSummaryData, status: "offline" }}
showRefetchSpinner={false}
@ -99,11 +101,30 @@ describe("HostHeader", () => {
renderActionsDropdown={renderActionDropdown}
/>
);
expect(screen.getByText(/an offline host/i)).toBeInTheDocument();
await user.hover(screen.getByText("Refetch"));
expect(await screen.findByText(/an offline host/i)).toBeInTheDocument();
});
it("renders device status tag and tooltip if hostMdmDeviceStatus is set", () => {
render(
it("prioritises showing host status tooltips over offline tooltips on the refetch button", async () => {
const { user } = renderWithSetup(
<HostHeader
summaryData={{ ...defaultSummaryData, status: "offline" }}
showRefetchSpinner={false}
onRefetchHost={jest.fn()}
renderActionsDropdown={renderActionDropdown}
hostMdmDeviceStatus={"locked" as HostMdmDeviceStatusUIState}
/>
);
await user.hover(screen.getByText("Refetch"));
expect(await screen.findByText(/a locked host/i)).toBeInTheDocument();
});
it("renders device status tag and tooltip if hostMdmDeviceStatus is set", async () => {
const { user } = renderWithSetup(
<HostHeader
summaryData={defaultSummaryData}
showRefetchSpinner={false}
@ -112,6 +133,9 @@ describe("HostHeader", () => {
hostMdmDeviceStatus={"locked" as HostMdmDeviceStatusUIState}
/>
);
expect(screen.getByText(/a locked host/i)).toBeInTheDocument();
await user.hover(screen.getByText("LOCKED"));
expect(await screen.findByText(/Host is locked/i)).toBeInTheDocument();
});
});

View file

@ -1,5 +1,4 @@
import React, { useRef } from "react";
import ReactTooltip from "react-tooltip";
import classnames from "classnames";
import { isAndroid, isIPadOrIPhone } from "interfaces/platform";
@ -8,7 +7,6 @@ import Button from "components/buttons/Button";
import Icon from "components/Icon/Icon";
import { HumanTimeDiffWithFleetLaunchCutoff } from "components/HumanTimeDiffWithDateTip";
import { DEFAULT_EMPTY_CELL_VALUE } from "utilities/constants";
import { COLORS } from "styles/var/colors";
import { useCheckTruncatedElement } from "hooks/useCheckTruncatedElement";
import TooltipWrapper from "components/TooltipWrapper";
@ -33,7 +31,6 @@ const RefetchButton = ({
onRefetchHost,
}: IRefetchButtonProps) => {
const classNames = classnames({
tooltip: isDisabled,
"refetch-spinner": isFetching,
"refetch-btn": !isFetching,
});
@ -42,41 +39,27 @@ const RefetchButton = ({
? "Fetching fresh vitals...this may take a moment"
: "Refetch";
// add additonal props when we need to display a tooltip for the button
const conditionalProps: { "data-tip"?: boolean; "data-for"?: string } = {};
if (tooltip) {
conditionalProps["data-tip"] = true;
conditionalProps["data-for"] = "refetch-tooltip";
}
const renderTooltip = () => {
return (
<ReactTooltip
place="top"
effect="solid"
id="refetch-tooltip"
backgroundColor={COLORS["tooltip-bg"]}
>
<span className={`${baseClass}__tooltip-text`}>{tooltip}</span>
</ReactTooltip>
);
};
return (
<>
<div className={`${baseClass}__refetch`} {...conditionalProps}>
<Button
className={classNames}
disabled={isDisabled || isFetching}
onClick={onRefetchHost}
variant="inverse"
>
<Icon name="refresh" color="ui-fleet-black-75" size="small" />
{buttonText}
</Button>
{tooltip && renderTooltip()}
</div>
<TooltipWrapper
underline={false}
disableTooltip={!tooltip}
tipContent={tooltip}
position="top"
showArrow
>
<div className={`${baseClass}__refetch`}>
<Button
className={classNames}
disabled={isDisabled || isFetching}
onClick={onRefetchHost}
variant="inverse"
>
<Icon name="refresh" color="ui-fleet-black-75" size="small" />
{buttonText}
</Button>
</div>
</TooltipWrapper>
</>
);
};
@ -99,7 +82,7 @@ const HostHeader = ({
renderActionsDropdown,
deviceUser,
hostMdmDeviceStatus,
}: IHostSummaryProps): JSX.Element => {
}: IHostSummaryProps) => {
const { platform } = summaryData;
const hostDisplayName = useRef<HTMLHeadingElement>(null);
@ -129,9 +112,7 @@ const HostHeader = ({
tooltip = !isOnline ? REFETCH_TOOLTIP_MESSAGES.offline : null;
} else {
isDisabled = true;
tooltip = !isOnline
? REFETCH_TOOLTIP_MESSAGES.offline
: REFETCH_TOOLTIP_MESSAGES[hostMdmDeviceStatus];
tooltip = REFETCH_TOOLTIP_MESSAGES[hostMdmDeviceStatus];
}
} else {
// ios and ipad devices refresh buttons disable state is determined only by the