diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 7eb2b00..53473d8 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -201,6 +201,7 @@ "ValidIssuer": "Valid Issuer", "Version": "Version", "VersionCannotBeNull": "Version cannot be null", + "WorkflowTemplates": "Workflow Templates", "Year": "Year", "YourProfileSettingsHaveBeenSaved": "Your profile settings have been saved" } diff --git a/src/App.tsx b/src/App.tsx index fe8e92e..654ebe6 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -44,6 +44,7 @@ import ErrorLogs from "./modules/errorLogs/errorLogs"; import SsoManager from "./modules/manager/ssoManager/ssoManager"; import SsoProviderDetails from "./modules/manager/ssoManager/SsoProviderDetails"; import { Namespaces } from "./i18n/i18n"; +import WorkflowTemplateManager from "./modules/manager/workflowTemplates/WorkflowTemplateManager"; function GetSecureRoutes() { const { t } = useTranslation(); @@ -370,6 +371,14 @@ function GetSecureRoutes() { } /> + + + + } + /> { const viewField = authentication.hasAccess("ViewField"); const viewSequence = authentication.hasAccess("ViewSequence"); const viewSsoManager = authentication.hasAccess("ViewSsoProviders"); + const ViewWorkflowTemplates = authentication.hasAccess( + "ViewWorkflowTemplates", + ); const viewAdmin = viewUser || @@ -51,7 +54,8 @@ const LeftMenu: React.FC = () => { viewGlossary || viewFormTemplate || viewField || - viewSequence; + viewSequence || + ViewWorkflowTemplates; const viewAuditLog = authentication.hasAccess("ViewAuditLog"); const viewBlockedIPAddresses = authentication.hasAccess( @@ -101,6 +105,12 @@ const LeftMenu: React.FC = () => { {viewSsoManager && ( )} + {ViewWorkflowTemplates && ( + + )} )} diff --git a/src/modules/manager/workflowTemplates/WorkflowTemplateManager.tsx b/src/modules/manager/workflowTemplates/WorkflowTemplateManager.tsx new file mode 100644 index 0000000..87e62aa --- /dev/null +++ b/src/modules/manager/workflowTemplates/WorkflowTemplateManager.tsx @@ -0,0 +1,142 @@ +import { useCallback, useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { Namespaces } from "../../../i18n/i18n"; +import Button, { ButtonType } from "../../../components/common/Button"; +import Column from "../../../components/common/columns"; +import Permission from "../../../components/common/Permission"; +import { Paginated } from "../../../services/Paginated"; +import Loading from "../../../components/common/Loading"; +import workflowTemplatesService, { + ReadWorkflowTemplate, +} from "./services/WorkflowTemplateService"; +import WorkflowTemplateManagerTable from "./components/WorkflowTemplateTable"; + +const WotkflowTemplateManager: React.FC = () => { + const { t } = useTranslation(); + const [loaded, setLoaded] = useState(false); + const [pagedData, setPagedData] = useState>({ + page: 1, + pageSize: 10, + count: 0, + totalPages: 1, + data: [], + }); + const [sortColumn, setSortColumn] = useState>({ + key: "name", + label: t("Name"), + order: "asc", + }); + const [filters, setFilters] = useState>( + new Map(), + ); + + const changePage = useCallback( + async (page: number, pageSize: number) => { + const data = await workflowTemplatesService.getTemplates( + 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 workflowTemplatesService.getTemplates( + 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 workflowTemplatesService.getTemplates( + page, + pageSize, + sortColumn.key, + sortColumn.order === "asc", + newFilters, + ); + if (data) { + setLoaded(true); + setFilters(newFilters); + setPagedData(data); + } else { + setLoaded(false); + } + }; + + const onDelete = async (item?: ReadWorkflowTemplate) => { + const response = await workflowTemplatesService.deleteTemplateVersion( + item?.id, + item?.guid, + ); + if (response) { + await changePage(pagedData.page, pagedData.pageSize); + } + }; + + useEffect(() => { + const loadInitial = async () => { + const data = await workflowTemplatesService.getTemplates( + 1, + 10, + "name", + true, + filters, + ); + if (data) { + setLoaded(true); + setPagedData(data); + } else { + setLoaded(false); + } + }; + + void loadInitial(); + }, []); // eslint-disable-line react-hooks/exhaustive-deps + + return ( + + + + +
+ +
+ ); +}; + +export default WotkflowTemplateManager; diff --git a/src/modules/manager/workflowTemplates/components/WorkflowTemplateTable.tsx b/src/modules/manager/workflowTemplates/components/WorkflowTemplateTable.tsx new file mode 100644 index 0000000..1b883fc --- /dev/null +++ b/src/modules/manager/workflowTemplates/components/WorkflowTemplateTable.tsx @@ -0,0 +1,66 @@ +import React, { 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 authentication from "../../../frame/services/authenticationService"; +import { ReadWorkflowTemplate } from "../services/WorkflowTemplateService"; + +const WorkflowTemplateManagerTable: React.FC< + PublishedTableProps +> = ({ data, sortColumn, onChangePage, onSearch, onDelete, onSort }) => { + const { t } = useTranslation(); + const canViewSite = authentication.hasAccess("ViewSite"); + + const columns: Column[] = useMemo( + () => [ + { + key: "name", + label: t("Name"), + order: "asc", + link: canViewSite ? "/site/{0}" : undefined, + }, + ], + [t, canViewSite], + ); + + const raiseSort = (sortCol: Column) => { + if (onSort !== undefined) onSort(sortCol); + }; + + const handleAuditParams = (item: any) => { + return { + entityName: "e_suite.Database.Core.Tables.Printer.Organisation", + primaryKey: `{"Id":${item.id}}`, + }; + }; + + const editPath = authentication.hasAccess("EditOrganisation") + ? "{0}" + : undefined; + const doDelete = authentication.hasAccess("DeleteOrganisation") + ? onDelete + : undefined; + const showAudit = authentication.hasAccess("ViewAuditLog") + ? handleAuditParams + : undefined; + + return ( + + ); +}; + +export default WorkflowTemplateManagerTable; diff --git a/src/modules/manager/workflowTemplates/services/WorkflowTemplateService.ts b/src/modules/manager/workflowTemplates/services/WorkflowTemplateService.ts new file mode 100644 index 0000000..86a0ee2 --- /dev/null +++ b/src/modules/manager/workflowTemplates/services/WorkflowTemplateService.ts @@ -0,0 +1,131 @@ +import httpService from "../../../../services/httpService"; +import { Paginated } from "../../../../services/Paginated"; +import { + GeneralIdRef, + MakeGeneralIdRef, + MakeGeneralIdRefParams, +} from "../../../../utils/GeneralIdRef"; +import MapToJson from "../../../../utils/MapToJson"; + +const apiEndpoint = "/WorkflowTemplate"; + +export type ReadWorkflowTemplate = { + id: bigint; + guid?: string; + name: string; + deleted: boolean; + version: bigint; +}; + +export type ReadWorkflowTemplateVersion = { + id: bigint; + guid?: string; + name: string; + address: string; + status: string; +}; + +export async function getTemplates( + page: number, + pageSize: number, + sortKey: string, + sortAscending: boolean, + filters?: Map, +): Promise> { + const filterString = MapToJson(filters); + const response = await httpService.get>( + apiEndpoint + "/templates", + { + params: { + page: page, + pageSize: pageSize, + sortKey: sortKey, + sortAscending: sortAscending, + filters: filterString, + }, + }, + ); + + return response?.data; +} + +export async function getTemplateVersions( + page: number, + pageSize: number, + sortKey: string, + sortAscending: boolean, + filters?: Map, +): Promise> { + const filterString = MapToJson(filters); + const response = await httpService.get< + Paginated + >(apiEndpoint + "/templateVersions", { + params: { + page: page, + pageSize: pageSize, + sortKey: sortKey, + sortAscending: sortAscending, + filters: filterString, + }, + }); + + return response?.data; +} + +export async function getTemplateVersion(id?: bigint, guid?: string) { + const params = MakeGeneralIdRefParams(id, guid); + + const response = await httpService.get( + apiEndpoint + "/templateVersion?" + params, + ); + + return response?.data; +} + +export async function postTemplateVersion( + name: string, + address: string, + status: string, +): Promise { + return await httpService.post(apiEndpoint + "/templateVersion", { + name, + address, + status, + }); +} + +export async function putTemplateVersion( + id: GeneralIdRef, + name: string, + address: string, + status: string, +): Promise { + return await httpService.put(apiEndpoint + "/templateVersion", { + GeneralIdRef: id, + name, + address, + status, + }); +} + +export async function deleteTemplateVersion( + id?: bigint, + guid?: string, +): Promise { + const generalIdRef = MakeGeneralIdRef(id, guid); + + return await httpService.delete(apiEndpoint + "/templateVersion", { + data: generalIdRef, + }); +} + +const templateVersionsService = { + getTemplates, + getTemplateVersions, + getTemplateVersion, + postTemplateVersion, + putTemplateVersion, + deleteTemplateVersion, +}; + +export default templateVersionsService;