Started working on the Tasks page

This commit is contained in:
Colin Dawson 2026-03-13 23:11:00 +00:00
parent 7bf87b95a4
commit 7fd8440ca6
6 changed files with 190 additions and 2 deletions

View File

@ -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",

View File

@ -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() {
</Mainframe>
}
/>
<Route
path="/tasks"
element={
<Mainframe title={t("Tasks")}>
<Tasks />
</Mainframe>
}
/>
<Route
path="/workflowTemplates"
element={

View File

@ -11,6 +11,7 @@ import LeftMenuItem from "./LeftMenuItem";
import LeftMenuSubMenu from "./LeftMenuSubMenu";
import { useTranslation } from "react-i18next";
import { Namespaces } from "../../../i18n/i18n";
import { faListCheck } from "@fortawesome/free-solid-svg-icons";
const LeftMenu: React.FC = () => {
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 = () => {
<div className="leftMenuContainer">
<div className="leftMenu">
<LeftMenuItem to="/" icon={faHome} label={t("Home")} />
{viewTasks && (
<LeftMenuItem to="/tasks" icon={faListCheck} label={t("Tasks")} />
)}
{viewOrganisation && (
<LeftMenuItem
to="/organisations"

View File

@ -0,0 +1,37 @@
import httpService from "../../../../services/httpService";
import { Paginated } from "../../../../services/Paginated";
import { GeneralIdRef } from "../../../../utils/GeneralIdRef";
import MapToJson from "../../../../utils/MapToJson";
const apiEndpoint = "/Tasks";
export interface GetMyTasks {}
export async function myTasks(
page: number,
pageSize: number,
sortKey: string,
sortAscending: boolean,
filters?: Map<string, string> | undefined,
): Promise<Paginated<GetMyTasks>> {
const filterString = MapToJson(filters);
const response = await httpService.get<Paginated<GetMyTasks>>(
apiEndpoint + "/myTasks",
{
params: {
page: page,
pageSize: pageSize,
sortKey: sortKey,
sortAscending: sortAscending,
filters: filterString,
},
},
);
return response?.data;
}
const tasksService = {
myTasks,
};
export default tasksService;

View File

@ -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<Paginated<GetMyTasks>>({
page: 1,
pageSize: 10,
count: 0,
totalPages: 1,
data: [],
});
const [sortColumn, setSortColumn] = useState<Column<GetMyTasks>>({
key: "displayName",
label: t("Name"),
order: "asc",
});
const [filters, setFilters] = useState<Map<string, string>>(
new Map<string, string>(),
);
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<GetMyTasks>) => {
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 (
<>
<Permission privilegeKey="CreateActivity">
<Button buttonType={ButtonType.primary} to="/activity/createActivity">
{t("CreateActivity")}
</Button>
</Permission>
<>My Tasks go here</>
<Loading loaded={loaded}>
My Tasks go here
{/* <UsersTable
data={pagedData}
sortColumn={sortColumn}
onChangePage={changePage}
onSort={onSort}
onSearch={onSearch}
onDelete={onDelete}
resendConfirmEmail={resentConfirmEmail}
/> */}
</Loading>
</>
);
};
export default Tasks;

View File

@ -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<TaskListProps> = ({
selectedValue={selectedTask}
renderLabel={(x) => {
if (x) {
const meta = taskMetadataByType.get(x.type);
return (
<>
<FontAwesomeStringIcon icon={meta?.icon} />
{x.config.name as string}
{
<ValidationErrorIcon
visible={