diff --git a/client/src/app/pages/applications/applications-table-analyze/applications-table-analyze.tsx b/client/src/app/pages/applications/applications-table-analyze/applications-table-analyze.tsx index c6dcece0c9..49047fbcb4 100644 --- a/client/src/app/pages/applications/applications-table-analyze/applications-table-analyze.tsx +++ b/client/src/app/pages/applications/applications-table-analyze/applications-table-analyze.tsx @@ -1,184 +1,162 @@ +// External libraries import * as React from "react"; -import { useHistory } from "react-router-dom"; +import { useState } from "react"; import { AxiosError } from "axios"; +import { useHistory } from "react-router-dom"; import { useTranslation } from "react-i18next"; -import WarningTriangleIcon from "@patternfly/react-icons/dist/esm/icons/warning-triangle-icon"; + +// @patternfly import { + Toolbar, + ToolbarContent, + ToolbarItem, Button, + ToolbarGroup, ButtonVariant, + DropdownItem, + Dropdown, + MenuToggle, + MenuToggleElement, Modal, - ToolbarGroup, - ToolbarItem, - TooltipPosition, } from "@patternfly/react-core"; -import { DropdownItem } from "@patternfly/react-core/deprecated"; import { - cellWidth, - IAction, - ICell, - IExtraData, - IRow, - IRowData, - ISeparator, - nowrap, - sortable, - TableText, + PencilAltIcon, + TagIcon, + EllipsisVIcon, + WarningTriangleIcon, +} from "@patternfly/react-icons"; +import { + Table, + Thead, + Tr, + Th, + Td, + ActionsColumn, } from "@patternfly/react-table"; -import TagIcon from "@patternfly/react-icons/dist/esm/icons/tag-icon"; -import PencilAltIcon from "@patternfly/react-icons/dist/esm/icons/pencil-alt-icon"; -import keycloak from "@app/keycloak"; +// @app components and utilities +import { AppPlaceholder } from "@app/components/AppPlaceholder"; +import { + FilterType, + FilterToolbar, +} from "@app/components/FilterToolbar/FilterToolbar"; +import { SimplePagination } from "@app/components/SimplePagination"; +import { + TableHeaderContentWithControls, + ConditionalTableBody, + TableRowContentWithControls, +} from "@app/components/TableControls"; +import { IconedStatus } from "@app/components/IconedStatus"; +import { ToolbarBulkSelector } from "@app/components/ToolbarBulkSelector"; +import { SimpleDocumentViewerModal } from "@app/components/SimpleDocumentViewer"; +import { getTaskById } from "@app/api/rest"; +import { ConfirmDialog } from "@app/components/ConfirmDialog"; +import { NotificationsContext } from "@app/components/NotificationsContext"; +import { dedupeFunction, getAxiosErrorMessage } from "@app/utils/utils"; import { Paths } from "@app/Paths"; -import { Application, Task } from "@app/api/models"; -import { getAxiosErrorMessage } from "@app/utils/utils"; -import { ApplicationForm } from "../components/application-form"; -import { ApplicationBusinessService } from "../components/application-business-service"; -import { ImportApplicationsForm } from "../components/import-applications-form"; -import { ApplicationAnalysisStatus } from "../components/application-analysis-status"; -import { FilterToolbar } from "@app/components/FilterToolbar"; -import { AnalysisWizard } from "../analysis-wizard/analysis-wizard"; -import { ApplicationIdentityForm } from "../components/application-identity-form/application-identity-form"; -import { useCancelTaskMutation, useFetchTasks } from "@app/queries/tasks"; +import keycloak from "@app/keycloak"; import { - applicationsWriteScopes, - importsWriteScopes, RBAC, RBAC_TYPE, - tasksReadScopes, + applicationsWriteScopes, tasksWriteScopes, + importsWriteScopes, + tasksReadScopes, } from "@app/rbac"; import { checkAccess } from "@app/utils/rbac-utils"; + +// Hooks +import { useLocalTableControls } from "@app/hooks/table-controls"; + +// Queries +import { Application, Task } from "@app/api/models"; import { - useFetchApplications, useBulkDeleteApplicationMutation, - ApplicationsQueryKey, + useFetchApplications, } from "@app/queries/applications"; -import { - ApplicationTableType, - useApplicationsFilterValues, -} from "../applicationsFilter"; -import { ConditionalTooltip } from "@app/components/ConditionalTooltip"; -import { NotificationsContext } from "@app/components/NotificationsContext"; -import { ConfirmDialog } from "@app/components/ConfirmDialog"; -import { ApplicationDetailDrawerAnalysis } from "../components/application-detail-drawer"; -import { useQueryClient } from "@tanstack/react-query"; -import { SimpleDocumentViewerModal } from "@app/components/SimpleDocumentViewer"; -import { getTaskById } from "@app/api/rest"; +import { useCancelTaskMutation, useFetchTasks } from "@app/queries/tasks"; +import { useFetchApplicationAssessments } from "@app/queries/assessments"; +import { useFetchReviews } from "@app/queries/reviews"; +import { useFetchIdentities } from "@app/queries/identities"; +import { useFetchTagCategories } from "@app/queries/tags"; + +// Relative components +import { ApplicationBusinessService } from "../components/application-business-service"; +import { ApplicationDetailDrawerAssessment } from "../components/application-detail-drawer"; +import { ApplicationForm } from "../components/application-form"; +import { ApplicationIdentityForm } from "../components/application-identity-form/application-identity-form"; +import { ImportApplicationsForm } from "../components/import-applications-form"; import { ConditionalRender } from "@app/components/ConditionalRender"; -import { AppPlaceholder } from "@app/components/AppPlaceholder"; -import { AppTableWithControls } from "@app/components/AppTableWithControls"; -import { ToolbarBulkSelector } from "@app/components/ToolbarBulkSelector"; -import { KebabDropdown } from "@app/components/KebabDropdown"; import { NoDataEmptyState } from "@app/components/NoDataEmptyState"; +import { ConditionalTooltip } from "@app/components/ConditionalTooltip"; import { TaskGroupProvider } from "../analysis-wizard/components/TaskGroupContext"; - -const ENTITY_FIELD = "entity"; - -const getRow = (rowData: IRowData): Application => { - return rowData[ENTITY_FIELD]; -}; +import { AnalysisWizard } from "../analysis-wizard/analysis-wizard"; export const ApplicationsTableAnalyze: React.FC = () => { - //RBAC - const token = keycloak.tokenParsed || undefined; - const { t } = useTranslation(); + const history = useHistory(); + const token = keycloak.tokenParsed; + const { pushNotification } = React.useContext(NotificationsContext); - const [isAnalyzeModalOpen, setAnalyzeModalOpen] = React.useState(false); + const [isToolbarKebabOpen, setIsToolbarKebabOpen] = + React.useState(false); - const [saveApplicationsModalState, setSaveApplicationsModalState] = + const [saveApplicationModalState, setSaveApplicationModalState] = React.useState<"create" | Application | null>(null); + const isCreateUpdateApplicationsModalOpen = - saveApplicationsModalState !== null; + saveApplicationModalState !== null; + const createUpdateApplications = - saveApplicationsModalState !== "create" ? saveApplicationsModalState : null; + saveApplicationModalState !== "create" ? saveApplicationModalState : null; - const [ - saveApplicationsCredentialsModalState, - setSaveApplicationsCredentialsModalState, - ] = React.useState<"create" | Application[] | null>(null); - const isCreateUpdateCredentialsModalOpen = - saveApplicationsCredentialsModalState !== null; - const applicationsCredentialsToUpdate = - saveApplicationsCredentialsModalState !== "create" - ? saveApplicationsCredentialsModalState - : null; + const [isAnalyzeModalOpen, setAnalyzeModalOpen] = useState(false); - const [applicationsToDelete, setApplicationsToDelete] = React.useState< + const [applicationsToDelete, setApplicationsToDelete] = useState< Application[] >([]); - const [isApplicationImportModalOpen, setIsApplicationImportModalOpen] = - React.useState(false); + const getTask = (application: Application) => + tasks.find((task: Task) => task.application?.id === application.id); - const [taskToView, setTaskToView] = React.useState<{ - name: string; - task: number | undefined; - }>(); + const { tasks } = useFetchTasks({ addon: "analyzer" }); - // Router - const history = useHistory(); + const { tagCategories: tagCategories } = useFetchTagCategories(); + + const { identities } = useFetchIdentities(); const { data: applications, - isFetching, - error: fetchError, + isFetching: isFetchingApplications, + error: applicationsFetchError, + refetch: fetchApplications, } = useFetchApplications(); - const { - paginationProps, - sortBy, - onSort, - filterCategories, - filterValues, - setFilterValues, - handleOnClearAllFilters, - currentPageItems, - isRowSelected, - toggleRowSelected, - selectAll, - selectMultiple, - areAllSelected, - selectedRows, - openDetailDrawer, - closeDetailDrawer, - activeAppInDetailDrawer, - } = useApplicationsFilterValues(ApplicationTableType.Analysis, applications); - - const { tasks } = useFetchTasks({ addon: "analyzer" }); - - const queryClient = useQueryClient(); - const allTasksComplete = tasks.every((task) => task.state !== "Running"); - - React.useEffect(() => { - queryClient.invalidateQueries({ queryKey: [ApplicationsQueryKey] }); - }, [allTasksComplete]); - - const completedCancelTask = () => { + const onDeleteApplicationSuccess = (appIDCount: number) => { pushNotification({ - title: "Task", - message: "Canceled", - variant: "info", + title: t("toastr.success.applicationDeleted", { + appIDCount: appIDCount, + }), + variant: "success", }); + clearActiveRow(); + setApplicationsToDelete([]); }; - const failedCancelTask = () => { + const onDeleteApplicationError = (error: AxiosError) => { pushNotification({ - title: "Task", - message: "Cancelation failed.", + title: getAxiosErrorMessage(error), variant: "danger", }); + setApplicationsToDelete([]); }; - const { mutate: cancelTask } = useCancelTaskMutation( - completedCancelTask, - failedCancelTask + const { mutate: bulkDeleteApplication } = useBulkDeleteApplicationMutation( + onDeleteApplicationSuccess, + onDeleteApplicationError ); - const getTask = (application: Application) => - tasks.find((task: Task) => task.application?.id === application.id); - const isTaskCancellable = (application: Application) => { const task = getTask(application); if (task?.state && task.state.match(/(Created|Running|Ready|Pending)/)) @@ -186,205 +164,215 @@ export const ApplicationsTableAnalyze: React.FC = () => { return false; }; - // Delete + const cancelAnalysis = (row: Application) => { + const task = tasks.find((task) => task.application?.id === row.id); + if (task?.id) cancelTask(task.id); + }; - const onDeleteApplicationSuccess = (appIDCount: number) => { + const completedCancelTask = () => { pushNotification({ - title: t("toastr.success.applicationDeleted", { - appIDCount: appIDCount, - }), - variant: "success", + title: "Task", + message: "Canceled", + variant: "info", }); - activeAppInDetailDrawer && closeDetailDrawer(); - setApplicationsToDelete([]); }; - const onDeleteApplicationError = (error: AxiosError) => { + const failedCancelTask = () => { pushNotification({ - title: getAxiosErrorMessage(error), + title: "Task", + message: "Cancelation failed.", variant: "danger", }); - setApplicationsToDelete([]); }; - const { mutate: bulkDeleteApplication } = useBulkDeleteApplicationMutation( - onDeleteApplicationSuccess, - onDeleteApplicationError + const { mutate: cancelTask } = useCancelTaskMutation( + completedCancelTask, + failedCancelTask ); - // Table - const columns: ICell[] = [ - { - title: t("terms.name"), - transforms: [sortable, cellWidth(20)], - }, - { title: t("terms.description"), transforms: [cellWidth(25)] }, - { - title: t("terms.businessService"), - transforms: [sortable, cellWidth(20)], - }, - { - title: t("terms.analysis"), - transforms: [cellWidth(10)], - cellTransforms: [nowrap], - }, - { - title: t("terms.tagCount"), - transforms: [sortable, cellWidth(10)], - cellTransforms: [nowrap], + const { getApplicationAssessment } = + useFetchApplicationAssessments(applications); + + const tableControls = useLocalTableControls({ + idProperty: "id", + items: applications || [], + columnNames: { + name: "Name", + description: "Description", + businessService: "Business Service", + analysis: "Analysis", + tags: "Tags", }, - { - title: "", - props: { - className: "pf-v5-c-table__inline-edit-action", + sortableColumns: ["name", "description", "businessService", "tags"], + initialSort: { columnKey: "name", direction: "asc" }, + filterCategories: [ + { + key: "name", + title: t("terms.name"), + type: FilterType.search, + placeholderText: + t("actions.filterBy", { + what: t("terms.name").toLowerCase(), + }) + "...", + getItemValue: (item) => item?.name || "", }, - }, - ]; - - const getTaskState = (application: Application) => { - const task = getTask(application); - if (task && task.state) return task.state; - return "No task"; - }; - - const rows: IRow[] = []; - currentPageItems?.forEach((item) => { - const isSelected = isRowSelected(item); - - rows.push({ - [ENTITY_FIELD]: item, - selected: isSelected, - isClickable: true, - isRowSelected: activeAppInDetailDrawer?.id === item.id, - cells: [ - { - title: {item.name}, - }, - { - title: ( - {item.description} - ), - }, - { - title: ( - - {item.businessService && ( - - )} - - ), - }, - { - title: ( - <> - {item.id && ( - - )} - - ), + { + key: "description", + title: t("terms.description"), + type: FilterType.search, + placeholderText: + t("actions.filterBy", { + what: t("terms.description").toLowerCase(), + }) + "...", + getItemValue: (item) => item.description || "", + }, + { + key: "businessService", + title: t("terms.businessService"), + placeholderText: + t("actions.filterBy", { + what: t("terms.businessService").toLowerCase(), + }) + "...", + type: FilterType.select, + selectOptions: dedupeFunction( + applications + .filter((app) => !!app.businessService?.name) + .map((app) => app.businessService?.name) + .map((name) => ({ key: name, value: name })) + ), + getItemValue: (item) => item.businessService?.name || "", + }, + { + key: "identities", + title: t("terms.credentialType"), + placeholderText: + t("actions.filterBy", { + what: t("terms.credentialType").toLowerCase(), + }) + "...", + type: FilterType.multiselect, + selectOptions: [ + { key: "source", value: "Source" }, + { key: "maven", value: "Maven" }, + { key: "proxy", value: "Proxy" }, + ], + getItemValue: (item) => { + const searchStringArr: string[] = []; + item.identities?.forEach((appIdentity) => { + const matchingIdentity = identities.find( + (identity) => identity.id === appIdentity.id + ); + searchStringArr.push(matchingIdentity?.kind || ""); + }); + const searchString = searchStringArr.join(""); + return searchString; }, - { - title: ( - <> - {item.tags ? item.tags.length : 0} - - ), + }, + { + key: "repository", + title: t("terms.repositoryType"), + placeholderText: + t("actions.filterBy", { + what: t("terms.repositoryType").toLowerCase(), + }) + "...", + type: FilterType.select, + selectOptions: [ + { key: "git", value: "Git" }, + { key: "subversion", value: "Subversion" }, + ], + getItemValue: (item) => item?.repository?.kind || "", + }, + { + key: "binary", + title: t("terms.artifact"), + placeholderText: + t("actions.filterBy", { + what: t("terms.artifact").toLowerCase(), + }) + "...", + type: FilterType.select, + selectOptions: [ + { key: "binary", value: t("terms.artifactAssociated") }, + { key: "none", value: t("terms.artifactNotAssociated") }, + ], + getItemValue: (item) => { + const hasBinary = + item.binary !== "::" && item.binary?.match(/.+:.+:.+/) + ? "binary" + : "none"; + + return hasBinary; }, - { - title: ( - - - - ), + }, + { + key: "tags", + title: t("terms.tags"), + type: FilterType.multiselect, + placeholderText: + t("actions.filterBy", { + what: t("terms.tagName").toLowerCase(), + }) + "...", + getItemValue: (item) => { + const tagNames = item?.tags?.map((tag) => tag.name).join(""); + return tagNames || ""; }, - ], - }); + selectOptions: dedupeFunction( + tagCategories + ?.map((tagCategory) => tagCategory?.tags) + .flat() + .filter((tag) => tag && tag.name) + .map((tag) => ({ key: tag?.name, value: tag?.name })) + ), + }, + ], + initialItemsPerPage: 10, + hasActionsColumn: true, + isSelectable: true, }); - const actionResolver = (rowData: IRowData): (IAction | ISeparator)[] => { - const row: Application = getRow(rowData); - if (!row) { - return []; - } - - const actions: (IAction | ISeparator)[] = []; - const userScopes: string[] = token?.scope.split(" ") || [], - applicationWriteAccess = checkAccess(userScopes, applicationsWriteScopes), - tasksReadAccess = checkAccess(userScopes, tasksReadScopes), - tasksWriteAccess = checkAccess(userScopes, tasksWriteScopes); - - if (applicationWriteAccess) { - actions.push( - { - title: "Manage credentials", - onClick: () => setSaveApplicationsCredentialsModalState([row]), - }, - { - title: t("actions.delete"), - ...(row.migrationWave !== null && { - isAriaDisabled: true, - tooltipProps: { - position: TooltipPosition.top, - content: - "Cannot delete application assigned to a migration wave.", - }, - }), - onClick: () => setApplicationsToDelete([row]), - } - ); - } - - if (tasksReadAccess) { - actions.push({ - title: t("actions.analysisDetails"), - "aria-disabled": !getTask(row), - onClick: () => { - const task = getTask(row); - if (task) setTaskToView({ name: row.name, task: task.id }); - }, - }); - } - - if (tasksWriteAccess) { - actions.push({ - title: "Cancel analysis", - "aria-disabled": !isTaskCancellable(row), - onClick: () => cancelAnalysis(row), - }); - } - - return actions; - }; + const { + currentPageItems, + numRenderedColumns, + propHelpers: { + toolbarProps, + filterToolbarProps, + paginationToolbarItemProps, + paginationProps, + tableProps, + getThProps, + getTdProps, + toolbarBulkSelectorProps, + getClickableTrProps, + }, + activeRowDerivedState: { activeRowItem, clearActiveRow }, - // Row actions - const selectRow = ( - _event: React.FormEvent, - _isSelected: boolean, - _rowIndex: number, - rowData: IRowData, - _extraData: IExtraData - ) => { - const row = getRow(rowData); - toggleRowSelected(row); - }; + selectionState: { selectedItems: selectedRows }, + } = tableControls; - const cancelAnalysis = (row: Application) => { - const task = tasks.find((task) => task.application?.id === row.id); - if (task?.id) cancelTask(task.id); - }; + const { reviews } = useFetchReviews(); + + const [ + saveApplicationsCredentialsModalState, + setSaveApplicationsCredentialsModalState, + ] = useState<"create" | Application[] | null>(null); + const isCreateUpdateCredentialsModalOpen = + saveApplicationsCredentialsModalState !== null; + const applicationsCredentialsToUpdate = + saveApplicationsCredentialsModalState !== "create" + ? saveApplicationsCredentialsModalState + : null; + + const [isApplicationImportModalOpen, setIsApplicationImportModalOpen] = + useState(false); + + const [taskToView, setTaskToView] = useState<{ + name: string; + task: number | undefined; + }>(); const userScopes: string[] = token?.scope.split(" ") || [], importWriteAccess = checkAccess(userScopes, importsWriteScopes), - applicationWriteAccess = checkAccess(userScopes, applicationsWriteScopes); + applicationWriteAccess = checkAccess(userScopes, applicationsWriteScopes), + tasksReadAccess = checkAccess(userScopes, tasksReadScopes), + tasksWriteAccess = checkAccess(userScopes, tasksWriteScopes); const areAppsInWaves = selectedRows.some( (application) => application.migrationWave !== null @@ -465,75 +453,41 @@ export const ApplicationsTableAnalyze: React.FC = () => { const hasExistingAnalysis = selectedRows.some((app) => tasks.some((task) => task.application?.id === app.id) ); + return ( - <> - } + } + > +
- { - if (activeAppInDetailDrawer === application) { - closeDetailDrawer(); - } else { - openDetailDrawer(application); - } - }} - toolbarToggle={ - {`${selectedRows.length} selected`} - } - /> - } - toolbarBulkSelector={ - - } - toolbarClearAllFilters={handleOnClearAllFilters} - toolbarActions={ - <> - + + + + + + - - - + + + { - {dropdownItems.length ? ( - - - - ) : ( - <> - )} - - - } - noDataState={ - - } + + {dropdownItems.length ? ( + + setIsToolbarKebabOpen(false)} + onOpenChange={(_isOpen) => setIsToolbarKebabOpen(false)} + toggle={(toggleRef: React.Ref) => ( + + setIsToolbarKebabOpen(!isToolbarKebabOpen) + } + isExpanded={isToolbarKebabOpen} + > + + + )} + shouldFocusToggleOnSelect + > + {dropdownItems} + + + ) : ( + <> + )} + + + + + + + + + + + + + + + } + numRenderedColumns={numRenderedColumns} + > + {currentPageItems?.map((application, rowIndex) => { + const actionItems = []; + + if (applicationWriteAccess) { + actionItems.push( + { + title: "Manage credentials", + onClick: () => + setSaveApplicationsCredentialsModalState([application]), + }, + { + title: t("actions.delete"), + onClick: () => setApplicationsToDelete([application]), + } + ); + } + + if (tasksReadAccess) { + actionItems.push({ + title: t("actions.analysisDetails"), + "aria-disabled": !getTask(application), + onClick: () => { + const task = getTask(application); + if (task) + setTaskToView({ name: application.name, task: task.id }); + }, + }); + } + + if (tasksWriteAccess) { + actionItems.push({ + title: "Cancel analysis", + "aria-disabled": !isTaskCancellable(application), + onClick: () => cancelAnalysis(application), + }); + } + + return ( + + + + + + + + + + + + ); + })} + +
+ + + + + +
+ {application.name} + + {application.description} + + {application.businessService && ( + + )} + + + + + {application.tags ? application.tags.length : 0} + + + +
+ - - - setSaveApplicationsModalState(null)} - > - setSaveApplicationsModalState(null)} - /> - {" "} - - { - setAnalyzeModalOpen(false); - }} - /> - - setIsApplicationImportModalOpen(false)} - > - { - setIsApplicationImportModalOpen(false); - selectAll(false); + + 1 + ? "dialog.title.delete" + : "dialog.title.deleteWithName", + { + what: + applicationsToDelete.length > 1 + ? t("terms.application(s)").toLowerCase() + : t("terms.application").toLowerCase(), + name: + applicationsToDelete.length === 1 && + applicationsToDelete[0].name, + } + )} + titleIconVariant={"warning"} + isOpen={applicationsToDelete.length > 0} + message={`${ + applicationsToDelete.length > 1 + ? t("dialog.message.applicationsBulkDelete") + : "" + } ${t("dialog.message.delete")}`} + aria-label="Applications bulk delete" + confirmBtnVariant={ButtonVariant.danger} + confirmBtnLabel={t("actions.delete")} + cancelBtnLabel={t("actions.cancel")} + onCancel={() => setApplicationsToDelete([])} + onClose={() => setApplicationsToDelete([])} + onConfirm={() => { + const ids = applicationsToDelete + .filter((application) => application.id) + .map((application) => application.id); + if (ids) bulkDeleteApplication({ ids: ids }); }} /> - - setSaveApplicationsCredentialsModalState(null)} - > - {applicationsCredentialsToUpdate && ( - setSaveApplicationsCredentialsModalState(null)} + + { + setAnalyzeModalOpen(false); + }} /> - )} - - 1 - ? "dialog.title.delete" - : "dialog.title.deleteWithName", - { - what: - applicationsToDelete.length > 1 - ? t("terms.application(s)").toLowerCase() - : t("terms.application").toLowerCase(), - name: - applicationsToDelete.length === 1 && applicationsToDelete[0].name, + + setSaveApplicationsCredentialsModalState(null)} + > + {applicationsCredentialsToUpdate && ( + setSaveApplicationsCredentialsModalState(null)} + /> + )} + + 0} - message={`${ - applicationsToDelete.length > 1 - ? t("dialog.message.applicationsBulkDelete") - : "" - } ${t("dialog.message.delete")}`} - aria-label="Applications bulk delete" - confirmBtnVariant={ButtonVariant.danger} - confirmBtnLabel={t("actions.delete")} - cancelBtnLabel={t("actions.cancel")} - onCancel={() => setApplicationsToDelete([])} - onClose={() => setApplicationsToDelete([])} - onConfirm={() => { - const ids = applicationsToDelete - .filter((application) => application.id) - .map((application) => application.id); - if (ids) bulkDeleteApplication({ ids: ids }); - }} - /> - - title={`Analysis details for ${taskToView?.name}`} - fetch={getTaskById} - documentId={taskToView?.task} - onClose={() => setTaskToView(undefined)} - /> - + variant="medium" + isOpen={isCreateUpdateApplicationsModalOpen} + onClose={() => setSaveApplicationModalState(null)} + > + setSaveApplicationModalState(null)} + /> + + + title={`Analysis details for ${taskToView?.name}`} + fetch={getTaskById} + documentId={taskToView?.task} + onClose={() => setTaskToView(undefined)} + /> + setIsApplicationImportModalOpen((current) => !current)} + > + { + setIsApplicationImportModalOpen(false); + fetchApplications(); + }} + /> + +
+
); }; diff --git a/client/src/app/pages/applications/applications-table-assessment/applications-table-assessment.tsx b/client/src/app/pages/applications/applications-table-assessment/applications-table-assessment.tsx index 1aa1bf26c7..378cba3b8a 100644 --- a/client/src/app/pages/applications/applications-table-assessment/applications-table-assessment.tsx +++ b/client/src/app/pages/applications/applications-table-assessment/applications-table-assessment.tsx @@ -71,7 +71,6 @@ import { Application, Assessment, Task } from "@app/api/models"; import { ApplicationsQueryKey, useBulkDeleteApplicationMutation, - useDeleteApplicationMutation, useFetchApplications, } from "@app/queries/applications"; import { useFetchTasks } from "@app/queries/tasks"; @@ -102,7 +101,6 @@ export const ApplicationsTable: React.FC = () => { const { pushNotification } = React.useContext(NotificationsContext); - const [isKebabOpen, setIsKebabOpen] = React.useState(null); const [isToolbarKebabOpen, setIsToolbarKebabOpen] = React.useState(false);