diff --git a/client/src/app/api/rest.ts b/client/src/app/api/rest.ts index 14d1677276..b77d2d0f8f 100644 --- a/client/src/app/api/rest.ts +++ b/client/src/app/api/rest.ts @@ -348,16 +348,6 @@ export const getApplicationImports = ( .get(`${APP_IMPORT}?importSummary.id=${importSummaryID}&isValid=${isValid}`) .then((response) => response.data); -export const getApplicationAnalysis = ( - applicationId: number, - format: "json" | "yaml" -): Promise => { - const headers = format === "yaml" ? yamlHeaders : jsonHeaders; - return axios - .get(`${APPLICATIONS}/${applicationId}/analysis`, headers) - .then((response) => response.data); -}; - export function getTaskById(id: number, format: "json"): Promise; export function getTaskById(id: number, format: "yaml"): Promise; export function getTaskById( diff --git a/client/src/app/pages/applications/components/application-detail-drawer/application-detail-drawer-analysis.tsx b/client/src/app/pages/applications/components/application-detail-drawer/application-detail-drawer-analysis.tsx index 3457a644ba..ebe8aa5884 100644 --- a/client/src/app/pages/applications/components/application-detail-drawer/application-detail-drawer-analysis.tsx +++ b/client/src/app/pages/applications/components/application-detail-drawer/application-detail-drawer-analysis.tsx @@ -6,6 +6,11 @@ import { Title, Tooltip, Button, + Divider, + DescriptionList, + DescriptionListGroup, + DescriptionListTerm, + DescriptionListDescription, } from "@patternfly/react-core"; import { CheckCircleIcon, @@ -23,8 +28,10 @@ import { EmptyTextMessage } from "@app/components/EmptyTextMessage"; import { useFetchFacts } from "@app/queries/facts"; import { ApplicationFacts } from "./application-facts"; import { SimpleDocumentViewerModal } from "@app/components/SimpleDocumentViewer"; -import { getTaskById } from "@app/api/rest"; +import { APPLICATIONS, getTaskById } from "@app/api/rest"; import { COLOR_HEX_VALUES_BY_NAME } from "@app/Constants"; +import { Link } from "react-router-dom"; +import DownloadButton, { MimeType } from "./components/download-button"; export interface IApplicationDetailDrawerAnalysisProps extends Pick< @@ -100,23 +107,57 @@ export const ApplicationDetailDrawerAnalysis: React.FC< {task?.state === "Succeeded" && application ? ( <> - - - + + + Details + + + + + + Download + + + + + {" | "} + + + + + + + ) : task?.state === "Failed" ? ( task ? ( diff --git a/client/src/app/pages/applications/components/application-detail-drawer/components/download-button.tsx b/client/src/app/pages/applications/components/application-detail-drawer/components/download-button.tsx new file mode 100644 index 0000000000..40bb848f40 --- /dev/null +++ b/client/src/app/pages/applications/components/application-detail-drawer/components/download-button.tsx @@ -0,0 +1,56 @@ +import React, { useState } from "react"; +import { Alert, Button } from "@patternfly/react-core"; +import spacing from "@patternfly/react-styles/css/utilities/Spacing/spacing"; +import { Application } from "@app/api/models"; +import { Spinner } from "@patternfly/react-core"; +import { useDownloadStaticReport } from "@app/queries/download"; + +export enum MimeType { + TAR = "tar", + YAML = "yaml", +} +function DownloadButton({ + application, + mimeType, +}: { + application: Application; + mimeType: MimeType; +}) { + const { + mutate: downloadFile, + isLoading, + isError, + } = useDownloadStaticReport(); + + const handleDownload = () => { + downloadFile({ + applicationId: application.id, + mimeType: mimeType, + }); + }; + + return ( + <> + {isLoading ? ( + + ) : isError ? ( + +

{"An error has occurred. Try to download again."}

+
+ ) : ( + <> + + + )} + + ); +} + +export default DownloadButton; diff --git a/client/src/app/queries/download.ts b/client/src/app/queries/download.ts new file mode 100644 index 0000000000..8efc46faa8 --- /dev/null +++ b/client/src/app/queries/download.ts @@ -0,0 +1,55 @@ +import axios from "axios"; +import { saveAs } from "file-saver"; +import { APPLICATIONS } from "@app/api/rest"; +import { useMutation } from "@tanstack/react-query"; +import { MimeType } from "@app/pages/applications/components/application-detail-drawer/components/download-button"; + +interface DownloadOptions { + applicationId: number; + mimeType: MimeType; +} + +export const downloadStaticReport = async ({ + applicationId, + mimeType, +}: DownloadOptions): Promise => { + let acceptHeader = "application/x-tar"; + + switch (mimeType) { + case MimeType.YAML: + acceptHeader = "application/x-yaml"; + break; + case MimeType.TAR: + default: + acceptHeader = "application/x-tar"; + } + + try { + const response = await axios.get( + `${APPLICATIONS}/${applicationId}/analysis/report`, + { + responseType: "blob", + headers: { + Accept: acceptHeader, + }, + } + ); + + if (response.status !== 200) { + throw new Error("Network response was not ok when downloading file."); + } + + const blob = new Blob([response.data]); + saveAs( + blob, + `analysis-report-app-${applicationId}.${acceptHeader.split("-")[1]}` + ); + } catch (error) { + console.error("There was an error downloading the file:", error); + throw error; + } +}; + +export const useDownloadStaticReport = () => { + return useMutation(downloadStaticReport); +}; diff --git a/common/src/proxies.ts b/common/src/proxies.ts index b56a2fcb37..75734f3081 100644 --- a/common/src/proxies.ts +++ b/common/src/proxies.ts @@ -39,9 +39,6 @@ export const proxyMap: Record = { }, onProxyReq: (proxyReq, req, res) => { - if (req.originalUrl.includes("windup/report/?filter")) { - proxyReq.setHeader("Accept", ""); - } if (req.cookies?.keycloak_cookie && !req.headers["authorization"]) { proxyReq.setHeader( "Authorization",