diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 52d57aa..8039866 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -181,6 +181,7 @@ "Subject": "Subject", "Support": "Support", "SupportingData": "Supporting Data", + "Tasks": "Tasks", "TasksValidationError": "Tasks configuration is invalid", "TemplateIdCannotBeNull": "Template Id cannot be null", "TemplateUnknown": "Template unknown", diff --git a/src/App.tsx b/src/App.tsx index 0903d47..a33e9b0 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -47,6 +47,7 @@ import { Namespaces } from "./i18n/i18n"; import WorkflowTemplateManager from "./modules/manager/workflowTemplates/WorkflowTemplateManager"; import WorkflowTemplateDetails from "./modules/manager/workflowTemplates/WorkflowTemplateDetails"; import CreateActivity from "./modules/manager/activity/CreateActivity"; +import Tasks from "./modules/manager/tasks/tasks"; function GetSecureRoutes() { const { t } = useTranslation(Namespaces.Common); @@ -387,6 +388,14 @@ function GetSecureRoutes() { } /> + + + + } + /> { const { t } = useTranslation(Namespaces.Common); @@ -37,6 +38,7 @@ const LeftMenu: React.FC = () => { // Access checks const viewOrganisation = authentication.hasAccess("ViewOrganisation"); + const viewTasks = authentication.hasAccess("ViewTasks"); const viewUser = authentication.hasAccess("ViewUser"); const viewDomain = authentication.hasAccess("ViewDomain"); const viewGlossary = authentication.hasAccess("ViewGlossary"); @@ -69,7 +71,9 @@ const LeftMenu: React.FC = () => {
- + {viewTasks && ( + + )} {viewOrganisation && ( | undefined, +): Promise> { + const filterString = MapToJson(filters); + const response = await httpService.get>( + apiEndpoint + "/myTasks", + { + params: { + page: page, + pageSize: pageSize, + sortKey: sortKey, + sortAscending: sortAscending, + filters: filterString, + }, + }, + ); + return response?.data; +} + +const tasksService = { + myTasks, +}; + +export default tasksService; diff --git a/src/modules/manager/tasks/tasks.tsx b/src/modules/manager/tasks/tasks.tsx new file mode 100644 index 0000000..595e2be --- /dev/null +++ b/src/modules/manager/tasks/tasks.tsx @@ -0,0 +1,134 @@ +import React, { useCallback, useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { Namespaces } from "../../../i18n/i18n"; +import Column from "../../../components/common/columns"; +import { Paginated } from "../../../services/Paginated"; +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"; + +const Tasks: React.FC = () => { + const { t } = useTranslation(Namespaces.Common); + const [loaded, setLoaded] = useState(false); + const [pagedData, setPagedData] = useState>({ + page: 1, + pageSize: 10, + count: 0, + totalPages: 1, + data: [], + }); + const [sortColumn, setSortColumn] = useState>({ + key: "displayName", + label: t("Name"), + order: "asc", + }); + const [filters, setFilters] = useState>( + new Map(), + ); + + const changePage = useCallback( + async (page: number, pageSize: number) => { + const data = await tasksService.myTasks( + page, + pageSize, + sortColumn.key, + sortColumn.order === "asc", + filters, + ); + if (data) { + setLoaded(true); + setPagedData(data); + } else { + setLoaded(false); + } + }, + [filters, sortColumn.key, sortColumn.order], + ); + + const onSort = async (newSortColumn: Column) => { + const { page, pageSize } = pagedData; + const data = await tasksService.myTasks( + page, + pageSize, + newSortColumn.key, + newSortColumn.order === "asc", + filters, + ); + + if (data) { + setLoaded(true); + setPagedData(data); + setSortColumn(newSortColumn); + } else { + setLoaded(false); + } + }; + + const onSearch = async (name: string, value: string) => { + const { page, pageSize } = pagedData; + const newFilters = new Map(filters); + newFilters.set(name, value); + const data = await tasksService.myTasks( + page, + pageSize, + sortColumn.key, + sortColumn.order === "asc", + newFilters, + ); + + if (data) { + setLoaded(true); + setFilters(newFilters); + setPagedData(data); + } else { + setLoaded(false); + } + }; + + useEffect(() => { + const loadInitial = async () => { + const data = await tasksService.myTasks( + 1, + 10, + "displayName", + true, + filters, + ); + if (data) { + setLoaded(true); + setPagedData(data); + } else { + setLoaded(false); + } + }; + + void loadInitial(); + }, []); // eslint-disable-line react-hooks/exhaustive-deps + + return ( + <> + + + + <>My Tasks go here + + My Tasks go here + {/* */} + + + ); +}; + +export default Tasks; diff --git a/src/modules/manager/workflowTemplates/components/TaskList.tsx b/src/modules/manager/workflowTemplates/components/TaskList.tsx index e93bd2a..95e3654 100644 --- a/src/modules/manager/workflowTemplates/components/TaskList.tsx +++ b/src/modules/manager/workflowTemplates/components/TaskList.tsx @@ -4,6 +4,7 @@ import templateVersionsService, { TaskMetadata, } from "../services/WorkflowTemplateService"; import AddTaskButton from "./AddTaskButton"; +import FontAwesomeStringIcon from "../../../../components/common/FontAwesomeStringIcon"; import { SelectableList } from "../../../../components/common/SelectableList"; import { sortTasksTopologically } from "./workflowGraphUtils"; import { useCapabilityDefaults, validateTask } from "./useCapabilityDefaults"; @@ -103,10 +104,12 @@ const TaskList: React.FC = ({ selectedValue={selectedTask} renderLabel={(x) => { if (x) { + const meta = taskMetadataByType.get(x.type); + return ( <> + {x.config.name as string} - {