From a456fbbdbc3567a067d56e647b51c94c203e5b03 Mon Sep 17 00:00:00 2001 From: Colin Dawson Date: Tue, 17 Mar 2026 10:22:24 +0000 Subject: [PATCH] The tasks page now display my assignments --- .../manager/tasks/components/tasksTable.tsx | 65 +++++++++++ .../manager/tasks/services/tasksService.ts | 15 ++- src/modules/manager/tasks/tasks.tsx | 27 +++-- .../components/TaskNameDisplayPanel.tsx | 91 ++-------------- .../TaskTypeAndNameDisplayPanel.tsx | 101 ++++++++++++++++++ 5 files changed, 201 insertions(+), 98 deletions(-) create mode 100644 src/modules/manager/tasks/components/tasksTable.tsx create mode 100644 src/modules/manager/workflowTemplates/components/TaskTypeAndNameDisplayPanel.tsx diff --git a/src/modules/manager/tasks/components/tasksTable.tsx b/src/modules/manager/tasks/components/tasksTable.tsx new file mode 100644 index 0000000..10e4bbf --- /dev/null +++ b/src/modules/manager/tasks/components/tasksTable.tsx @@ -0,0 +1,65 @@ +import React, { useCallback, useMemo } from "react"; +import { useTranslation } from "react-i18next"; +import { Namespaces } from "../../../../i18n/i18n"; +import Column from "../../../../components/common/columns"; +import Table, { + PublishedTableProps, +} from "../../../../components/common/Table"; +import { GetMyAssignments } from "../services/tasksService"; +import TaskTypeAndNameDisplayPanel from "../../workflowTemplates/components/TaskTypeAndNameDisplayPanel"; + +export interface TasksTableProps extends PublishedTableProps {} + +const TasksTable: React.FC = ({ + data, + sortColumn, + onChangePage, + onSearch, + onDelete, + onSort, +}) => { + const { t } = useTranslation(Namespaces.Common); + + const columns: Column[] = useMemo( + () => [ + { + key: "taskName", + label: t("Name"), + content: (item) => { + return ( + + ); + }, + order: "asc", + }, + { key: "user", label: t("User"), order: "asc" }, + { key: "role", label: t("Role"), order: "asc" }, + { key: "startDateTime", label: t("StartDateTime"), order: "asc" }, + ], + [t], + ); + + const raiseSort = (sortCol: Column) => { + if (onSort !== undefined) onSort(sortCol); + }; + + return ( + + ); +}; + +export default TasksTable; diff --git a/src/modules/manager/tasks/services/tasksService.ts b/src/modules/manager/tasks/services/tasksService.ts index 6221117..976a81a 100644 --- a/src/modules/manager/tasks/services/tasksService.ts +++ b/src/modules/manager/tasks/services/tasksService.ts @@ -5,7 +5,16 @@ import MapToJson from "../../../../utils/MapToJson"; const apiEndpoint = "/Tasks"; -export interface GetMyTasks {} +export interface GetMyAssignments { + Id: bigint; + Guid: string; + + taskType: string; + taskName: string; + user?: GeneralIdRef; + role?: GeneralIdRef; + startDateTime?: Date; +} export async function myTasks( page: number, @@ -13,9 +22,9 @@ export async function myTasks( sortKey: string, sortAscending: boolean, filters?: Map | undefined, -): Promise> { +): Promise> { const filterString = MapToJson(filters); - const response = await httpService.get>( + const response = await httpService.get>( apiEndpoint + "/myTasks", { params: { diff --git a/src/modules/manager/tasks/tasks.tsx b/src/modules/manager/tasks/tasks.tsx index 595e2be..38c39a8 100644 --- a/src/modules/manager/tasks/tasks.tsx +++ b/src/modules/manager/tasks/tasks.tsx @@ -7,19 +7,20 @@ import Button, { ButtonType } from "../../../components/common/Button"; import { toast } from "react-toastify"; import Loading from "../../../components/common/Loading"; import Permission from "../../../components/common/Permission"; -import tasksService, { GetMyTasks } from "./services/tasksService"; +import tasksService, { GetMyAssignments } from "./services/tasksService"; +import TasksTable from "./components/tasksTable"; const Tasks: React.FC = () => { const { t } = useTranslation(Namespaces.Common); const [loaded, setLoaded] = useState(false); - const [pagedData, setPagedData] = useState>({ + const [pagedData, setPagedData] = useState>({ page: 1, pageSize: 10, count: 0, totalPages: 1, data: [], }); - const [sortColumn, setSortColumn] = useState>({ + const [sortColumn, setSortColumn] = useState>({ key: "displayName", label: t("Name"), order: "asc", @@ -47,7 +48,7 @@ const Tasks: React.FC = () => { [filters, sortColumn.key, sortColumn.order], ); - const onSort = async (newSortColumn: Column) => { + const onSort = async (newSortColumn: Column) => { const { page, pageSize } = pagedData; const data = await tasksService.myTasks( page, @@ -114,18 +115,14 @@ const Tasks: React.FC = () => { {t("CreateActivity")} - <>My Tasks go here - My Tasks go here - {/* */} + ); diff --git a/src/modules/manager/workflowTemplates/components/TaskNameDisplayPanel.tsx b/src/modules/manager/workflowTemplates/components/TaskNameDisplayPanel.tsx index 0284bd6..c1fdf7d 100644 --- a/src/modules/manager/workflowTemplates/components/TaskNameDisplayPanel.tsx +++ b/src/modules/manager/workflowTemplates/components/TaskNameDisplayPanel.tsx @@ -1,99 +1,30 @@ -import { useEffect } from "react"; -import templateVersionsService, { - TaskMetadata, - TaskDefinition, -} from "../services/WorkflowTemplateService"; import React from "react"; -import FontAwesomeStringIcon from "../../../../components/common/FontAwesomeStringIcon"; -import ValidationErrorIcon from "../../../../components/validationErrorIcon"; +import { TaskDefinition } from "../services/WorkflowTemplateService"; +import TaskTypeAndNameDisplayPanel from "./TaskTypeAndNameDisplayPanel"; -export interface TaskNameDisplayPanel { +export interface TaskNameDisplayPanelProps { task: TaskDefinition; showValidationErrorIcon: boolean; allowWordWrap?: boolean; reserveValidationErrorIconSpace?: boolean; } -const TaskNameDisplayPanel: React.FC = ({ +const TaskNameDisplayPanel: React.FC = ({ task, showValidationErrorIcon = false, allowWordWrap = false, reserveValidationErrorIconSpace = false, }) => { - const [tasksMetadata, setTasksMetadata] = React.useState([]); - const [isNameTruncated, setIsNameTruncated] = React.useState(false); - const taskNameRef = React.useRef(null); const taskName = task.config.name as string; - useEffect(() => { - const fetchTaskMetadata = async () => { - const meta = await templateVersionsService.getTaskMetadata("GeneralTask"); - setTasksMetadata(meta); - }; - - fetchTaskMetadata(); - }, []); - - const taskMetadataByType = React.useMemo(() => { - const map = new Map(); - tasksMetadata.forEach((meta) => { - map.set(meta.taskType, meta); - }); - return map; - }, [tasksMetadata]); - - const meta = taskMetadataByType.get(task.type); - const panelClassName = allowWordWrap - ? "task-name-display-panel task-name-display-panel--wrap" - : "task-name-display-panel"; - - const updateTruncationState = React.useCallback(() => { - const el = taskNameRef.current; - - if (!el || allowWordWrap) { - setIsNameTruncated(false); - return; - } - - setIsNameTruncated(el.scrollWidth > el.clientWidth); - }, [allowWordWrap]); - - useEffect(() => { - updateTruncationState(); - }, [taskName, allowWordWrap, updateTruncationState]); - - useEffect(() => { - const el = taskNameRef.current; - if (!el || allowWordWrap || typeof ResizeObserver === "undefined") { - return; - } - - const observer = new ResizeObserver(() => { - updateTruncationState(); - }); - - observer.observe(el); - - return () => { - observer.disconnect(); - }; - }, [allowWordWrap, updateTruncationState]); - return ( -
- - - {taskName} - - -
+ ); }; diff --git a/src/modules/manager/workflowTemplates/components/TaskTypeAndNameDisplayPanel.tsx b/src/modules/manager/workflowTemplates/components/TaskTypeAndNameDisplayPanel.tsx new file mode 100644 index 0000000..064deb9 --- /dev/null +++ b/src/modules/manager/workflowTemplates/components/TaskTypeAndNameDisplayPanel.tsx @@ -0,0 +1,101 @@ +import React, { useEffect } from "react"; +import templateVersionsService, { + TaskMetadata, +} from "../services/WorkflowTemplateService"; +import FontAwesomeStringIcon from "../../../../components/common/FontAwesomeStringIcon"; +import ValidationErrorIcon from "../../../../components/validationErrorIcon"; + +export interface TaskTypeAndNameDisplayPanelProps { + taskName: string; + taskType: string; + showValidationErrorIcon: boolean; + allowWordWrap?: boolean; + reserveValidationErrorIconSpace?: boolean; +} + +const TaskTypeAndNameDisplayPanel: React.FC< + TaskTypeAndNameDisplayPanelProps +> = ({ + taskName, + taskType, + showValidationErrorIcon = false, + allowWordWrap = false, + reserveValidationErrorIconSpace = false, +}) => { + const [tasksMetadata, setTasksMetadata] = React.useState([]); + const [isNameTruncated, setIsNameTruncated] = React.useState(false); + const taskNameRef = React.useRef(null); + + useEffect(() => { + const fetchTaskMetadata = async () => { + const meta = await templateVersionsService.getTaskMetadata("GeneralTask"); + setTasksMetadata(meta); + }; + + fetchTaskMetadata(); + }, []); + + const taskMetadataByType = React.useMemo(() => { + const map = new Map(); + tasksMetadata.forEach((meta) => { + map.set(meta.taskType, meta); + }); + return map; + }, [tasksMetadata]); + + const meta = taskMetadataByType.get(taskType); + const panelClassName = allowWordWrap + ? "task-name-display-panel task-name-display-panel--wrap" + : "task-name-display-panel"; + + const updateTruncationState = React.useCallback(() => { + const el = taskNameRef.current; + + if (!el || allowWordWrap) { + setIsNameTruncated(false); + return; + } + + setIsNameTruncated(el.scrollWidth > el.clientWidth); + }, [allowWordWrap]); + + useEffect(() => { + updateTruncationState(); + }, [taskName, allowWordWrap, updateTruncationState]); + + useEffect(() => { + const el = taskNameRef.current; + if (!el || allowWordWrap || typeof ResizeObserver === "undefined") { + return; + } + + const observer = new ResizeObserver(() => { + updateTruncationState(); + }); + + observer.observe(el); + + return () => { + observer.disconnect(); + }; + }, [allowWordWrap, updateTruncationState]); + + return ( +
+ + + {taskName} + + +
+ ); +}; + +export default TaskTypeAndNameDisplayPanel;