Fleet UI: Remove install tooltip and add timestamp to InstallDetails modal (#33991)

This commit is contained in:
RachelElysia 2025-10-08 13:30:58 -04:00 committed by GitHub
parent b4a1671490
commit f21e9f67b2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 56 additions and 62 deletions

View file

@ -19,7 +19,7 @@ import SoftwareInstallDetailsModal, {
describe("SoftwareInstallDetailsModal", () => {
describe("StatusMessage component", () => {
it("renders basic 'is installed' message when not installed by fleet (no installResult provided)", () => {
render(<StatusMessage softwareName="CoolApp" isDUP={false} />);
render(<StatusMessage softwareName="CoolApp" isMyDevicePage={false} />);
expect(screen.getByText(/CoolApp/)).toBeInTheDocument();
expect(screen.getByText(/is installed/)).toBeInTheDocument();
});
@ -31,7 +31,7 @@ describe("SoftwareInstallDetailsModal", () => {
installResult={createMockSoftwareInstallResult({
status: "pending_install",
})}
isDUP={false}
isMyDevicePage={false}
/>
);
@ -42,6 +42,7 @@ describe("SoftwareInstallDetailsModal", () => {
expect(screen.getByText(/\(com\.cool\.app\)/)).toBeInTheDocument();
expect(screen.getByText(/Test Host/)).toBeInTheDocument();
expect(screen.getByText(/when it comes online/)).toBeInTheDocument();
expect(screen.queryByText(/\d+.*ago/)).not.toBeInTheDocument();
});
it("on device user page, renders failed install with retry option with contact link", () => {
@ -51,7 +52,7 @@ describe("SoftwareInstallDetailsModal", () => {
installResult={createMockSoftwareInstallResult({
status: "failed_install",
})}
isDUP
isMyDevicePage
contactUrl="http://support"
/>
);
@ -61,6 +62,7 @@ describe("SoftwareInstallDetailsModal", () => {
expect(screen.getByText(/CoolApp/)).toBeInTheDocument();
// Host name should not be rendered for device user page
expect(screen.queryByText(/Test Host/)).not.toBeInTheDocument();
expect(screen.getByText(/\d+.*ago/)).toBeInTheDocument();
expect(screen.getByText(/You can retry/)).toBeInTheDocument();
expect(
screen.getByRole("link", { name: /contact your IT admin/ })
@ -74,7 +76,7 @@ describe("SoftwareInstallDetailsModal", () => {
installResult={createMockSoftwareInstallResult({
status: "failed_install",
})}
isDUP
isMyDevicePage
/>
);
@ -83,6 +85,7 @@ describe("SoftwareInstallDetailsModal", () => {
expect(screen.getByText(/CoolApp/)).toBeInTheDocument();
// Host name should not be rendered for device user page
expect(screen.queryByText(/Test Host/)).not.toBeInTheDocument();
expect(screen.getByText(/\d+.*ago/)).toBeInTheDocument();
expect(screen.getByText(/You can retry/)).toBeInTheDocument();
// Don't show link of not provided
expect(
@ -97,7 +100,7 @@ describe("SoftwareInstallDetailsModal", () => {
installResult={createMockSoftwareInstallResult({
status: "failed_install",
})}
isDUP={false}
isMyDevicePage={false}
contactUrl="http://support"
/>
);
@ -106,6 +109,7 @@ describe("SoftwareInstallDetailsModal", () => {
expect(screen.getByText(/failed to install/)).toBeInTheDocument();
expect(screen.getByText(/Test Host/)).toBeInTheDocument();
expect(screen.queryByText(/You can retry/)).not.toBeInTheDocument();
expect(screen.getByText(/\d+.*ago/)).toBeInTheDocument();
});
it("on host details page/install activity, renders installed message with timestamp", () => {
@ -115,7 +119,7 @@ describe("SoftwareInstallDetailsModal", () => {
installResult={createMockSoftwareInstallResult({
status: "installed",
})}
isDUP={false}
isMyDevicePage={false}
/>
);

View file

@ -53,7 +53,7 @@ export const renderContactOption = (url?: string) => (
interface IInstallStatusMessage {
softwareName: string;
installResult?: ISoftwareInstallResult;
isDUP: boolean;
isMyDevicePage: boolean;
contactUrl?: string;
}
@ -62,7 +62,7 @@ interface IInstallStatusMessage {
export const StatusMessage = ({
softwareName,
installResult,
isDUP,
isMyDevicePage,
contactUrl,
}: IInstallStatusMessage) => {
// the case when software is installed by the user and not by Fleet
@ -107,22 +107,25 @@ export const StatusMessage = ({
Fleet {getInstallDetailsStatusPredicate(status)} <b>{software_title}</b>
</>
);
let middle = null;
if (isDUP) {
if (status === "failed_install") {
middle = <>. You can retry{renderContactOption(contactUrl)}</>;
}
} else {
// host details page
middle = (
<>
{" "}
({software_package}) on {formattedHost}
{status === "pending_install" ? " when it comes online" : ""}
{displayTimeStamp}
</>
);
}
const middle = isMyDevicePage ? (
<>
{" "}
{displayTimeStamp}
{status === "failed_install" && (
<>. You can retry{renderContactOption(contactUrl)}</>
)}
</>
) : (
<>
{" "}
({software_package}) on {formattedHost}
{status === "pending_install"
? " when it comes online"
: displayTimeStamp}
</>
);
return (
<span>
{prefix}
@ -349,7 +352,7 @@ export const SoftwareInstallDetailsModal = ({
<StatusMessage
installResult={installResultWithHostDisplayName}
softwareName={hostSoftware?.name || "Software"} // will always be defined at this point
isDUP={!!deviceAuthToken}
isMyDevicePage={!!deviceAuthToken}
contactUrl={contactUrl}
/>

View file

@ -15,7 +15,7 @@ describe("SoftwareUninstallDetailsModal - StatusMessage component", () => {
status="pending_uninstall"
softwareName="CoolApp"
softwarePackageName="com.cool.app"
isDUP={false}
isMyDevicePage={false}
/>
);
@ -36,7 +36,7 @@ describe("SoftwareUninstallDetailsModal - StatusMessage component", () => {
hostDisplayName="Test Host"
status="failed_uninstall"
softwareName="CoolApp"
isDUP
isMyDevicePage
contactUrl="http://support"
/>
);
@ -54,7 +54,7 @@ describe("SoftwareUninstallDetailsModal - StatusMessage component", () => {
hostDisplayName="Test Host"
status="failed_uninstall"
softwareName="CoolApp"
isDUP={false}
isMyDevicePage={false}
contactUrl="http://support"
/>
);
@ -74,7 +74,7 @@ describe("SoftwareUninstallDetailsModal - StatusMessage component", () => {
softwareName="CoolApp"
softwarePackageName="com.cool.app"
timestamp="2025-08-10T12:00:00Z"
isDUP={false}
isMyDevicePage={false}
/>
);

View file

@ -36,7 +36,7 @@ interface IUninstallStatusMessage {
softwareName: string;
softwarePackageName?: string;
timestamp?: string;
isDUP: boolean;
isMyDevicePage: boolean;
contactUrl?: string;
}
@ -46,7 +46,7 @@ export const StatusMessage = ({
softwareName,
softwarePackageName,
timestamp,
isDUP,
isMyDevicePage,
contactUrl,
}: IUninstallStatusMessage) => {
const formattedHost = hostDisplayName ? <b>{hostDisplayName}</b> : "the host";
@ -67,7 +67,7 @@ export const StatusMessage = ({
</>
);
let suffix = null;
if (isDUP) {
if (isMyDevicePage) {
if (status === "failed_uninstall") {
suffix = <>. You can retry{renderContactOption(contactUrl)}</>;
}
@ -232,7 +232,7 @@ const SoftwareUninstallDetailsModal = ({
softwareName={softwareName}
softwarePackageName={softwarePackageName}
timestamp={uninstallResult?.created_at}
isDUP={!!deviceAuthToken}
isMyDevicePage={!!deviceAuthToken}
contactUrl={contactUrl}
/>
{uninstallStatus !== "pending_uninstall" && (

View file

@ -158,7 +158,7 @@ describe("getStatusMessage helper function", () => {
it("on the device user page, does not show host info", () => {
render(
getStatusMessage({
isDUP: true,
isMyDevicePage: true,
displayStatus: "installed",
isMDMStatusNotNow: false,
isMDMStatusAcknowledged: false,

View file

@ -29,7 +29,7 @@ import {
} from "../constants";
interface IGetStatusMessageProps {
isDUP?: boolean;
isMyDevicePage?: boolean;
/** "pending" is an edge case here where VPP install activities that were added to the feed prior to v4.57
* (when we split pending into pending_install/pending_uninstall) will list the status as "pending" rather than "pending_install" */
displayStatus: SoftwareInstallStatus | "pending";
@ -41,7 +41,7 @@ interface IGetStatusMessageProps {
}
export const getStatusMessage = ({
isDUP = false,
isMyDevicePage = false,
displayStatus,
isMDMStatusNotNow,
isMDMStatusAcknowledged,
@ -79,7 +79,7 @@ export const getStatusMessage = ({
return (
<>
Fleet tried to install <b>{appName}</b>
{!isDUP && (
{!isMyDevicePage && (
<>
{" "}
on {formattedHost} but couldn&apos;t because the host was locked or
@ -96,9 +96,9 @@ export const getStatusMessage = ({
return (
<>
The MDM command (request) to install <b>{appName}</b>
{!isDUP && <> on {formattedHost}</>} was acknowledged but the
{!isMyDevicePage && <> on {formattedHost}</>} was acknowledged but the
installation has not been verified. To re-check, select <b>Refetch</b>
{!isDUP && " for this host"}.
{!isMyDevicePage && " for this host"}.
</>
);
}
@ -108,7 +108,7 @@ export const getStatusMessage = ({
return (
<>
The MDM command (request) to install <b>{appName}</b>
{!isDUP && <> on {formattedHost}</>} was acknowledged but the
{!isMyDevicePage && <> on {formattedHost}</>} was acknowledged but the
installation has not been verified. Please re-attempt this installation.
</>
);
@ -119,7 +119,7 @@ export const getStatusMessage = ({
return (
<>
The MDM command (request) to install <b>{appName}</b>
{!isDUP && <> on {formattedHost}</>} failed
{!isMyDevicePage && <> on {formattedHost}</>} failed
{displayTimeStamp && <> {displayTimeStamp}</>}. Please re-attempt this
installation.
</>
@ -127,7 +127,7 @@ export const getStatusMessage = ({
}
const renderSuffix = () => {
if (isDUP) {
if (isMyDevicePage) {
return <> {displayTimeStamp && <> {displayTimeStamp}</>}</>;
}
return (
@ -299,7 +299,7 @@ export const VppInstallDetailsModal = ({
: true; // if no hostSoftware passed in, can assume this is the activity feed, meaning this can only refer to a Fleet-handled install
const statusMessage = getStatusMessage({
isDUP: !!deviceAuthToken,
isMyDevicePage: !!deviceAuthToken,
displayStatus,
isMDMStatusNotNow,
isMDMStatusAcknowledged,

View file

@ -19,7 +19,7 @@ jest.mock("lodash", () => ({
const testSoftwarePackage = createMockHostSoftwarePackage();
describe("InstallStatusCell - component", () => {
it("renders 'Installed' status with tooltip", async () => {
it("renders 'Installed' status without tooltip", async () => {
const { user } = renderWithSetup(
<InstallStatusCell
software={{
@ -43,9 +43,10 @@ describe("InstallStatusCell - component", () => {
await user.hover(screen.getByText("Installed"));
await waitFor(() => {
expect(screen.getByText(/Software was installed/i)).toBeInTheDocument();
});
// No tooltip on install status
expect(
screen.queryByText(/Software was installed/i)
).not.toBeInTheDocument();
// There SHOULD be a button with this label
expect(

View file

@ -74,21 +74,7 @@ export const INSTALL_STATUS_DISPLAY_OPTIONS: Record<
installed: {
iconName: "success",
displayText: "Installed",
tooltip: ({ isSelfService, isAppStoreApp, lastInstalledAt }) => {
if (!lastInstalledAt) {
return undefined;
}
return (
<>
Software was installed{" "}
{!isSelfService &&
!isAppStoreApp &&
"(install script finished with exit code 0) "}
{dateAgo(lastInstalledAt)}.
</>
);
},
tooltip: () => undefined, // No tooltip for installed state
},
recently_updated: {
iconName: "success",