From d2a57bd74ff9afbbf51b1f0f311f982068976630 Mon Sep 17 00:00:00 2001 From: TalyaNeima Date: Wed, 18 Sep 2024 12:19:00 +0300 Subject: [PATCH 1/3] adding filtering by analysis --- .../applications-table/applications-table.tsx | 193 ++++++++++-------- .../application-analysis-status.tsx | 2 +- 2 files changed, 110 insertions(+), 85 deletions(-) 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 d102d69a2..8c58b5f7a 100644 --- a/client/src/app/pages/applications/applications-table/applications-table.tsx +++ b/client/src/app/pages/applications/applications-table/applications-table.tsx @@ -85,10 +85,11 @@ import { import { useDeleteAssessmentMutation } from "@app/queries/assessments"; import { useDeleteReviewMutation } from "@app/queries/reviews"; import { useFetchTagsWithTagItems } from "@app/queries/tags"; +import { TaskState } from "@app/api/models"; // Relative components import { AnalysisWizard } from "../analysis-wizard/analysis-wizard"; -import { ApplicationAnalysisStatus } from "../components/application-analysis-status"; +import { ApplicationAnalysisStatus, taskStateToAnalyze } from "../components/application-analysis-status"; import { ApplicationAssessmentStatus } from "../components/application-assessment-status"; import { ApplicationBusinessService } from "../components/application-business-service"; import { ApplicationDependenciesForm } from "@app/components/ApplicationDependenciesFormContainer/ApplicationDependenciesForm"; @@ -109,6 +110,8 @@ import { DecoratedApplication, useDecoratedApplications, } from "./useDecoratedApplications"; +import { Item } from "@app/pages/migration-targets/components/dnd/item"; +import AnalysisDetails from "../analysis-details"; export const ApplicationsTable: React.FC = () => { const { t } = useTranslation(); @@ -367,7 +370,7 @@ export const ApplicationsTable: React.FC = () => { title: t("terms.archetypes"), type: FilterType.multiselect, placeholderText: - t("actions.filterBy", { + t("action s.filterBy", { what: t("terms.archetypes").toLowerCase(), }) + "...", selectOptions: referencedArchetypeRefs.map(({ name }) => ({ @@ -499,6 +502,29 @@ export const ApplicationsTable: React.FC = () => { ], getItemValue: (item) => normalizeRisk(item.risk) ?? "", }, + { + categoryKey: "analysis", + title: t("terms.analysis"), + type: FilterType.multiselect, + placeholderText: + t("actions.filterBy", { + what: t("terms.analysis").toLowerCase(), + }) + "...", + + // taskStateToAnalyze.map(state,icon)=>{ + // value: + + // } forEach.toString()} + // ApplicationAnalysisStatus.toString() + // Object.entries(Analy) + selectOptions: Array.from(taskStateToAnalyze).map(([taskState, displayStatus]) => ({ + value: taskState, // The task state will be the value + label: t(`${displayStatus}`) // The display status translated using t() + })), + + getItemValue: (item) => item?.tasks.currentAnalyzer?.state || + "No task" + }, ], initialItemsPerPage: 10, hasActionsColumn: true, @@ -547,48 +573,48 @@ export const ApplicationsTable: React.FC = () => { const importDropdownItems = importWriteAccess ? [ - setIsApplicationImportModalOpen(true)} - > - {t("actions.import")} - , - { - history.push(Paths.applicationsImports); - }} - > - {t("actions.manageImports")} - , - ] + setIsApplicationImportModalOpen(true)} + > + {t("actions.import")} + , + { + history.push(Paths.applicationsImports); + }} + > + {t("actions.manageImports")} + , + ] : []; const applicationDropdownItems = applicationWriteAccess ? [ - { - setApplicationsToDelete(selectedRows); - }} - > - {t("actions.delete")} - , - ...(credentialsReadAccess - ? [ - { - setSaveApplicationsCredentialsModalState(selectedRows); - }} - > - {t("actions.manageCredentials")} - , - ] - : []), - ] + { + setApplicationsToDelete(selectedRows); + }} + > + {t("actions.delete")} + , + ...(credentialsReadAccess + ? [ + { + setSaveApplicationsCredentialsModalState(selectedRows); + }} + > + {t("actions.manageCredentials")} + , + ] + : []), + ] : []; const dropdownItems = [...importDropdownItems, ...applicationDropdownItems]; @@ -977,58 +1003,58 @@ export const ApplicationsTable: React.FC = () => { onClick: () => assessSelectedApp(application), }, assessmentWriteAccess && - (application.assessments?.length ?? 0) > 0 && { - title: t("actions.discardAssessment"), - onClick: () => - setAssessmentToDiscard(application), - }, + (application.assessments?.length ?? 0) > 0 && { + title: t("actions.discardAssessment"), + onClick: () => + setAssessmentToDiscard(application), + }, reviewsWriteAccess && { title: t("actions.review"), onClick: () => reviewSelectedApp(application), }, reviewsWriteAccess && - application?.review && { - title: t("actions.discardReview"), - onClick: () => setReviewToDiscard(application), - }, + application?.review && { + title: t("actions.discardReview"), + onClick: () => setReviewToDiscard(application), + }, dependenciesWriteAccess && { title: t("actions.manageDependencies"), onClick: () => setApplicationDependenciesToManage(application), }, credentialsReadAccess && - applicationWriteAccess && { - title: t("actions.manageCredentials"), - onClick: () => - setSaveApplicationsCredentialsModalState([ - application, - ]), - }, + applicationWriteAccess && { + title: t("actions.manageCredentials"), + onClick: () => + setSaveApplicationsCredentialsModalState([ + application, + ]), + }, analysesReadAccess && - !!application.tasks.currentAnalyzer && { - title: t("actions.analysisDetails"), - onClick: () => { - const taskId = - application.tasks.currentAnalyzer?.id; - if (taskId && application.id) { - history.push( - formatPath( - Paths.applicationsAnalysisDetails, - { - applicationId: application.id, - taskId, - } - ) - ); - } - }, + !!application.tasks.currentAnalyzer && { + title: t("actions.analysisDetails"), + onClick: () => { + const taskId = + application.tasks.currentAnalyzer?.id; + if (taskId && application.id) { + history.push( + formatPath( + Paths.applicationsAnalysisDetails, + { + applicationId: application.id, + taskId, + } + ) + ); + } }, + }, tasksReadAccess && - tasksWriteAccess && - isTaskCancellable(application) && { - title: t("actions.cancelAnalysis"), - onClick: () => cancelAnalysis(application), - }, + tasksWriteAccess && + isTaskCancellable(application) && { + title: t("actions.cancelAnalysis"), + onClick: () => cancelAnalysis(application), + }, applicationWriteAccess && { isSeparator: true }, applicationWriteAccess && { title: t("actions.delete"), @@ -1131,11 +1157,10 @@ export const ApplicationsTable: React.FC = () => { )} titleIconVariant={"warning"} isOpen={applicationsToDelete.length > 0} - message={`${ - applicationsToDelete.length > 1 - ? t("dialog.message.applicationsBulkDelete") - : "" - } ${t("dialog.message.delete")}`} + message={`${applicationsToDelete.length > 1 + ? t("dialog.message.applicationsBulkDelete") + : "" + } ${t("dialog.message.delete")}`} aria-label="Applications bulk delete" confirmBtnVariant={ButtonVariant.danger} confirmBtnLabel={t("actions.delete")} diff --git a/client/src/app/pages/applications/components/application-analysis-status.tsx b/client/src/app/pages/applications/components/application-analysis-status.tsx index 4462aacaf..94c1e7953 100644 --- a/client/src/app/pages/applications/components/application-analysis-status.tsx +++ b/client/src/app/pages/applications/components/application-analysis-status.tsx @@ -7,7 +7,7 @@ export interface ApplicationAnalysisStatusProps { state: TaskState; } -const taskStateToAnalyze: Map = new Map([ +export const taskStateToAnalyze: Map = new Map([ ["not supported", "Canceled"], ["Canceled", "Canceled"], ["Created", "Scheduled"], From dcea9074c137b5094a4e352c192b6b4459cdc0cc Mon Sep 17 00:00:00 2001 From: TalyaNeima Date: Sun, 22 Sep 2024 10:44:16 +0300 Subject: [PATCH 2/3] sort by analysis Signed-off-by: TalyaNeima --- .../applications-table/applications-table.tsx | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) 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 8c58b5f7a..b3c80a6e9 100644 --- a/client/src/app/pages/applications/applications-table/applications-table.tsx +++ b/client/src/app/pages/applications/applications-table/applications-table.tsx @@ -338,7 +338,7 @@ export const ApplicationsTable: React.FC = () => { sort: "sessionStorage", }, isLoading: isFetchingApplications, - sortableColumns: ["name", "businessService", "tags", "effort"], + sortableColumns: ["name", "businessService", "tags", "effort","analysis"], initialSort: { columnKey: "name", direction: "asc" }, initialColumns: { name: { isIdentity: true }, @@ -348,6 +348,7 @@ export const ApplicationsTable: React.FC = () => { businessService: app.businessService?.name || "", tags: app.tags?.length || 0, effort: app.effort || 0, + analysis: app.tasks.currentAnalyzer?.state || 0 }), filterCategories: [ { @@ -510,18 +511,11 @@ export const ApplicationsTable: React.FC = () => { t("actions.filterBy", { what: t("terms.analysis").toLowerCase(), }) + "...", - - // taskStateToAnalyze.map(state,icon)=>{ - // value: - - // } forEach.toString()} - // ApplicationAnalysisStatus.toString() - // Object.entries(Analy) - selectOptions: Array.from(taskStateToAnalyze).map(([taskState, displayStatus]) => ({ - value: taskState, // The task state will be the value - label: t(`${displayStatus}`) // The display status translated using t() - })), - + selectOptions: Array.from(taskStateToAnalyze).map(([taskState, displayStatus]) => ({ + value: taskState, // The task state will be the value + label: t(`${displayStatus}`) // The display status translated using t() + })), + getItemValue: (item) => item?.tasks.currentAnalyzer?.state || "No task" }, From 01b7f08458c3af42191c8c220af04f8f52401977 Mon Sep 17 00:00:00 2001 From: TalyaNaima Date: Mon, 7 Oct 2024 15:36:45 +0300 Subject: [PATCH 3/3] Fixing bug MTA-3095 Signed-off-by: TalyaNaima --- client/public/locales/en/translation.json | 2 +- client/public/locales/es/translation.json | 2 +- .../applications-table/applications-table.tsx | 212 ++++++++++-------- 3 files changed, 120 insertions(+), 96 deletions(-) diff --git a/client/public/locales/en/translation.json b/client/public/locales/en/translation.json index 6942e06e7..29a0a4a34 100644 --- a/client/public/locales/en/translation.json +++ b/client/public/locales/en/translation.json @@ -507,7 +507,7 @@ "success": { "saveWhat": "{{type}} {{what}} was successfully saved.", "save": "{{type}} was successfully saved.", - "applicationDeleted": "{{appIDCount}} application(s) successfully deleted.", + "applicationDeleted": "{{appName}} application(s) successfully deleted.", "assessmentAndReviewCopied": "Success! Assessment and review copied to selected applications", "assessmentCopied": "Success! Assessment copied to selected applications", "assessmentDiscarded": "Success! Assessment discarded for {{application}}.", diff --git a/client/public/locales/es/translation.json b/client/public/locales/es/translation.json index 2304a0ccc..a90a57db0 100644 --- a/client/public/locales/es/translation.json +++ b/client/public/locales/es/translation.json @@ -309,7 +309,7 @@ "toastr": { "success": { "added": "Éxito! {{what}} fue creado como un {{type}}.", - "applicationDeleted": "{{appIDCount}} aplicacione(s) descheda.", + "applicationDeleted": "{{appName}} aplicacione(s) descheda.", "assessmentAndReviewCopied": "Éxito! Evaluación y revisión copiada a las aplicaciones seleccionadas", "assessmentCopied": "Éxito! Evaluación copiada a las aplicaciones seleccionadas", "assessmentDiscarded": "Éxito! Evaluación de {{application}} desechada.", 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 b3c80a6e9..b343de28c 100644 --- a/client/src/app/pages/applications/applications-table/applications-table.tsx +++ b/client/src/app/pages/applications/applications-table/applications-table.tsx @@ -89,7 +89,10 @@ import { TaskState } from "@app/api/models"; // Relative components import { AnalysisWizard } from "../analysis-wizard/analysis-wizard"; -import { ApplicationAnalysisStatus, taskStateToAnalyze } from "../components/application-analysis-status"; +import { + ApplicationAnalysisStatus, + taskStateToAnalyze, +} from "../components/application-analysis-status"; import { ApplicationAssessmentStatus } from "../components/application-assessment-status"; import { ApplicationBusinessService } from "../components/application-business-service"; import { ApplicationDependenciesForm } from "@app/components/ApplicationDependenciesFormContainer/ApplicationDependenciesForm"; @@ -110,8 +113,6 @@ import { DecoratedApplication, useDecoratedApplications, } from "./useDecoratedApplications"; -import { Item } from "@app/pages/migration-targets/components/dnd/item"; -import AnalysisDetails from "../analysis-details"; export const ApplicationsTable: React.FC = () => { const { t } = useTranslation(); @@ -239,7 +240,7 @@ export const ApplicationsTable: React.FC = () => { const onDeleteApplicationSuccess = (appIDCount: number) => { pushNotification({ title: t("toastr.success.applicationDeleted", { - appIDCount: appIDCount, + appName: applicationsToDelete[0].name, }), variant: "success", }); @@ -338,7 +339,7 @@ export const ApplicationsTable: React.FC = () => { sort: "sessionStorage", }, isLoading: isFetchingApplications, - sortableColumns: ["name", "businessService", "tags", "effort","analysis"], + sortableColumns: ["name", "businessService", "tags", "effort", "analysis"], initialSort: { columnKey: "name", direction: "asc" }, initialColumns: { name: { isIdentity: true }, @@ -348,7 +349,7 @@ export const ApplicationsTable: React.FC = () => { businessService: app.businessService?.name || "", tags: app.tags?.length || 0, effort: app.effort || 0, - analysis: app.tasks.currentAnalyzer?.state || 0 + analysis: app.tasks.currentAnalyzer?.state || 0, }), filterCategories: [ { @@ -503,6 +504,23 @@ export const ApplicationsTable: React.FC = () => { ], getItemValue: (item) => normalizeRisk(item.risk) ?? "", }, + // { + // categoryKey: "analysis", + // title: t("terms.analysis"), + // type: FilterType.multiselect, + // placeholderText: + // t("actions.filterBy", { + // what: t("terms.analysis").toLowerCase(), + // }) + "...", + // selectOptions: Object.values(applications) + // .map(a => ({ + // value: a?.tasks.currentAnalyzer?.state || "No Task", + // label: a?.tasks.currentAnalyzer?.state || "Not Started", + // })) + // .filter((v, i, a) => a.findIndex(v2 => v2.label === v.label) === i) + // .sort((a, b) => a.value.localeCompare(b.value)), + // getItemValue: (item) => item?.tasks.currentAnalyzer?.state || "No Task", + // } { categoryKey: "analysis", title: t("terms.analysis"), @@ -511,13 +529,18 @@ export const ApplicationsTable: React.FC = () => { t("actions.filterBy", { what: t("terms.analysis").toLowerCase(), }) + "...", - selectOptions: Array.from(taskStateToAnalyze).map(([taskState, displayStatus]) => ({ - value: taskState, // The task state will be the value - label: t(`${displayStatus}`) // The display status translated using t() - })), - - getItemValue: (item) => item?.tasks.currentAnalyzer?.state || - "No task" + selectOptions: Object.values(applications) + .map((a) => { + let value = a?.tasks.currentAnalyzer?.state || "No Task"; + if (value === "No Task") { + value = "No task"; + } + const label = taskStateToAnalyze.get(value as TaskState) || value; + return { value, label }; + }) + .filter((v, i, a) => a.findIndex((v2) => v2.label === v.label) === i) + .sort((a, b) => a.value.localeCompare(b.value)), + getItemValue: (item) => item?.tasks.currentAnalyzer?.state || "No Task", }, ], initialItemsPerPage: 10, @@ -567,48 +590,48 @@ export const ApplicationsTable: React.FC = () => { const importDropdownItems = importWriteAccess ? [ - setIsApplicationImportModalOpen(true)} - > - {t("actions.import")} - , - { - history.push(Paths.applicationsImports); - }} - > - {t("actions.manageImports")} - , - ] + setIsApplicationImportModalOpen(true)} + > + {t("actions.import")} + , + { + history.push(Paths.applicationsImports); + }} + > + {t("actions.manageImports")} + , + ] : []; const applicationDropdownItems = applicationWriteAccess ? [ - { - setApplicationsToDelete(selectedRows); - }} - > - {t("actions.delete")} - , - ...(credentialsReadAccess - ? [ - { - setSaveApplicationsCredentialsModalState(selectedRows); - }} - > - {t("actions.manageCredentials")} - , - ] - : []), - ] + { + setApplicationsToDelete(selectedRows); + }} + > + {t("actions.delete")} + , + ...(credentialsReadAccess + ? [ + { + setSaveApplicationsCredentialsModalState(selectedRows); + }} + > + {t("actions.manageCredentials")} + , + ] + : []), + ] : []; const dropdownItems = [...importDropdownItems, ...applicationDropdownItems]; @@ -997,58 +1020,58 @@ export const ApplicationsTable: React.FC = () => { onClick: () => assessSelectedApp(application), }, assessmentWriteAccess && - (application.assessments?.length ?? 0) > 0 && { - title: t("actions.discardAssessment"), - onClick: () => - setAssessmentToDiscard(application), - }, + (application.assessments?.length ?? 0) > 0 && { + title: t("actions.discardAssessment"), + onClick: () => + setAssessmentToDiscard(application), + }, reviewsWriteAccess && { title: t("actions.review"), onClick: () => reviewSelectedApp(application), }, reviewsWriteAccess && - application?.review && { - title: t("actions.discardReview"), - onClick: () => setReviewToDiscard(application), - }, + application?.review && { + title: t("actions.discardReview"), + onClick: () => setReviewToDiscard(application), + }, dependenciesWriteAccess && { title: t("actions.manageDependencies"), onClick: () => setApplicationDependenciesToManage(application), }, credentialsReadAccess && - applicationWriteAccess && { - title: t("actions.manageCredentials"), - onClick: () => - setSaveApplicationsCredentialsModalState([ - application, - ]), - }, + applicationWriteAccess && { + title: t("actions.manageCredentials"), + onClick: () => + setSaveApplicationsCredentialsModalState([ + application, + ]), + }, analysesReadAccess && - !!application.tasks.currentAnalyzer && { - title: t("actions.analysisDetails"), - onClick: () => { - const taskId = - application.tasks.currentAnalyzer?.id; - if (taskId && application.id) { - history.push( - formatPath( - Paths.applicationsAnalysisDetails, - { - applicationId: application.id, - taskId, - } - ) - ); - } + !!application.tasks.currentAnalyzer && { + title: t("actions.analysisDetails"), + onClick: () => { + const taskId = + application.tasks.currentAnalyzer?.id; + if (taskId && application.id) { + history.push( + formatPath( + Paths.applicationsAnalysisDetails, + { + applicationId: application.id, + taskId, + } + ) + ); + } + }, }, - }, tasksReadAccess && - tasksWriteAccess && - isTaskCancellable(application) && { - title: t("actions.cancelAnalysis"), - onClick: () => cancelAnalysis(application), - }, + tasksWriteAccess && + isTaskCancellable(application) && { + title: t("actions.cancelAnalysis"), + onClick: () => cancelAnalysis(application), + }, applicationWriteAccess && { isSeparator: true }, applicationWriteAccess && { title: t("actions.delete"), @@ -1151,10 +1174,11 @@ export const ApplicationsTable: React.FC = () => { )} titleIconVariant={"warning"} isOpen={applicationsToDelete.length > 0} - message={`${applicationsToDelete.length > 1 - ? t("dialog.message.applicationsBulkDelete") - : "" - } ${t("dialog.message.delete")}`} + message={`${ + applicationsToDelete.length > 1 + ? t("dialog.message.applicationsBulkDelete") + : "" + } ${t("dialog.message.delete")}`} aria-label="Applications bulk delete" confirmBtnVariant={ButtonVariant.danger} confirmBtnLabel={t("actions.delete")}