From c08d206bc419d829bbeca66c9d0c12ef6cbebb33 Mon Sep 17 00:00:00 2001 From: esty Date: Tue, 17 Sep 2024 16:39:55 +0300 Subject: [PATCH 1/5] Add Tasks tab to the Applications table Signed-off-by: EstyBiton --- .../application-detail-drawer.tsx | 203 ++++++++++++++++++ 1 file changed, 203 insertions(+) diff --git a/client/src/app/pages/applications/components/application-detail-drawer/application-detail-drawer.tsx b/client/src/app/pages/applications/components/application-detail-drawer/application-detail-drawer.tsx index 882578b58e..4b9f165355 100644 --- a/client/src/app/pages/applications/components/application-detail-drawer/application-detail-drawer.tsx +++ b/client/src/app/pages/applications/components/application-detail-drawer/application-detail-drawer.tsx @@ -65,6 +65,30 @@ import { useFetchArchetypes } from "@app/queries/archetypes"; import { useFetchAssessments } from "@app/queries/assessments"; import { DecoratedApplication } from "../../applications-table/useDecoratedApplications"; import { TaskStates } from "@app/queries/tasks"; +//for tasks table +import { + PageSection, + Toolbar, + ToolbarContent, + ToolbarItem, +} from "@patternfly/react-core"; +import { Table, Tbody, Td, Th, Thead, Tr } from "@patternfly/react-table"; +import { + useTableControlState, + useTableControlProps, +} from "@app/hooks/table-controls"; +import { SimplePagination } from "@app/components/SimplePagination"; +import { useServerTasks } from "@app/queries/tasks"; +import { FilterToolbar, FilterType } from "@app/components/FilterToolbar"; +import { + getHubRequestParams, + deserializeFilterUrlParams, +} from "@app/hooks/table-controls"; +import { useSelectionState } from "@migtools/lib-ui"; +import { TablePersistenceKeyPrefix } from "@app/Constants"; +import { useSharedAffectedApplicationFilterCategories } from "../../../issues/helpers"; +//for the icon +import { TaskActionColumn } from "../../../../pages/tasks/TaskActionColumn"; export interface IApplicationDetailDrawerProps extends Pick { @@ -79,6 +103,7 @@ enum TabKey { Reports, Facts, Reviews, + Tasks, } export const ApplicationDetailDrawer: React.FC< @@ -152,6 +177,14 @@ export const ApplicationDetailDrawer: React.FC< )} + {!application ? null : ( + {t("terms.Tasks")}} + > + + + )} @@ -521,3 +554,173 @@ const TabReportsContent: React.FC<{ ); }; + +const TabTasksContent: React.FC<{}> = () => { + const { t } = useTranslation(); + + const allAffectedApplicationsFilterCategories = + useSharedAffectedApplicationFilterCategories(); + + const urlParams = new URLSearchParams(window.location.search); + const filters = urlParams.get("filters"); + const deserializedFilterValues = deserializeFilterUrlParams({ filters }); + + const tableControlState = useTableControlState({ + tableName: "tasks-table", + persistTo: "urlParams", + persistenceKeyPrefix: TablePersistenceKeyPrefix.tasks, + columnNames: { + taskId: "Task ID", + taskKind: "Task Kind", + status: "Status", + priority: "Priority", + action: "action", + }, + initialFilterValues: deserializedFilterValues, + isFilterEnabled: true, + isSortEnabled: true, + isPaginationEnabled: true, + initialItemsPerPage: 10, + sortableColumns: ["taskId", "taskKind", "status", "priority"], + initialSort: { columnKey: "taskId", direction: "asc" }, + filterCategories: [ + ...allAffectedApplicationsFilterCategories, + { + categoryKey: "taskId", + title: t("Task ID"), + type: FilterType.search, + filterGroup: "Task", + placeholderText: t("Filter by Task ID"), + getServerFilterValue: (value) => (value ? [`*${value[0]}*`] : []), + }, + { + categoryKey: "taskKind", + title: t("Task Kind"), + type: FilterType.search, + filterGroup: "Task", + placeholderText: t("Filter by Task Kind"), + getServerFilterValue: (value) => (value ? [`*${value[0]}*`] : []), + }, + { + categoryKey: "status", + title: t("Status"), + type: FilterType.search, + filterGroup: "Task", + placeholderText: t("Filter by Status"), + getServerFilterValue: (value) => (value ? [`*${value[0]}*`] : []), + }, + ], + }); + + const { + result: { data: currentPageItems, total: totalItemCount }, + isFetching, + } = useServerTasks( + getHubRequestParams({ + ...tableControlState, + hubSortFieldKeys: { + taskId: "taskId", + taskKind: "taskKind", + status: "status", + priority: "priority", + }, + }) + ); + + const tableControls = useTableControlProps({ + ...tableControlState, // Includes filterState, sortState and paginationState + idProperty: "id", + currentPageItems, + totalItemCount, + isLoading: isFetching, + selectionState: useSelectionState({ + items: currentPageItems, + isEqual: (a, b) => a.name === b.name, + }), + }); + + const { + propHelpers: { + toolbarProps, + filterToolbarProps, + paginationProps, + tableProps, + getThProps, + getTdProps, + getTrProps, + }, + } = tableControls; + + const history = useHistory(); + + const clearFilters = () => { + const currentPath = history.location.pathname; + const newSearch = new URLSearchParams(history.location.search); + newSearch.delete("filters"); + history.push(`${currentPath}`); + }; + + return ( + <> + + + + + + + + + + + + + + + + + + + + + + + {currentPageItems?.map((task) => ( + + + + {" "} + {/*check if state=status*/} + + + + ))} + +
{t("Task ID")} + {t("Task Kind")} + {t("Status")} + {t("Priority")} +
{task.id}{task.kind} + {task.state} + + {task.priority} + + {" "} +
+ + +
+ + ); +}; From 7fc6cbb32c7cca5aca7d0f20877a63bd1ae1cb29 Mon Sep 17 00:00:00 2001 From: esty Date: Wed, 25 Sep 2024 14:33:31 +0300 Subject: [PATCH 2/5] breadcrumb navigation back to the application table Signed-off-by: esty Signed-off-by: EstyBiton --- client/src/app/Paths.ts | 3 ++ .../application-detail-drawer.tsx | 14 +++++---- .../src/app/pages/tasks/TaskActionColumn.tsx | 12 ++++++-- client/src/app/pages/tasks/TaskDetails.tsx | 30 ++++++++++++++++--- client/src/app/pages/tasks/tasks-page.tsx | 9 +++++- client/src/app/pages/tasks/useTaskActions.tsx | 18 +++++++++-- 6 files changed, 72 insertions(+), 14 deletions(-) diff --git a/client/src/app/Paths.ts b/client/src/app/Paths.ts index 8bd2e6f1d0..357407b183 100644 --- a/client/src/app/Paths.ts +++ b/client/src/app/Paths.ts @@ -42,6 +42,9 @@ export const DevPaths = { dependencies: "/dependencies", tasks: "/tasks", taskDetails: "/tasks/:taskId", + //bread + applicationsTabTaskDetails: "/applications/:taskId", + // taskDetailsAttachment: "/tasks/:taskId/attachments/:attachmentId", } as const; diff --git a/client/src/app/pages/applications/components/application-detail-drawer/application-detail-drawer.tsx b/client/src/app/pages/applications/components/application-detail-drawer/application-detail-drawer.tsx index 4b9f165355..1e6536820d 100644 --- a/client/src/app/pages/applications/components/application-detail-drawer/application-detail-drawer.tsx +++ b/client/src/app/pages/applications/components/application-detail-drawer/application-detail-drawer.tsx @@ -97,7 +97,7 @@ export interface IApplicationDetailDrawerProps onEditClick: () => void; } -enum TabKey { +export enum TabKey { Details = 0, Tags, Reports, @@ -557,6 +557,9 @@ const TabReportsContent: React.FC<{ const TabTasksContent: React.FC<{}> = () => { const { t } = useTranslation(); + //path + + const isFApplication = true; const allAffectedApplicationsFilterCategories = useSharedAffectedApplicationFilterCategories(); @@ -696,9 +699,7 @@ const TabTasksContent: React.FC<{}> = () => { {task.id} {task.kind} - - {task.state} - {" "} + {task.state} {/*check if state=status*/} {task.priority} @@ -708,7 +709,10 @@ const TabTasksContent: React.FC<{}> = () => { isActionCell id={`row-actions-${task.id}`} > - {" "} + {" "} ))} diff --git a/client/src/app/pages/tasks/TaskActionColumn.tsx b/client/src/app/pages/tasks/TaskActionColumn.tsx index 0f99d035e8..c55d9a737e 100644 --- a/client/src/app/pages/tasks/TaskActionColumn.tsx +++ b/client/src/app/pages/tasks/TaskActionColumn.tsx @@ -3,8 +3,16 @@ import React, { FC } from "react"; import { Task } from "@app/api/models"; import { ActionsColumn } from "@patternfly/react-table"; import { useTaskActions } from "./useTaskActions"; +//path +export interface TaskActionColumnProps { + task: Task; + isFApplication: boolean; +} -export const TaskActionColumn: FC<{ task: Task }> = ({ task }) => { - const actions = useTaskActions(task); +export const TaskActionColumn: FC = ({ + task, + isFApplication, +}) => { + const actions = useTaskActions(task, isFApplication); return ; }; diff --git a/client/src/app/pages/tasks/TaskDetails.tsx b/client/src/app/pages/tasks/TaskDetails.tsx index 86381a285c..5207a122c1 100644 --- a/client/src/app/pages/tasks/TaskDetails.tsx +++ b/client/src/app/pages/tasks/TaskDetails.tsx @@ -6,17 +6,39 @@ import { Paths, TaskDetailsAttachmentRoute } from "@app/Paths"; import "@app/components/simple-document-viewer/SimpleDocumentViewer.css"; import { formatPath } from "@app/utils/utils"; import { TaskDetailsBase } from "./TaskDetailsBase"; +//path +import { TaskActionColumnProps } from "./TaskActionColumn"; +//path +import { useFetchApplicationById } from "@app/queries/applications"; +import { AnalysisDetailsAttachmentRoute } from "@app/Paths"; +import { TabKey } from "../applications/components/application-detail-drawer/application-detail-drawer"; -export const TaskDetails = () => { +const { applicationId } = useParams(); +const detailsPath = formatPath(Paths.applicationsAnalysisDetails, { + applicationId: applicationId, +}); +const { application } = useFetchApplicationById(applicationId); + +export const TaskDetails = (isFApplication: TaskActionColumnProps) => { const { t } = useTranslation(); + //bread + const appName: string = application?.name ?? t("terms.unknown"); + const { taskId, attachmentId } = useParams(); - const detailsPath = formatPath(Paths.taskDetails, { taskId }); + const detailsPath = isFApplication + ? formatPath(Paths.applicationsTabTaskDetails, { taskId }) + : formatPath(Paths.taskDetails, { taskId }); return ( { : "", }); + //path + + const isFApplication = false; + return ( <> @@ -356,7 +360,10 @@ export const TasksPage: React.FC = () => { isActionCell id={`row-actions-${task.id}`} > - + diff --git a/client/src/app/pages/tasks/useTaskActions.tsx b/client/src/app/pages/tasks/useTaskActions.tsx index bfcd70c288..bdbb839bf5 100644 --- a/client/src/app/pages/tasks/useTaskActions.tsx +++ b/client/src/app/pages/tasks/useTaskActions.tsx @@ -10,6 +10,7 @@ import { useTranslation } from "react-i18next"; import { useHistory } from "react-router-dom"; import { formatPath } from "@app/utils/utils"; import { Paths } from "@app/Paths"; +/*breadcrumbs*/ const canCancel = (state: TaskState = "No task") => !["Succeeded", "Failed", "Canceled"].includes(state); @@ -60,8 +61,8 @@ const useAsyncTaskActions = () => { return { cancelTask, togglePreemption }; }; - -export const useTaskActions = (task: Task) => { +//? +export const useTaskActions = (task: Task, isFApplication?: boolean) => { const { cancelTask, togglePreemption } = useAsyncTaskActions(); const { t } = useTranslation(); const history = useHistory(); @@ -88,5 +89,18 @@ export const useTaskActions = (task: Task) => { }) ), }, + // { + // title:t("actions.taskDetails"), + // onClick: () => { + // /* we check if drawer open*/ + // history.push( + // formatPath( + // isFApplication ? Paths.applicationsTabTaskDetails : Paths.taskDetails, + // { taskId: task.id } + // ) + // ); + + // }, + // }, ]; }; From 48565dae90266c48b1f1b061777062a9a1420cea Mon Sep 17 00:00:00 2001 From: esty Date: Thu, 26 Sep 2024 13:19:36 +0300 Subject: [PATCH 3/5] Update breadcrumbs for improved navigation Signed-off-by: EstyBiton --- client/src/app/Paths.ts | 6 +++--- client/src/app/hooks/table-controls/types.ts | 1 + .../applications-table/applications-table.tsx | 1 + client/src/app/pages/tasks/TaskDetails.tsx | 19 +++++++++---------- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/client/src/app/Paths.ts b/client/src/app/Paths.ts index 357407b183..b9559ad89d 100644 --- a/client/src/app/Paths.ts +++ b/client/src/app/Paths.ts @@ -42,9 +42,9 @@ export const DevPaths = { dependencies: "/dependencies", tasks: "/tasks", taskDetails: "/tasks/:taskId", - //bread - applicationsTabTaskDetails: "/applications/:taskId", - // + /*bread + applicationsTabTaskDetails: "/applications/:taskId", + */ taskDetailsAttachment: "/tasks/:taskId/attachments/:attachmentId", } as const; diff --git a/client/src/app/hooks/table-controls/types.ts b/client/src/app/hooks/table-controls/types.ts index 38b8e00b8a..0b4f994842 100644 --- a/client/src/app/hooks/table-controls/types.ts +++ b/client/src/app/hooks/table-controls/types.ts @@ -58,6 +58,7 @@ import { IColumnState } from "./column/useColumnState"; export type TableFeature = | "filter" | "sort" + | "tabKey" | "pagination" | "selection" | "expansion" 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..396a920ae2 100644 --- a/client/src/app/pages/applications/applications-table/applications-table.tsx +++ b/client/src/app/pages/applications/applications-table/applications-table.tsx @@ -330,6 +330,7 @@ export const ApplicationsTable: React.FC = () => { isActiveItemEnabled: true, persistTo: { activeItem: "urlParams", + tabKey: "urlParams", filter: "urlParams", pagination: "sessionStorage", sort: "sessionStorage", diff --git a/client/src/app/pages/tasks/TaskDetails.tsx b/client/src/app/pages/tasks/TaskDetails.tsx index 5207a122c1..7273c14503 100644 --- a/client/src/app/pages/tasks/TaskDetails.tsx +++ b/client/src/app/pages/tasks/TaskDetails.tsx @@ -21,13 +21,11 @@ const { application } = useFetchApplicationById(applicationId); export const TaskDetails = (isFApplication: TaskActionColumnProps) => { const { t } = useTranslation(); - //bread + /*bread*/ const appName: string = application?.name ?? t("terms.unknown"); const { taskId, attachmentId } = useParams(); - const detailsPath = isFApplication - ? formatPath(Paths.applicationsTabTaskDetails, { taskId }) - : formatPath(Paths.taskDetails, { taskId }); + const detailsPath = formatPath(Paths.taskDetails, { taskId }); return ( { title: t(isFApplication ? "terms.applications" : "terms.tasks"), path: isFApplication ? Paths.applications : Paths.tasks, }, - - { - title: appName, - path: `${Paths.applications}/?activeItem=${applicationId}&TabKey=${TabKey.Tasks}`, - }, + isFApplication + ? { + title: appName, + path: `${Paths.applications}/?activeItem=${applicationId}&tabKey=${TabKey.Tasks}`, + } + : null, { title: t("titles.taskWithId", { taskId }), path: detailsPath, }, - ]} + ].filter(Boolean)} detailsPath={detailsPath} formatTitle={(taskName) => `Task details for task ${taskId}, ${taskName}`} formatAttachmentPath={(attachmentId) => From fc085f37360c83d45329937f89987694f719d9bd Mon Sep 17 00:00:00 2001 From: EstyBiton Date: Tue, 8 Oct 2024 14:55:37 +0300 Subject: [PATCH 4/5] Add Tasks tab to the Applications table application details drawer Signed-off-by: EstyBiton --- client/src/app/Paths.ts | 8 +- .../task-manager/TaskManagerDrawer.tsx | 3 +- client/src/app/hooks/table-controls/types.ts | 1 - .../applications-table/applications-table.tsx | 1 - .../application-detail-drawer.tsx | 245 ++++++++++-------- .../src/app/pages/tasks/TaskActionColumn.tsx | 7 +- client/src/app/pages/tasks/TaskDetails.tsx | 49 ++-- client/src/app/pages/tasks/tasks-page.tsx | 6 +- client/src/app/pages/tasks/useTaskActions.tsx | 19 +- 9 files changed, 181 insertions(+), 158 deletions(-) diff --git a/client/src/app/Paths.ts b/client/src/app/Paths.ts index b9559ad89d..f40b056445 100644 --- a/client/src/app/Paths.ts +++ b/client/src/app/Paths.ts @@ -41,10 +41,7 @@ export const DevPaths = { dependencies: "/dependencies", tasks: "/tasks", - taskDetails: "/tasks/:taskId", - /*bread - applicationsTabTaskDetails: "/applications/:taskId", - */ + taskDetails: "/tasks/:taskId/:isFApplication", taskDetailsAttachment: "/tasks/:taskId/attachments/:attachmentId", } as const; @@ -112,3 +109,6 @@ export interface TaskDetailsAttachmentRoute { taskId: string; attachmentId: string; } +export interface TaskFromApp { + isFApplication: string; +} diff --git a/client/src/app/components/task-manager/TaskManagerDrawer.tsx b/client/src/app/components/task-manager/TaskManagerDrawer.tsx index 10824bc16e..21bba41fd3 100644 --- a/client/src/app/components/task-manager/TaskManagerDrawer.tsx +++ b/client/src/app/components/task-manager/TaskManagerDrawer.tsx @@ -163,7 +163,8 @@ const TaskItem: React.FC<{ : `${task.id} (${task.addon}) - ${task.applicationName} - ${ task.priority ?? 0 }`; - const taskActionItems = useTaskActions(task._); + + const taskActionItems = useTaskActions(task._, false); return ( { isActiveItemEnabled: true, persistTo: { activeItem: "urlParams", - tabKey: "urlParams", filter: "urlParams", pagination: "sessionStorage", sort: "sessionStorage", diff --git a/client/src/app/pages/applications/components/application-detail-drawer/application-detail-drawer.tsx b/client/src/app/pages/applications/components/application-detail-drawer/application-detail-drawer.tsx index 1e6536820d..271a641ed8 100644 --- a/client/src/app/pages/applications/components/application-detail-drawer/application-detail-drawer.tsx +++ b/client/src/app/pages/applications/components/application-detail-drawer/application-detail-drawer.tsx @@ -65,13 +65,7 @@ import { useFetchArchetypes } from "@app/queries/archetypes"; import { useFetchAssessments } from "@app/queries/assessments"; import { DecoratedApplication } from "../../applications-table/useDecoratedApplications"; import { TaskStates } from "@app/queries/tasks"; -//for tasks table -import { - PageSection, - Toolbar, - ToolbarContent, - ToolbarItem, -} from "@patternfly/react-core"; +import { Toolbar, ToolbarContent, ToolbarItem } from "@patternfly/react-core"; import { Table, Tbody, Td, Th, Thead, Tr } from "@patternfly/react-table"; import { useTableControlState, @@ -86,9 +80,12 @@ import { } from "@app/hooks/table-controls"; import { useSelectionState } from "@migtools/lib-ui"; import { TablePersistenceKeyPrefix } from "@app/Constants"; -import { useSharedAffectedApplicationFilterCategories } from "../../../issues/helpers"; -//for the icon import { TaskActionColumn } from "../../../../pages/tasks/TaskActionColumn"; +import { + ConditionalTableBody, + TableHeaderContentWithControls, + TableRowContentWithControls, +} from "@app/components/TableControls"; export interface IApplicationDetailDrawerProps extends Pick { @@ -180,9 +177,9 @@ export const ApplicationDetailDrawer: React.FC< {!application ? null : ( {t("terms.Tasks")}} + title={{t("terms.tasks")}} > - + )} @@ -555,21 +552,18 @@ const TabReportsContent: React.FC<{ ); }; -const TabTasksContent: React.FC<{}> = () => { - const { t } = useTranslation(); - //path - +const TabTasksContent: React.FC<{ application: DecoratedApplication }> = ({ + application, +}) => { const isFApplication = true; - const allAffectedApplicationsFilterCategories = - useSharedAffectedApplicationFilterCategories(); - + const { t } = useTranslation(); + const history = useHistory(); const urlParams = new URLSearchParams(window.location.search); const filters = urlParams.get("filters"); const deserializedFilterValues = deserializeFilterUrlParams({ filters }); - const tableControlState = useTableControlState({ - tableName: "tasks-table", + tableName: "tasks-apps-table", persistTo: "urlParams", persistenceKeyPrefix: TablePersistenceKeyPrefix.tasks, columnNames: { @@ -577,63 +571,75 @@ const TabTasksContent: React.FC<{}> = () => { taskKind: "Task Kind", status: "Status", priority: "Priority", - action: "action", }, - initialFilterValues: deserializedFilterValues, isFilterEnabled: true, isSortEnabled: true, isPaginationEnabled: true, - initialItemsPerPage: 10, sortableColumns: ["taskId", "taskKind", "status", "priority"], initialSort: { columnKey: "taskId", direction: "asc" }, + initialFilterValues: deserializedFilterValues, filterCategories: [ - ...allAffectedApplicationsFilterCategories, { - categoryKey: "taskId", - title: t("Task ID"), - type: FilterType.search, - filterGroup: "Task", - placeholderText: t("Filter by Task ID"), - getServerFilterValue: (value) => (value ? [`*${value[0]}*`] : []), + categoryKey: "id", + title: "ID", + type: FilterType.numsearch, + placeholderText: t("actions.filterBy", { + what: "ID...", + }), + getServerFilterValue: (value) => { + console.log("this id:", value); + return value ? value : []; + }, }, { - categoryKey: "taskKind", - title: t("Task Kind"), + categoryKey: "kind", + title: t("terms.kind"), type: FilterType.search, - filterGroup: "Task", - placeholderText: t("Filter by Task Kind"), + placeholderText: t("actions.filterBy", { + what: t("terms.kind") + "...", + }), getServerFilterValue: (value) => (value ? [`*${value[0]}*`] : []), }, { - categoryKey: "status", - title: t("Status"), + categoryKey: "state", + title: t("terms.status"), type: FilterType.search, - filterGroup: "Task", - placeholderText: t("Filter by Status"), + placeholderText: t("actions.filterBy", { + what: t("terms.status") + "...", + }), getServerFilterValue: (value) => (value ? [`*${value[0]}*`] : []), }, ], + initialItemsPerPage: 10, }); const { - result: { data: currentPageItems, total: totalItemCount }, + result: { data: currentPageItems = [], total: totalItemCount }, isFetching, + fetchError, } = useServerTasks( getHubRequestParams({ ...tableControlState, hubSortFieldKeys: { - taskId: "taskId", - taskKind: "taskKind", + taskId: "id", + taskKind: "kind", status: "status", priority: "priority", }, - }) + implicitFilters: [ + { + field: "application.id", + operator: "=", + value: application.id, + }, + ], + }), + 5000 ); - const tableControls = useTableControlProps({ - ...tableControlState, // Includes filterState, sortState and paginationState + ...tableControlState, idProperty: "id", - currentPageItems, + currentPageItems: currentPageItems, totalItemCount, isLoading: isFetching, selectionState: useSelectionState({ @@ -643,88 +649,123 @@ const TabTasksContent: React.FC<{}> = () => { }); const { + numRenderedColumns, propHelpers: { toolbarProps, filterToolbarProps, + paginationToolbarItemProps, paginationProps, tableProps, getThProps, - getTdProps, getTrProps, + getTdProps, }, } = tableControls; - const history = useHistory(); - const clearFilters = () => { const currentPath = history.location.pathname; const newSearch = new URLSearchParams(history.location.search); newSearch.delete("filters"); history.push(`${currentPath}`); }; - return ( <> - - - - - - - - + + + + + + + + + + + +
+ + + - - - - - - - - - - - - - + + + + + - {currentPageItems?.map((task) => ( + {currentPageItems?.map((task, rowIndex) => ( - - - - {/*check if state=status*/} - - + + + + + + ))} -
{t("Task ID")} - {t("Task Kind")} - {t("Status")} - {t("Priority")} -
{task.id}{task.kind}{task.state} - {task.priority} - - {" "} - + {task.id} + + {task.kind} + + {task.state} + + {task.priority || 0} + + +
- - - + +
+ ); }; diff --git a/client/src/app/pages/tasks/TaskActionColumn.tsx b/client/src/app/pages/tasks/TaskActionColumn.tsx index c55d9a737e..7ad4006ded 100644 --- a/client/src/app/pages/tasks/TaskActionColumn.tsx +++ b/client/src/app/pages/tasks/TaskActionColumn.tsx @@ -3,13 +3,8 @@ import React, { FC } from "react"; import { Task } from "@app/api/models"; import { ActionsColumn } from "@patternfly/react-table"; import { useTaskActions } from "./useTaskActions"; -//path -export interface TaskActionColumnProps { - task: Task; - isFApplication: boolean; -} -export const TaskActionColumn: FC = ({ +export const TaskActionColumn: FC<{ task: Task; isFApplication: boolean }> = ({ task, isFApplication, }) => { diff --git a/client/src/app/pages/tasks/TaskDetails.tsx b/client/src/app/pages/tasks/TaskDetails.tsx index 7273c14503..b370853fe3 100644 --- a/client/src/app/pages/tasks/TaskDetails.tsx +++ b/client/src/app/pages/tasks/TaskDetails.tsx @@ -2,41 +2,47 @@ import React from "react"; import { useParams } from "react-router-dom"; import { useTranslation } from "react-i18next"; -import { Paths, TaskDetailsAttachmentRoute } from "@app/Paths"; +import { Paths, TaskDetailsAttachmentRoute, TaskFromApp } from "@app/Paths"; import "@app/components/simple-document-viewer/SimpleDocumentViewer.css"; import { formatPath } from "@app/utils/utils"; import { TaskDetailsBase } from "./TaskDetailsBase"; -//path -import { TaskActionColumnProps } from "./TaskActionColumn"; -//path -import { useFetchApplicationById } from "@app/queries/applications"; -import { AnalysisDetailsAttachmentRoute } from "@app/Paths"; -import { TabKey } from "../applications/components/application-detail-drawer/application-detail-drawer"; +import { getTaskById } from "@app/api/rest"; +import { useState, useEffect } from "react"; -const { applicationId } = useParams(); -const detailsPath = formatPath(Paths.applicationsAnalysisDetails, { - applicationId: applicationId, -}); -const { application } = useFetchApplicationById(applicationId); - -export const TaskDetails = (isFApplication: TaskActionColumnProps) => { +export const TaskDetails = () => { const { t } = useTranslation(); - /*bread*/ - const appName: string = application?.name ?? t("terms.unknown"); - const { taskId, attachmentId } = useParams(); + const { isFApplication } = useParams(); + const result = isFApplication === "true" ? true : false; + const [applicationName, setApplicationName] = useState(); + const [applicationId, setApplicationId] = useState(); + + useEffect(() => { + const currentTask = getTaskById(Number(taskId)); + currentTask + .then((task) => { + setApplicationName(task.application?.name); + setApplicationId(task.application?.id); + }) + .catch((error) => { + console.error("Error fetching task:", error); + }); + }, [taskId]); + const appName: string = applicationName ?? t("terms.unknown"); + console.log(appName); const detailsPath = formatPath(Paths.taskDetails, { taskId }); + return ( { /> ); }; - export default TaskDetails; diff --git a/client/src/app/pages/tasks/tasks-page.tsx b/client/src/app/pages/tasks/tasks-page.tsx index 771c6dad2f..ba47a123e8 100644 --- a/client/src/app/pages/tasks/tasks-page.tsx +++ b/client/src/app/pages/tasks/tasks-page.tsx @@ -71,7 +71,7 @@ export const TasksPage: React.FC = () => { const urlParams = new URLSearchParams(window.location.search); const filters = urlParams.get("filters") ?? ""; - + const isFApplication = false; const deserializedFilterValues = deserializeFilterUrlParams({ filters }); const tableControlState = useTableControlState({ @@ -265,10 +265,6 @@ export const TasksPage: React.FC = () => { : "", }); - //path - - const isFApplication = false; - return ( <> diff --git a/client/src/app/pages/tasks/useTaskActions.tsx b/client/src/app/pages/tasks/useTaskActions.tsx index bdbb839bf5..608c9bfeca 100644 --- a/client/src/app/pages/tasks/useTaskActions.tsx +++ b/client/src/app/pages/tasks/useTaskActions.tsx @@ -10,7 +10,6 @@ import { useTranslation } from "react-i18next"; import { useHistory } from "react-router-dom"; import { formatPath } from "@app/utils/utils"; import { Paths } from "@app/Paths"; -/*breadcrumbs*/ const canCancel = (state: TaskState = "No task") => !["Succeeded", "Failed", "Canceled"].includes(state); @@ -61,8 +60,8 @@ const useAsyncTaskActions = () => { return { cancelTask, togglePreemption }; }; -//? -export const useTaskActions = (task: Task, isFApplication?: boolean) => { + +export const useTaskActions = (task: Task, isFApplication: boolean) => { const { cancelTask, togglePreemption } = useAsyncTaskActions(); const { t } = useTranslation(); const history = useHistory(); @@ -86,21 +85,9 @@ export const useTaskActions = (task: Task, isFApplication?: boolean) => { history.push( formatPath(Paths.taskDetails, { taskId: task.id, + isFApplication: isFApplication, }) ), }, - // { - // title:t("actions.taskDetails"), - // onClick: () => { - // /* we check if drawer open*/ - // history.push( - // formatPath( - // isFApplication ? Paths.applicationsTabTaskDetails : Paths.taskDetails, - // { taskId: task.id } - // ) - // ); - - // }, - // }, ]; }; From 033323d5bbda65e1fda345af9d61c69e532fc219 Mon Sep 17 00:00:00 2001 From: EstyBiton Date: Sun, 3 Nov 2024 10:15:58 +0200 Subject: [PATCH 5/5] Fix tasks tab in detail drawer Signed-off-by: EstyBiton --- client/src/app/Paths.ts | 7 +- client/src/app/Routes.tsx | 5 ++ .../task-manager/TaskManagerDrawer.tsx | 2 +- .../application-detail-drawer.tsx | 66 ++++++++----------- .../src/app/pages/tasks/TaskActionColumn.tsx | 7 +- client/src/app/pages/tasks/TaskDetails.tsx | 41 +++++------- client/src/app/pages/tasks/tasks-page.tsx | 8 +-- client/src/app/pages/tasks/useTaskActions.tsx | 26 +++++--- 8 files changed, 75 insertions(+), 87 deletions(-) diff --git a/client/src/app/Paths.ts b/client/src/app/Paths.ts index f40b056445..46a41ba5e8 100644 --- a/client/src/app/Paths.ts +++ b/client/src/app/Paths.ts @@ -3,6 +3,7 @@ export const DevPaths = { applications: "/applications", applicationsAnalysisDetails: "/applications/:applicationId/analysis-details/:taskId", + applicationsTaskDetails: "/applications/:applicationId/tasks/:taskId", applicationsAnalysisDetailsAttachment: "/applications/:applicationId/analysis-details/:taskId/attachments/:attachmentId", applicationsAnalysisTab: "/applications/analysis-tab", @@ -41,7 +42,7 @@ export const DevPaths = { dependencies: "/dependencies", tasks: "/tasks", - taskDetails: "/tasks/:taskId/:isFApplication", + taskDetails: "/tasks/:taskId", taskDetailsAttachment: "/tasks/:taskId/attachments/:attachmentId", } as const; @@ -108,7 +109,5 @@ export interface AnalysisDetailsAttachmentRoute { export interface TaskDetailsAttachmentRoute { taskId: string; attachmentId: string; -} -export interface TaskFromApp { - isFApplication: string; + applicationId: string; } diff --git a/client/src/app/Routes.tsx b/client/src/app/Routes.tsx index 64cb995cc2..f1e7796be3 100644 --- a/client/src/app/Routes.tsx +++ b/client/src/app/Routes.tsx @@ -85,6 +85,11 @@ export const devRoutes: IRoute[] = [ comp: AnalysisDetails, exact: true, }, + { + path: Paths.applicationsTaskDetails, + comp: TaskDetails, + exact: true, + }, { path: Paths.applicationsAnalysisDetailsAttachment, comp: AnalysisDetails, diff --git a/client/src/app/components/task-manager/TaskManagerDrawer.tsx b/client/src/app/components/task-manager/TaskManagerDrawer.tsx index 21bba41fd3..8e9141a4be 100644 --- a/client/src/app/components/task-manager/TaskManagerDrawer.tsx +++ b/client/src/app/components/task-manager/TaskManagerDrawer.tsx @@ -164,7 +164,7 @@ const TaskItem: React.FC<{ task.priority ?? 0 }`; - const taskActionItems = useTaskActions(task._, false); + const taskActionItems = useTaskActions(task._); return ( { @@ -107,6 +109,7 @@ export const ApplicationDetailDrawer: React.FC< IApplicationDetailDrawerProps > = ({ application, task, onCloseClick, onEditClick }) => { const { t } = useTranslation(); + const [activeTabKey, setActiveTabKey] = React.useState( TabKey.Details ); @@ -179,7 +182,7 @@ export const ApplicationDetailDrawer: React.FC< eventKey={TabKey.Tasks} title={{t("terms.tasks")}} > - + )} @@ -552,11 +555,10 @@ const TabReportsContent: React.FC<{ ); }; -const TabTasksContent: React.FC<{ application: DecoratedApplication }> = ({ - application, -}) => { - const isFApplication = true; - +const TabTasksContent: React.FC<{ + application: DecoratedApplication; + task: TaskDashboard | null; +}> = ({ application, task }) => { const { t } = useTranslation(); const history = useHistory(); const urlParams = new URLSearchParams(window.location.search); @@ -570,12 +572,11 @@ const TabTasksContent: React.FC<{ application: DecoratedApplication }> = ({ taskId: "Task ID", taskKind: "Task Kind", status: "Status", - priority: "Priority", }, isFilterEnabled: true, isSortEnabled: true, isPaginationEnabled: true, - sortableColumns: ["taskId", "taskKind", "status", "priority"], + sortableColumns: ["taskId", "taskKind", "status"], initialSort: { columnKey: "taskId", direction: "asc" }, initialFilterValues: deserializedFilterValues, filterCategories: [ @@ -624,7 +625,6 @@ const TabTasksContent: React.FC<{ application: DecoratedApplication }> = ({ taskId: "id", taskKind: "kind", status: "status", - priority: "priority", }, implicitFilters: [ { @@ -642,6 +642,7 @@ const TabTasksContent: React.FC<{ application: DecoratedApplication }> = ({ currentPageItems: currentPageItems, totalItemCount, isLoading: isFetching, + variant: "compact", selectionState: useSelectionState({ items: currentPageItems, isEqual: (a, b) => a.name === b.name, @@ -697,10 +698,6 @@ const TabTasksContent: React.FC<{ application: DecoratedApplication }> = ({ modifier="nowrap" /> - @@ -719,40 +716,31 @@ const TabTasksContent: React.FC<{ application: DecoratedApplication }> = ({ item={task} rowIndex={rowIndex} > - - {task.id} - - + {task.id} + {task.kind} - - {task.state} - - - {task.priority || 0} + + } + label={ + + {t(taskStateToLabel[task.state ?? "No task"])} + + } + /> - + diff --git a/client/src/app/pages/tasks/TaskActionColumn.tsx b/client/src/app/pages/tasks/TaskActionColumn.tsx index 7ad4006ded..0f99d035e8 100644 --- a/client/src/app/pages/tasks/TaskActionColumn.tsx +++ b/client/src/app/pages/tasks/TaskActionColumn.tsx @@ -4,10 +4,7 @@ import { Task } from "@app/api/models"; import { ActionsColumn } from "@patternfly/react-table"; import { useTaskActions } from "./useTaskActions"; -export const TaskActionColumn: FC<{ task: Task; isFApplication: boolean }> = ({ - task, - isFApplication, -}) => { - const actions = useTaskActions(task, isFApplication); +export const TaskActionColumn: FC<{ task: Task }> = ({ task }) => { + const actions = useTaskActions(task); return ; }; diff --git a/client/src/app/pages/tasks/TaskDetails.tsx b/client/src/app/pages/tasks/TaskDetails.tsx index b370853fe3..31770baed5 100644 --- a/client/src/app/pages/tasks/TaskDetails.tsx +++ b/client/src/app/pages/tasks/TaskDetails.tsx @@ -2,44 +2,37 @@ import React from "react"; import { useParams } from "react-router-dom"; import { useTranslation } from "react-i18next"; -import { Paths, TaskDetailsAttachmentRoute, TaskFromApp } from "@app/Paths"; +import { Paths, TaskDetailsAttachmentRoute } from "@app/Paths"; import "@app/components/simple-document-viewer/SimpleDocumentViewer.css"; import { formatPath } from "@app/utils/utils"; import { TaskDetailsBase } from "./TaskDetailsBase"; -import { getTaskById } from "@app/api/rest"; -import { useState, useEffect } from "react"; +import { useFetchApplicationById } from "@app/queries/applications"; export const TaskDetails = () => { const { t } = useTranslation(); - const { taskId, attachmentId } = useParams(); - const { isFApplication } = useParams(); - const result = isFApplication === "true" ? true : false; - const [applicationName, setApplicationName] = useState(); - const [applicationId, setApplicationId] = useState(); + const { taskId, attachmentId, applicationId } = + useParams(); + const currentPath = window.location.pathname; + const isFromApplication = currentPath.includes("application") ? true : false; + const { application } = useFetchApplicationById(applicationId); - useEffect(() => { - const currentTask = getTaskById(Number(taskId)); - currentTask - .then((task) => { - setApplicationName(task.application?.name); - setApplicationId(task.application?.id); - }) - .catch((error) => { - console.error("Error fetching task:", error); - }); - }, [taskId]); - const appName: string = applicationName ?? t("terms.unknown"); + const appName: string = application?.name ?? t("terms.unknown"); console.log(appName); - const detailsPath = formatPath(Paths.taskDetails, { taskId }); + const detailsPath = isFromApplication + ? formatPath(Paths.applicationsTaskDetails, { + applicationId: applicationId, + taskId: taskId, + }) + : formatPath(Paths.taskDetails, { taskId }); return ( = { +export const taskStateToLabel: Record = { "No task": "taskState.NoTask", "not supported": "", Canceled: "taskState.Canceled", @@ -71,7 +71,6 @@ export const TasksPage: React.FC = () => { const urlParams = new URLSearchParams(window.location.search); const filters = urlParams.get("filters") ?? ""; - const isFApplication = false; const deserializedFilterValues = deserializeFilterUrlParams({ filters }); const tableControlState = useTableControlState({ @@ -356,10 +355,7 @@ export const TasksPage: React.FC = () => { isActionCell id={`row-actions-${task.id}`} > - + diff --git a/client/src/app/pages/tasks/useTaskActions.tsx b/client/src/app/pages/tasks/useTaskActions.tsx index 608c9bfeca..ee3910e54d 100644 --- a/client/src/app/pages/tasks/useTaskActions.tsx +++ b/client/src/app/pages/tasks/useTaskActions.tsx @@ -61,7 +61,7 @@ const useAsyncTaskActions = () => { return { cancelTask, togglePreemption }; }; -export const useTaskActions = (task: Task, isFApplication: boolean) => { +export const useTaskActions = (task: Task) => { const { cancelTask, togglePreemption } = useAsyncTaskActions(); const { t } = useTranslation(); const history = useHistory(); @@ -81,13 +81,23 @@ export const useTaskActions = (task: Task, isFApplication: boolean) => { }, { title: t("actions.taskDetails"), - onClick: () => - history.push( - formatPath(Paths.taskDetails, { - taskId: task.id, - isFApplication: isFApplication, - }) - ), + onClick: () => { + const currentPath = window.location.pathname; + if (currentPath.includes("application")) { + history.push( + formatPath(Paths.applicationsTaskDetails, { + applicationId: task.application?.id, + taskId: task?.id, + }) + ); + } else { + history.push( + formatPath(Paths.taskDetails, { + taskId: task?.id, + }) + ); + } + }, }, ]; };