diff --git a/client/src/app/api/rest.ts b/client/src/app/api/rest.ts index 542507b07b..a054969a33 100644 --- a/client/src/app/api/rest.ts +++ b/client/src/app/api/rest.ts @@ -358,6 +358,28 @@ export function getTaskByIdAndFormat( }); } +export function getTasksByIds( + ids: number[], + format: "json" | "yaml" +): Promise { + const isYaml = format === "yaml"; + const headers = isYaml ? { ...yamlHeaders } : { ...jsonHeaders }; + const responseType = isYaml ? "text" : "json"; + const filterParam = `id:(${ids.join("|")})`; + + return axios + .get(`${TASKS}`, { + headers: headers, + responseType: responseType, + params: { + filter: filterParam, + }, + }) + .then((response) => { + return response.data; + }); +} + export const getTasksDashboard = () => axios .get(`${TASKS}/report/dashboard`) diff --git a/client/src/app/pages/applications/applications-table/applications-table.tsx b/client/src/app/pages/applications/applications-table/applications-table.tsx index d102d69a2a..28580503e1 100644 --- a/client/src/app/pages/applications/applications-table/applications-table.tsx +++ b/client/src/app/pages/applications/applications-table/applications-table.tsx @@ -16,8 +16,10 @@ import { DropdownItem, Modal, Tooltip, + FormGroup, } from "@patternfly/react-core"; import { + CodeIcon, PencilAltIcon, TagIcon, WarningTriangleIcon, @@ -71,7 +73,11 @@ import { checkAccess } from "@app/utils/rbac-utils"; import { useLocalTableControls } from "@app/hooks/table-controls"; // Queries -import { getArchetypeById, getAssessmentsByItemId } from "@app/api/rest"; +import { + getArchetypeById, + getAssessmentsByItemId, + getTasksByIds, +} from "@app/api/rest"; import { Assessment, Ref } from "@app/api/models"; import { useBulkDeleteApplicationMutation, @@ -109,6 +115,7 @@ import { DecoratedApplication, useDecoratedApplications, } from "./useDecoratedApplications"; +import yaml from "js-yaml"; export const ApplicationsTable: React.FC = () => { const { t } = useTranslation(); @@ -145,8 +152,13 @@ export const ApplicationsTable: React.FC = () => { const [applicationDependenciesToManage, setApplicationDependenciesToManage] = useState(null); + const isDependenciesModalOpen = applicationDependenciesToManage !== null; + const [isDownloadModalOpen, setIsDownloadModalOpen] = useState(false); + + const [selectedFormat, setSelectedFormat] = useState<"json" | "yaml">("json"); + const [assessmentToEdit, setAssessmentToEdit] = useState( null ); @@ -194,6 +206,37 @@ export const ApplicationsTable: React.FC = () => { }); }; + const handleDownload = async () => { + const ids = selectedRows + .map((row) => row.tasks.currentAnalyzer?.id) + .filter((id): id is number => typeof id === "number"); + + try { + const tasks = await getTasksByIds(ids, selectedFormat); + const data = + selectedFormat === "yaml" + ? yaml.dump(tasks, { indent: 2 }) + : JSON.stringify(tasks, null, 2); + + const blob = new Blob([data], { + type: + selectedFormat === "json" ? "application/json" : "application/x-yaml", + }); + const url = URL.createObjectURL(blob); + const downloadLink = document.createElement("a"); // שינוי שם למשתנה + downloadLink.href = url; + downloadLink.download = `logs - ${ids}.${selectedFormat}`; + document.body.appendChild(downloadLink); + downloadLink.click(); + document.body.removeChild(downloadLink); + URL.revokeObjectURL(url); + + setIsDownloadModalOpen(false); + } catch (error) { + console.error("Error fetching tasks:", error); + } + }; + const failedCancelTask = () => { pushNotification({ title: "Task", @@ -575,6 +618,20 @@ export const ApplicationsTable: React.FC = () => { > {t("actions.delete")} , + + application.tasks.currentAnalyzer?.id !== undefined + ) + } + onClick={() => { + setIsDownloadModalOpen(true); + }} + > + {t("actions.download", { what: "analysis details" })} + , ...(credentialsReadAccess ? [ { }} /> + setIsDownloadModalOpen(false)} + > + + {" "} +
+ {" "} + {" "} + {" "} +
{" "} +

Selected Format: {selectedFormat}

{" "} +
{" "} + {" "} +
); };