diff --git a/changes/33733-install-details-modal b/changes/33733-install-details-modal new file mode 100644 index 0000000000..820ee99202 --- /dev/null +++ b/changes/33733-install-details-modal @@ -0,0 +1 @@ +* Fleet UI: Return pre-install query output in Install Details modal \ No newline at end of file diff --git a/frontend/components/ActivityDetails/InstallDetails/SoftwareInstallDetailsModal/SoftwareInstallDetailsModal.tests.tsx b/frontend/components/ActivityDetails/InstallDetails/SoftwareInstallDetailsModal/SoftwareInstallDetailsModal.tests.tsx index 3daa56de3a..1f94462c64 100644 --- a/frontend/components/ActivityDetails/InstallDetails/SoftwareInstallDetailsModal/SoftwareInstallDetailsModal.tests.tsx +++ b/frontend/components/ActivityDetails/InstallDetails/SoftwareInstallDetailsModal/SoftwareInstallDetailsModal.tests.tsx @@ -7,6 +7,8 @@ import { getDefaultSoftwareInstallHandler, getSoftwareInstallHandlerNoOutputs, getSoftwareInstallHandlerOnlyInstallOutput, + getSoftwareInstallHandlerWithPreInstall, + getSoftwareInstallHandlerOnlyPreInstallOutput, } from "test/handlers/software-handlers"; import mockServer from "test/mock-server"; import { noop } from "lodash"; @@ -216,14 +218,78 @@ describe("SoftwareInstallDetailsModal", () => { expect(detailsButton).toBeInTheDocument(); expect( - screen.queryByLabelText("Install script output:") + screen.queryByText("Pre-install query output:") ).not.toBeInTheDocument(); expect( - screen.queryByLabelText(/Post-install script output:/i) + screen.queryByText("Install script output:") + ).not.toBeInTheDocument(); + expect( + screen.queryByText(/Post-install script output:/i) ).not.toBeInTheDocument(); }); - it("shows install and post-install outputs after clicking Details", async () => { + it("shows pre-install, install, and post-install outputs after clicking Details", async () => { + mockServer.use(getSoftwareInstallHandlerWithPreInstall); + const renderWithServer = createCustomRenderer({ withBackendMock: true }); + const { user } = renderWithServer( + + ); + + const detailsBtn = await screen.findByRole("button", { + name: /Details/i, + }); + await user.click(detailsBtn); + + // Pre-install output + expect( + await screen.getByText("Pre-install query output:") + ).toBeInTheDocument(); + expect(screen.getByText("Pre-install check passed")).toBeInTheDocument(); + + // Install output + expect(screen.getByText("Install script output:")).toBeInTheDocument(); + expect(screen.getByText("Install script ran")).toBeInTheDocument(); + + // Post-install output + expect( + screen.getByText("Post-install script output:") + ).toBeInTheDocument(); + expect(screen.getByText("Post-install success")).toBeInTheDocument(); + }); + + it("renders only pre-install output if that's the only script output present", async () => { + mockServer.use(getSoftwareInstallHandlerOnlyPreInstallOutput); + const renderWithServer = createCustomRenderer({ withBackendMock: true }); + const { user } = renderWithServer( + + ); + + const detailsBtn = await screen.findByRole("button", { + name: /Details/i, + }); + await user.click(detailsBtn); + + expect( + await screen.getByText("Pre-install query output:") + ).toBeInTheDocument(); + expect(screen.getByText(/pre-install only/i)).toBeInTheDocument(); + expect( + screen.queryByText("Install script output:") + ).not.toBeInTheDocument(); + expect( + screen.queryByText(/Post-install script output:/i) + ).not.toBeInTheDocument(); + }); + + it("shows install and post-install outputs after clicking Details (no pre-install)", async () => { mockServer.use(getDefaultSoftwareInstallHandler); const renderWithServer = createCustomRenderer({ withBackendMock: true }); const { user } = renderWithServer( @@ -239,15 +305,48 @@ describe("SoftwareInstallDetailsModal", () => { }); await user.click(detailsBtn); - await screen.findByText("Install script output:"); + expect( + await screen.getByText("Install script output:") + ).toBeInTheDocument(); expect(screen.getByText("Install script ran")).toBeInTheDocument(); expect( screen.getByText(/Post-install script output:/i) ).toBeInTheDocument(); expect(screen.getByText("Post-install success")).toBeInTheDocument(); + expect( + screen.queryByText("Pre-install query output:") + ).not.toBeInTheDocument(); }); - it("does not render details button if details (script outputs) are empty", async () => { + it("shows only the install output if post-install and pre-install output is empty", async () => { + mockServer.use(getSoftwareInstallHandlerOnlyInstallOutput); + const renderWithServer = createCustomRenderer({ withBackendMock: true }); + const { user } = renderWithServer( + + ); + + const detailsBtn = await screen.findByRole("button", { + name: /Details/i, + }); + await user.click(detailsBtn); + + expect( + await screen.getByText("Install script output:") + ).toBeInTheDocument(); + expect(screen.getByText(/install only/i)).toBeInTheDocument(); + expect( + screen.queryByText("Pre-install query output:") + ).not.toBeInTheDocument(); + expect( + screen.queryByText(/Post-install script output:/i) + ).not.toBeInTheDocument(); + }); + + it("does not render details button if all script outputs are empty", async () => { mockServer.use(getSoftwareInstallHandlerNoOutputs); const renderWithServer = createCustomRenderer({ withBackendMock: true }); renderWithServer( @@ -264,28 +363,5 @@ describe("SoftwareInstallDetailsModal", () => { }) ).not.toBeInTheDocument(); }); - - it("shows only the install output if post-install output is empty", async () => { - mockServer.use(getSoftwareInstallHandlerOnlyInstallOutput); - const renderWithServer = createCustomRenderer({ withBackendMock: true }); - const { user } = renderWithServer( - - ); - - const detailsBtn = await screen.findByRole("button", { - name: /Details/i, - }); - await user.click(detailsBtn); - - await screen.findByText("Install script output:"); - expect(screen.getByText(/install only/i)).toBeInTheDocument(); - expect( - screen.queryByText(/Post-install script output:/i) - ).not.toBeInTheDocument(); - }); }); }); diff --git a/frontend/components/ActivityDetails/InstallDetails/SoftwareInstallDetailsModal/SoftwareInstallDetailsModal.tsx b/frontend/components/ActivityDetails/InstallDetails/SoftwareInstallDetailsModal/SoftwareInstallDetailsModal.tsx index b0f27cf46f..daec922174 100644 --- a/frontend/components/ActivityDetails/InstallDetails/SoftwareInstallDetailsModal/SoftwareInstallDetailsModal.tsx +++ b/frontend/components/ActivityDetails/InstallDetails/SoftwareInstallDetailsModal/SoftwareInstallDetailsModal.tsx @@ -260,6 +260,10 @@ export const SoftwareInstallDetailsModal = ({ const renderInstallDetailsSection = () => { const outputs = [ + { + label: "Pre-install query output:", + value: swInstallResult?.pre_install_query_output, + }, { label: "Install script output:", value: swInstallResult?.output, @@ -273,7 +277,8 @@ export const SoftwareInstallDetailsModal = ({ // Only show details button if there's details to display const showDetailsButton = (!!swInstallResult?.post_install_script_output || - !!swInstallResult?.output) && + !!swInstallResult?.output || + !!swInstallResult?.pre_install_query_output) && swInstallResult?.status !== "pending_install"; return ( diff --git a/frontend/test/handlers/software-handlers.ts b/frontend/test/handlers/software-handlers.ts index d9e53f4bb1..b8ae9fd1ec 100644 --- a/frontend/test/handlers/software-handlers.ts +++ b/frontend/test/handlers/software-handlers.ts @@ -64,6 +64,44 @@ export const getSoftwareInstallResultHandler = http.get( } ); +// ---- Pre install query output ---- + +// Installed, outputs for pre-install, install, and post-install +export const getSoftwareInstallHandlerWithPreInstall = http.get( + baseUrl("/software/install/:install_uuid/results"), + ({ params }) => { + return HttpResponse.json({ + results: { + ...createMockSoftwareInstallResult({ + install_uuid: params.install_uuid as string, + status: "installed", + output: "Install script ran", + post_install_script_output: "Post-install success", + pre_install_query_output: "Pre-install check passed", + }), + }, + }); + } +); + +// Failed install, only pre-install output +export const getSoftwareInstallHandlerOnlyPreInstallOutput = http.get( + baseUrl("/software/install/:install_uuid/results"), + ({ params }) => { + return HttpResponse.json({ + results: { + ...createMockSoftwareInstallResult({ + install_uuid: params.install_uuid as string, + status: "failed_install", + output: "", + post_install_script_output: "", + pre_install_query_output: "Pre-install only", + }), + }, + }); + } +); + // ---- MDM Command Handlers ---- /** This is used for testing command results of IPA custom packages */