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 */