From 81a01fe9f3e13ef05117fbbe593ac5dcaf241a89 Mon Sep 17 00:00:00 2001 From: Colin Dawson Date: Fri, 30 Jan 2026 23:54:14 +0000 Subject: [PATCH] Next round of refactoring done --- public/locales/en/common.json | 9 + src/modules/manager/domains/Domains.tsx | 39 ++-- .../domains/components/RoleAccessEditor.tsx | 166 +++++++------- .../domains/components/RolesEditor.tsx | 46 ++-- .../domains/components/UserRoleEditor.tsx | 58 ++--- src/modules/manager/forms/Forms.tsx | 40 ++-- src/modules/manager/sequence/sequence.tsx | 40 ++-- .../manager/sites/components/SitesTable.tsx | 3 +- .../manager/specifications/Specifications.tsx | 202 +++++++++-------- .../components/SpecificationsTable.tsx | 87 +++++--- .../ssoManager/components/ssoManagerTable.tsx | 87 +++++--- src/modules/manager/ssoManager/ssoManager.tsx | 197 +++++++++-------- src/modules/manager/users/UserDetails.tsx | 44 ++-- .../manager/users/components/usersTable.tsx | 159 ++++++++------ src/modules/manager/users/users.tsx | 204 ++++++++++-------- 15 files changed, 769 insertions(+), 612 deletions(-) diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 4ca6adb..35200d0 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -2,6 +2,7 @@ "Activate": "Activate", "Add": "Add", "AddDomain": "Add Domain", + "AddUser": "Add User", "Address": "Address", "Admin": "Admin", "AnEmailWithPasswordResetLinkHasBeenSent": "An email with a password reset link has been sent.", @@ -15,16 +16,22 @@ "BlockedIPs": "Blocked IPs", "Cancel": "Cancel", "Changes": "Changes", + "Confirm": "Confirm", + "ConfirmEmailResent": "Confirm e-mail resent", "ClientDomainManager": "Client Domain Manager", "ClientDomains": "Client Domains", "Comment": "Comment", "ConfirmPassword": "Confirm Password", "CustomFieldManager": "Custom Field Manager", "CustomFields": "Custom Fields", + "Created": "Created", "DisableAuthenticator": "Disable Authenticator", "DisplayName": "Display Name", + "Domain": "Domain", + "Email": "Email", "Edit": "Edit", "EditDomain": "Edit Domain", + "EditUser": "Edit User", "e-print": "e-print", "e-suite": "e-suite", "e-suiteLogo": "e-suite logo", @@ -45,6 +52,7 @@ "IPAddress": "IP Address", "IPAddressUnblocked": "IP Address '{{ip}}' unblocked.", "Items": "Items", + "LastUpdated": "Last Updated", "Loading": "Loading", "LoggingOut": "Logging out", "MailTemplates": "Mail Templates", @@ -62,6 +70,7 @@ "PasswordsMustMatch": "You need to confirm by typing exactly the same as the new password", "PressAgainToUnblock": "Press again to unblock", "ResetPassword": "Reset Password", + "ResendConfirm": "Resend Confirm", "RoleAccess": "Role Access", "RoleAccessUpdated": "Role access updated successfully.", "SecurityRoles": "Security Roles", diff --git a/src/modules/manager/domains/Domains.tsx b/src/modules/manager/domains/Domains.tsx index dc08981..1c6713a 100644 --- a/src/modules/manager/domains/Domains.tsx +++ b/src/modules/manager/domains/Domains.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from "react"; +import React, { useCallback, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import Column from "../../../components/common/columns"; import { Paginated } from "../../../services/Paginated"; @@ -30,29 +30,32 @@ const Domains: React.FC = () => { () => new Map(), ); + const changePage = useCallback( + async (page: number, pageSize: number) => { + const pagedDataResult = await domainsService.getDomains( + page, + pageSize, + sortColumn.key, + sortColumn.order === "asc", + filters, + ); + if (pagedDataResult) { + setLoaded(true); + setPagedData(pagedDataResult); + } else { + setLoaded(false); + } + }, + [filters, sortColumn.key, sortColumn.order], + ); + useEffect(() => { const loadInitial = async () => { await changePage(initialPagedData.page, initialPagedData.pageSize); }; void loadInitial(); - }, []); - - const changePage = async (page: number, pageSize: number) => { - const pagedDataResult = await domainsService.getDomains( - page, - pageSize, - sortColumn.key, - sortColumn.order === "asc", - filters, - ); - if (pagedDataResult) { - setLoaded(true); - setPagedData(pagedDataResult); - } else { - setLoaded(false); - } - }; + }, [changePage]); const onSort = async (nextSortColumn: Column) => { const { page, pageSize } = pagedData; diff --git a/src/modules/manager/domains/components/RoleAccessEditor.tsx b/src/modules/manager/domains/components/RoleAccessEditor.tsx index b9b0615..5d47ab0 100644 --- a/src/modules/manager/domains/components/RoleAccessEditor.tsx +++ b/src/modules/manager/domains/components/RoleAccessEditor.tsx @@ -1,7 +1,6 @@ -import React, { useEffect, useState } from "react"; +import React, { useCallback, useEffect, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import { toast } from "react-toastify"; -import Column from "../../../../components/common/columns"; import { Paginated } from "../../../../services/Paginated"; import { MakeGeneralIdRef } from "../../../../utils/GeneralIdRef"; import withRouter, { RouterProps } from "../../../../utils/withRouter"; @@ -40,98 +39,106 @@ const RoleAccessEditorNoRouter: React.FC = ({ const [loaded, setLoaded] = useState(false); const [accessList, setAccessList] = useState>(initialAccessList); - const [accessRightsForRole, setAccessRightsForRole] = - useState>(initialPagedData); const [pagedData, setPagedData] = useState>(initialPagedData); - const [sortColumn] = useState>({ - key: "name", - label: t("Name"), - order: "asc", - }); + const roleGeneralIdRef = useMemo( + () => MakeGeneralIdRef(role?.id, role?.guid), + [role?.id, role?.guid], + ); - const isItemSelected = ( - securityAccess: string, - roleAccessList: unknown[] | undefined, - ): boolean => { - if (roleAccessList === undefined) return false; + const isItemSelected = useCallback( + ( + securityAccess: string, + roleAccessList: unknown[] | undefined, + ): boolean => { + if (roleAccessList === undefined) return false; - const filtered = roleAccessList.filter( - (x) => (x as any).securityAccess === securityAccess, - ); - return filtered.length > 0; - }; + const filtered = roleAccessList.filter( + (x) => (x as any).securityAccess === securityAccess, + ); + return filtered.length > 0; + }, + [], + ); - const compileAccessRightsPagedData = ( - masterList: GetSecurityAccess[] | undefined, - roleAccessList: unknown[] | undefined, - ): Paginated => { - if (masterList === undefined) { - return initialPagedData; - } + const compileAccessRightsPagedData = useCallback( + ( + masterList: GetSecurityAccess[] | undefined, + roleAccessList: unknown[] | undefined, + ): Paginated => { + if (masterList === undefined) { + return initialPagedData; + } + + if (roleAccessList === undefined) { + return { + page: 1, + pageSize: 10, + count: 0, + totalPages: 1, + data: masterList as GetRoleSecurityAccess[], + }; + } + + const accessRightsForRoleData = masterList.map((value) => { + const item: any = value; + item.selected = isItemSelected(item.securityAccess, roleAccessList); + return item; + }); - if (roleAccessList === undefined) { return { page: 1, pageSize: 10, count: 0, totalPages: 1, - data: masterList as GetRoleSecurityAccess[], + data: accessRightsForRoleData, }; - } + }, + [isItemSelected], + ); - const accessRightsForRoleData = masterList.map((value) => { - const item: any = value; - item.selected = isItemSelected(item.securityAccess, roleAccessList); - return item; - }); + const changePage = useCallback( + async (nextAccessList?: Paginated) => { + const list = nextAccessList || accessList; - return { - page: 1, - pageSize: 10, - count: 0, - totalPages: 1, - data: accessRightsForRoleData, - }; - }; - - const changePage = async (nextAccessList?: Paginated) => { - const list = nextAccessList || accessList; - - const roleAccessFilters = new Map(); - roleAccessFilters.set("roleId", String(role?.id)); - const accessRightsResponse = await roleService.getRoleAccess( - 0, - 10, - "name", - true, - roleAccessFilters, - ); - - if (accessRightsResponse) { - const nextPagedData = compileAccessRightsPagedData( - list?.data, - accessRightsResponse?.data, + const roleAccessFilters = new Map(); + roleAccessFilters.set("roleId", String(role?.id)); + const accessRightsResponse = await roleService.getRoleAccess( + 0, + 10, + "name", + true, + roleAccessFilters, ); - if (nextPagedData) { - setLoaded(true); - setAccessRightsForRole(accessRightsResponse); - setPagedData(nextPagedData); - } - } else { - setLoaded(false); - } - }; - const updatePage = async (nextAccessList?: Paginated) => { - if (nextAccessList && nextAccessList.count === 0) { - const list = await roleService.getAccessList(0, 10, "name", true); - setAccessList(list); - await changePage(list); - } else { - await changePage(nextAccessList); - } - }; + if (accessRightsResponse) { + const nextPagedData = compileAccessRightsPagedData( + list?.data, + accessRightsResponse?.data, + ); + if (nextPagedData) { + setLoaded(true); + setPagedData(nextPagedData); + } + } else { + setLoaded(false); + } + }, + [accessList, compileAccessRightsPagedData, role?.id], + ); + + const updatePage = useCallback( + async (nextAccessList?: Paginated) => { + if (nextAccessList && nextAccessList.count === 0) { + const list = await roleService.getAccessList(0, 10, "name", true); + setAccessList(list); + await changePage(list); + } else { + await changePage(nextAccessList); + } + }, + [changePage], + ); useEffect(() => { const loadInitial = async () => { @@ -144,10 +151,9 @@ const RoleAccessEditorNoRouter: React.FC = ({ }; void loadInitial(); - }, [role?.id]); + }, [accessList, updatePage, role?.id]); const handleSave = async (additions: string[], deletions: string[]) => { - const roleGeneralIdRef = MakeGeneralIdRef(role?.id, role?.guid); let response = undefined; if (additions.length > 0) { diff --git a/src/modules/manager/domains/components/RolesEditor.tsx b/src/modules/manager/domains/components/RolesEditor.tsx index 1f33203..d611aaa 100644 --- a/src/modules/manager/domains/components/RolesEditor.tsx +++ b/src/modules/manager/domains/components/RolesEditor.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from "react"; +import React, { useCallback, useEffect, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import Column from "../../../../components/common/columns"; import { Paginated } from "../../../../services/Paginated"; @@ -44,7 +44,30 @@ const RolesEditorTabNoRouter: React.FC = ({ ); const { domainId } = router.params; - const domainGeneralIdRef = MakeGeneralIdRef(domainId); + const domainGeneralIdRef = useMemo( + () => MakeGeneralIdRef(domainId), + [domainId], + ); + + const changePage = useCallback( + async (page: number, pageSize: number) => { + const pagedDataResult = await roleService.getRoles( + page, + pageSize, + sortColumn.key, + sortColumn.order === "asc", + domainGeneralIdRef, + filters, + ); + if (pagedDataResult) { + setLoaded(true); + setPagedData(pagedDataResult); + } else { + setLoaded(false); + } + }, + [domainGeneralIdRef, filters, sortColumn.key, sortColumn.order], + ); useEffect(() => { const loadInitial = async () => { @@ -52,24 +75,7 @@ const RolesEditorTabNoRouter: React.FC = ({ }; void loadInitial(); - }, [domainId]); - - const changePage = async (page: number, pageSize: number) => { - const pagedDataResult = await roleService.getRoles( - page, - pageSize, - sortColumn.key, - sortColumn.order === "asc", - domainGeneralIdRef, - filters, - ); - if (pagedDataResult) { - setLoaded(true); - setPagedData(pagedDataResult); - } else { - setLoaded(false); - } - }; + }, [changePage, domainId]); const onSort = async (nextSortColumn: Column) => { const { page, pageSize } = pagedData; diff --git a/src/modules/manager/domains/components/UserRoleEditor.tsx b/src/modules/manager/domains/components/UserRoleEditor.tsx index 7ab3ecc..4516142 100644 --- a/src/modules/manager/domains/components/UserRoleEditor.tsx +++ b/src/modules/manager/domains/components/UserRoleEditor.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from "react"; +import React, { useCallback, useEffect, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import Column from "../../../../components/common/columns"; import { Paginated } from "../../../../services/Paginated"; @@ -39,31 +39,37 @@ const UserRoleEditorNoRouter: React.FC = ({ () => new Map(), ); - const roleGeneralIdRef = MakeGeneralIdRef(role?.id, role?.guid); + const roleGeneralIdRef = useMemo( + () => MakeGeneralIdRef(role?.id, role?.guid), + [role?.id, role?.guid], + ); - const getRoleUsers = async ( - page: number, - pageSize: number, - nextSortColumn: Column, - nextFilters: Map, - ) => { - const pagedDataResult = await roleService.getRoleUsers( - page, - pageSize, - nextSortColumn.key, - nextSortColumn.order === "asc", - roleGeneralIdRef, - nextFilters, - ); - if (pagedDataResult) { - setLoaded(true); - setFilters(nextFilters); - setPagedData(pagedDataResult); - setSortColumn(nextSortColumn); - } else { - setLoaded(false); - } - }; + const getRoleUsers = useCallback( + async ( + page: number, + pageSize: number, + nextSortColumn: Column, + nextFilters: Map, + ) => { + const pagedDataResult = await roleService.getRoleUsers( + page, + pageSize, + nextSortColumn.key, + nextSortColumn.order === "asc", + roleGeneralIdRef, + nextFilters, + ); + if (pagedDataResult) { + setLoaded(true); + setFilters(nextFilters); + setPagedData(pagedDataResult); + setSortColumn(nextSortColumn); + } else { + setLoaded(false); + } + }, + [roleGeneralIdRef], + ); useEffect(() => { const loadInitial = async () => { @@ -76,7 +82,7 @@ const UserRoleEditorNoRouter: React.FC = ({ }; void loadInitial(); - }, [role?.id]); + }, [getRoleUsers, role?.id, sortColumn]); const changePage = async (page: number, pageSize: number) => { await getRoleUsers(page, pageSize, sortColumn, filters); diff --git a/src/modules/manager/forms/Forms.tsx b/src/modules/manager/forms/Forms.tsx index 5166afb..645a2b0 100644 --- a/src/modules/manager/forms/Forms.tsx +++ b/src/modules/manager/forms/Forms.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from "react"; +import { useCallback, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import Button, { ButtonType } from "../../../components/common/Button"; import Column from "../../../components/common/columns"; @@ -28,21 +28,24 @@ const Forms: React.FC = () => { new Map(), ); - const changePage = async (page: number, pageSize: number) => { - const data = await formsService.getForms( - page, - pageSize, - sortColumn.key, - sortColumn.order === "asc", - filters, - ); - if (data) { - setLoaded(true); - setPagedData(data); - } else { - setLoaded(false); - } - }; + const changePage = useCallback( + async (page: number, pageSize: number) => { + const data = await formsService.getForms( + 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; @@ -91,9 +94,8 @@ const Forms: React.FC = () => { }; useEffect(() => { - const { page, pageSize } = pagedData; - changePage(page, pageSize); - }, [pagedData]); + changePage(pagedData.page, pagedData.pageSize); + }, [changePage, pagedData.page, pagedData.pageSize]); return ( diff --git a/src/modules/manager/sequence/sequence.tsx b/src/modules/manager/sequence/sequence.tsx index 12a3442..a51fdd2 100644 --- a/src/modules/manager/sequence/sequence.tsx +++ b/src/modules/manager/sequence/sequence.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from "react"; +import React, { useCallback, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import sequenceService, { ReadSequence } from "./services/sequenceService"; import SequenceTable from "./components/squenceTable"; @@ -27,21 +27,24 @@ const Sequence: React.FC = () => { new Map(), ); - const changePage = async (page: number, pageSize: number) => { - const data = await sequenceService.getSequences( - page, - pageSize, - sortColumn.key, - sortColumn.order === "asc", - filters, - ); - if (data) { - setLoaded(true); - setPagedData(data); - } else { - setLoaded(false); - } - }; + const changePage = useCallback( + async (page: number, pageSize: number) => { + const data = await sequenceService.getSequences( + 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; @@ -90,9 +93,8 @@ const Sequence: React.FC = () => { }; useEffect(() => { - const { page, pageSize } = pagedData; - changePage(page, pageSize); - }, []); + changePage(pagedData.page, pagedData.pageSize); + }, [changePage, pagedData.page, pagedData.pageSize]); return ( diff --git a/src/modules/manager/sites/components/SitesTable.tsx b/src/modules/manager/sites/components/SitesTable.tsx index 5aa49d6..1440eb7 100644 --- a/src/modules/manager/sites/components/SitesTable.tsx +++ b/src/modules/manager/sites/components/SitesTable.tsx @@ -17,7 +17,6 @@ const SitesTable: React.FC> = ({ onSort, }) => { const { t } = useTranslation(); - const canViewSpecification = authentication.hasAccess("ViewSpecification"); const columns: Column[] = useMemo( () => [ @@ -37,7 +36,7 @@ const SitesTable: React.FC> = ({ { key: "address", label: t("Address"), order: "asc" }, { key: "status", label: t("Status"), order: "asc" }, ], - [t, canViewSpecification], + [t], ); const raiseSort = (sortCol: Column) => { diff --git a/src/modules/manager/specifications/Specifications.tsx b/src/modules/manager/specifications/Specifications.tsx index beedea3..11a15c8 100644 --- a/src/modules/manager/specifications/Specifications.tsx +++ b/src/modules/manager/specifications/Specifications.tsx @@ -1,106 +1,130 @@ -import React, { Component } from 'react'; -import Column from '../../../components/common/columns'; -import { Paginated } from '../../../services/Paginated'; -import Button, { ButtonType } from '../../../components/common/Button'; -import withRouter from '../../../utils/withRouter'; -import specificationService, { ReadSpecification } from './services/specificationService'; -import SpecificationsTable from './components/SpecificationsTable'; -import Loading from '../../../components/common/Loading'; -import Permission from '../../../components/common/Permission'; +import React, { Component } from "react"; +import Column from "../../../components/common/columns"; +import { Paginated } from "../../../services/Paginated"; +import Button, { ButtonType } from "../../../components/common/Button"; +import withRouter from "../../../utils/withRouter"; +import specificationService, { + ReadSpecification, +} from "./services/specificationService"; +import SpecificationsTable from "./components/SpecificationsTable"; +import Loading from "../../../components/common/Loading"; +import Permission from "../../../components/common/Permission"; -interface SpecificationsState{ - loaded: boolean; - pagedData : Paginated, - sortColumn : Column, - filters: Map; +interface SpecificationsState { + loaded: boolean; + pagedData: Paginated; + sortColumn: Column; + filters: Map; } class LocSpecifications extends Component { - state = { - loaded : false, - pagedData : { page: 1, - pageSize : 10, - count: 0, - totalPages: 1, - data: [] - }, - sortColumn: { key: "name", label: "Name", order: "asc" }, - filters: new Map() + state = { + loaded: false, + pagedData: { page: 1, pageSize: 10, count: 0, totalPages: 1, data: [] }, + sortColumn: { key: "name", label: "Name", order: "asc" }, + filters: new Map(), + }; + + componentDidMount = async () => { + const { page, pageSize } = this.state.pagedData; + await this.changePage(page, pageSize); + }; + + changePage = async (page: number, pageSize: number) => { + const { sortColumn, filters } = this.state; + const { siteId } = this.props.router.params; + filters.set("site.id", siteId); + + const pagedData = await specificationService.GetSSpecifications( + page, + pageSize, + sortColumn.key, + sortColumn.order === "asc", + filters, + ); + if (pagedData) { + this.setState({ loaded: true, pagedData, filters }); + } else { + this.setState({ loaded: false }); } + }; - componentDidMount = async () => { - const { page, pageSize } = this.state.pagedData; - await this.changePage(page, pageSize); + onSort = async (sortColumn: Column) => { + const { page, pageSize } = this.state.pagedData; + const { filters } = this.state; + + const { siteId } = this.props.router.params; + filters.set("site.id", siteId); + + const pagedData = await specificationService.GetSSpecifications( + page, + pageSize, + sortColumn.key, + sortColumn.order === "asc", + filters, + ); + if (pagedData) { + this.setState({ loaded: true, pagedData, sortColumn }); + } else { + this.setState({ loaded: false }); } + }; - changePage = async (page: number, pageSize: number) => { - const { sortColumn, filters } = this.state; - const { siteId } = this.props.router.params; - filters.set("site.id", siteId); + onSearch = async (name: string, value: string) => { + const { page, pageSize } = this.state.pagedData; + const { sortColumn, filters } = this.state; + filters.set(name, value); - const pagedData = await specificationService.GetSSpecifications(page, pageSize, sortColumn.key, sortColumn.order === "asc", filters); - if (pagedData) { - this.setState({ loaded: true, pagedData, filters }); - } - else { - this.setState({ loaded: false }); - } + const { siteId } = this.props.router.params; + filters.set("site.id", siteId); + + const pagedData = await specificationService.GetSSpecifications( + page, + pageSize, + sortColumn.key, + sortColumn.order === "asc", + filters, + ); + if (pagedData) { + this.setState({ loaded: true, filters, pagedData }); + } else { + this.setState({ loaded: false }); } + }; - onSort = async (sortColumn: Column) => { - const { page, pageSize } = this.state.pagedData; - const { filters } = this.state; - - const { siteId } = this.props.router.params; - filters.set("site.id", siteId); - - const pagedData = await specificationService.GetSSpecifications(page, pageSize, sortColumn.key, sortColumn.order === "asc", filters); - if (pagedData) { - this.setState({ loaded: true, pagedData, sortColumn }); - } - else { - this.setState({ loaded: false }); - } + onDelete = async (item?: ReadSpecification) => { + const response = await specificationService.DeleteSpecification( + item?.id, + item?.guid, + ); + if (response) { + this.componentDidMount(); } + }; - onSearch = async (name: string, value: string) => { - const { page, pageSize } = this.state.pagedData; - const { sortColumn, filters } = this.state; - filters.set(name, value); + render(): JSX.Element { + const { loaded, pagedData, sortColumn } = this.state; - const { siteId } = this.props.router.params; - filters.set("site.id", siteId); - - const pagedData = await specificationService.GetSSpecifications(page, pageSize, sortColumn.key, sortColumn.order === "asc", filters); - if (pagedData) { - this.setState({ loaded: true, filters, pagedData }); - } - else { - this.setState({ loaded: false }); - } - }; - - onDelete = async (item?: ReadSpecification) => { - const response = await specificationService.DeleteSpecification(item?.id, item?.guid); - if (response) { - this.componentDidMount(); - } - } - - render(): JSX.Element { - const { loaded, pagedData, sortColumn } = this.state; - - return ( - - - - -
- -
- ); - } -}; + return ( + + + + +
+ +
+ ); + } +} const Specifications = withRouter(LocSpecifications); diff --git a/src/modules/manager/specifications/components/SpecificationsTable.tsx b/src/modules/manager/specifications/components/SpecificationsTable.tsx index 88c2ec8..9a056a2 100644 --- a/src/modules/manager/specifications/components/SpecificationsTable.tsx +++ b/src/modules/manager/specifications/components/SpecificationsTable.tsx @@ -1,45 +1,62 @@ -import React from "react"; +import React, { useMemo } from "react"; +import { useTranslation } from "react-i18next"; import Column from "../../../../components/common/columns"; -import Table, { PublishedTableProps } from "../../../../components/common/Table"; +import Table, { + PublishedTableProps, +} from "../../../../components/common/Table"; import authentication from "../../../frame/services/authenticationService"; import { ReadSpecification } from "../services/specificationService"; -class SpecificationsTable extends React.Component> { - columns: Column[] = [{ key: "name", label: "Name", order: "asc" }]; +const SpecificationsTable: React.FC> = ({ + data, + sortColumn, + onChangePage, + onSearch, + onDelete, + onSort, +}) => { + const { t } = useTranslation(); - raiseSort = (sortColumn: Column) => { - this.setState({ sortColumn }); - if (this.props.onSort !== undefined) this.props.onSort(sortColumn); + const columns: Column[] = useMemo( + () => [{ key: "name", label: t("Name"), order: "asc" }], + [t], + ); + + const raiseSort = (sortCol: Column) => { + if (onSort !== undefined) onSort(sortCol); + }; + + const handleAuditParams = (item: any) => { + return { + entityName: "e_suite.Database.Core.Tables.Printer.Specification", + primaryKey: `{"Id":${item.id}}`, }; + }; - handleAuditParams = (item: any) => { - return { - entityName: "e_suite.Database.Core.Tables.Printer.Specification", - primaryKey: '{"Id":' + item.id + "}", - }; - }; + const editPath = authentication.hasAccess("EditSpecification") + ? "{0}" + : undefined; + const doDelete = authentication.hasAccess("DeleteSpecification") + ? onDelete + : undefined; + const showAudit = authentication.hasAccess("ViewAuditLog") + ? handleAuditParams + : undefined; - render() { - const { data, sortColumn, onChangePage, onSearch, onDelete } = this.props; - const editPath = authentication.hasAccess("EditSpecification") ? "{0}" : undefined; - const doDelete = authentication.hasAccess("DeleteSpecification") ? onDelete : undefined; - const showAudit = authentication.hasAccess("ViewAuditLog") ? this.handleAuditParams : undefined; - - return ( - - ); - } -} + return ( +
+ ); +}; export default SpecificationsTable; diff --git a/src/modules/manager/ssoManager/components/ssoManagerTable.tsx b/src/modules/manager/ssoManager/components/ssoManagerTable.tsx index 4accb1b..8f5f9b7 100644 --- a/src/modules/manager/ssoManager/components/ssoManagerTable.tsx +++ b/src/modules/manager/ssoManager/components/ssoManagerTable.tsx @@ -1,45 +1,62 @@ -import React from "react"; +import React, { useMemo } from "react"; +import { useTranslation } from "react-i18next"; import Column from "../../../../components/common/columns"; -import Table, { PublishedTableProps } from "../../../../components/common/Table"; +import Table, { + PublishedTableProps, +} from "../../../../components/common/Table"; import authentication from "../../../frame/services/authenticationService"; import { GetSsoProvider } from "../services/ssoManagerService"; -class SsoManagerTable extends React.Component> { - columns: Column[] = [{ key: "name", label: "Name", order: "asc" }]; +const SsoManagerTable: React.FC> = ({ + data, + sortColumn, + onChangePage, + onSearch, + onDelete, + onSort, +}) => { + const { t } = useTranslation(); - raiseSort = (sortColumn: Column) => { - this.setState({ sortColumn }); - if (this.props.onSort !== undefined) this.props.onSort(sortColumn); + const columns: Column[] = useMemo( + () => [{ key: "name", label: t("Name"), order: "asc" }], + [t], + ); + + const raiseSort = (sortCol: Column) => { + if (onSort !== undefined) onSort(sortCol); + }; + + const handleAuditParams = (item: any) => { + return { + entityName: "e_suite.Database.Core.Tables.UserManager.SsoProvider", + primaryKey: `{"Id":${item.id}}`, }; + }; - handleAuditParams = (item: any) => { - return { - entityName: "e_suite.Database.Core.Tables.UserManager.SsoProvider", - primaryKey: '{"Id":' + item.id + "}", - }; - }; + const editPath = authentication.hasAccess("EditSsoProvider") + ? "edit/{0}" + : undefined; + const doDelete = authentication.hasAccess("DeleteSsoProvider") + ? onDelete + : undefined; + const showAudit = authentication.hasAccess("ViewAuditLog") + ? handleAuditParams + : undefined; - render() { - const { data, sortColumn, onChangePage, onSearch, onDelete } = this.props; - const editPath = authentication.hasAccess("EditSsoProvider") ? "edit/{0}" : undefined; - const doDelete = authentication.hasAccess("DeleteSsoProvider") ? onDelete : undefined; - const showAudit = authentication.hasAccess("ViewAuditLog") ? this.handleAuditParams : undefined; - - return ( -
- ); - } -} + return ( +
+ ); +}; export default SsoManagerTable; diff --git a/src/modules/manager/ssoManager/ssoManager.tsx b/src/modules/manager/ssoManager/ssoManager.tsx index bc301b1..e5fe1b1 100644 --- a/src/modules/manager/ssoManager/ssoManager.tsx +++ b/src/modules/manager/ssoManager/ssoManager.tsx @@ -1,97 +1,126 @@ -import React, { Component } from 'react'; -import Column from '../../../components/common/columns'; -import { Paginated } from '../../../services/Paginated'; -import SsoManagerTable from './components/ssoManagerTable'; -import ssoManagerService, { GetSsoProvider } from './services/ssoManagerService'; -import Button, { ButtonType } from '../../../components/common/Button'; -import Loading from '../../../components/common/Loading'; -import Permission from '../../../components/common/Permission'; +import React, { useCallback, useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; +import Column from "../../../components/common/columns"; +import { Paginated } from "../../../services/Paginated"; +import SsoManagerTable from "./components/ssoManagerTable"; +import ssoManagerService, { + GetSsoProvider, +} from "./services/ssoManagerService"; +import Button, { ButtonType } from "../../../components/common/Button"; +import Loading from "../../../components/common/Loading"; +import Permission from "../../../components/common/Permission"; -interface SsoManagerState{ - loaded: boolean; - pagedData : Paginated, - sortColumn : Column, - filters: Map; -} +const SsoManager: 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(), + ); -class SsoManager extends Component< any, any, SsoManagerState> { - state = { - loaded : false, - pagedData : { page: 1, - pageSize : 10, - count: 0, - totalPages: 1, - data: [] }, - sortColumn: { key: "name", label: "Name", order: "asc" }, - filters: new Map() + const changePage = useCallback( + async (page: number, pageSize: number) => { + const data = await ssoManagerService.getSsoProviders( + 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 ssoManagerService.getSsoProviders( + page, + pageSize, + newSortColumn.key, + newSortColumn.order === "asc", + filters, + ); + if (data) { + setLoaded(true); + setPagedData(data); + setSortColumn(newSortColumn); + } else { + setLoaded(false); } + }; - componentDidMount = async () => { - const { page, pageSize } = this.state.pagedData; + const onSearch = async (name: string, value: string) => { + const { page, pageSize } = pagedData; + const newFilters = new Map(filters); + newFilters.set(name, value); - await this.changePage(page, pageSize); + const data = await ssoManagerService.getSsoProviders( + page, + pageSize, + sortColumn.key, + sortColumn.order === "asc", + newFilters, + ); + if (data) { + setLoaded(true); + setFilters(newFilters); + setPagedData(data); + } else { + setLoaded(false); } + }; - changePage = async(page: number, pageSize : number) =>{ - const { sortColumn, filters } = this.state; - - const pagedData = await ssoManagerService.getSsoProviders(page, pageSize, sortColumn.key, sortColumn.order === "asc", filters); - if (pagedData) { - this.setState({ loaded: true, pagedData }); - } - else { - this.setState({ loaded: false }); - } + const onDelete = async (keyValue?: GetSsoProvider) => { + const response = await ssoManagerService.deleteSsoProvider( + keyValue?.id, + keyValue?.guid, + ); + if (response) { + await changePage(pagedData.page, pagedData.pageSize); } + }; - onSort = async(sortColumn : Column) => { - const {page, pageSize } = this.state.pagedData; - const { filters } = this.state; - const pagedData = await ssoManagerService.getSsoProviders(page, pageSize, sortColumn.key, sortColumn.order === "asc", filters); - if (pagedData) { - this.setState({ loaded: true, pagedData, sortColumn }); - } - else { - this.setState({ loaded: false }); - } - } + useEffect(() => { + changePage(pagedData.page, pagedData.pageSize); + }, [changePage, pagedData.page, pagedData.pageSize]); - onSearch = async ( name: string, value: string) => { - const {page, pageSize } = this.state.pagedData; - const {sortColumn, filters } = this.state; - filters.set(name, value); - - const pagedData = await ssoManagerService.getSsoProviders(page, pageSize, sortColumn.key, sortColumn.order === "asc", filters); - if (pagedData) { - this.setState({ loaded: true, filters, pagedData }); - } - else { - this.setState({ loaded: false }); - } - }; - - onDelete = async ( keyValue? : GetSsoProvider) => { - const response = await ssoManagerService.deleteSsoProvider( keyValue?.id, keyValue?.guid); - if (response) { - this.componentDidMount(); - } - } - - render(): JSX.Element { - const { loaded, pagedData, sortColumn } = this.state; - - return ( - - -
- -
-
-
- -
- ); - } + return ( + + +
+ +
+
+
+ +
+ ); }; export default SsoManager; diff --git a/src/modules/manager/users/UserDetails.tsx b/src/modules/manager/users/UserDetails.tsx index bde8f47..f787ac3 100644 --- a/src/modules/manager/users/UserDetails.tsx +++ b/src/modules/manager/users/UserDetails.tsx @@ -1,40 +1,30 @@ import React from "react"; +import { useTranslation } from "react-i18next"; import HorizontalTabs from "../../../components/common/HorizionalTabs"; import Tab from "../../../components/common/Tab"; import GeneralTab from "./components/GeneralTab"; interface UserDetailsProps { - editMode : boolean; + editMode: boolean; } -class UserDetails extends React.Component { - isEditMode = () => { - const { editMode } = this.props; - return editMode; - }; +const UserDetails: React.FC = ({ editMode }) => { + const { t } = useTranslation(); - render() { - const isEditMode = this.isEditMode(); + const heading = editMode ? t("EditUser") : t("AddUser"); - let mode = "Add"; - if (isEditMode) mode = "Edit"; + const tabs: JSX.Element[] = [ + + + , + ]; - - let tabs : JSX.Element[] = []; - - tabs.push( - - ); - - return ( -
-

{mode} User

- - {tabs} - -
- ); - } -} + return ( +
+

{heading}

+ {tabs} +
+ ); +}; export default UserDetails; diff --git a/src/modules/manager/users/components/usersTable.tsx b/src/modules/manager/users/components/usersTable.tsx index e63c19b..11ce861 100644 --- a/src/modules/manager/users/components/usersTable.tsx +++ b/src/modules/manager/users/components/usersTable.tsx @@ -1,6 +1,9 @@ -import React from "react"; +import React, { useCallback, useMemo } from "react"; +import { useTranslation } from "react-i18next"; import Column from "../../../../components/common/columns"; -import Table, { PublishedTableProps } from "../../../../components/common/Table"; +import Table, { + PublishedTableProps, +} from "../../../../components/common/Table"; import { GetUser } from "../services/usersService"; import Button, { ButtonType } from "../../../../components/common/Button"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; @@ -8,83 +11,99 @@ import { faEnvelope } from "@fortawesome/free-solid-svg-icons"; import authentication from "../../../frame/services/authenticationService"; export interface UsersTableProps extends PublishedTableProps { - resendConfirmEmail?: (user: GetUser) => void; + resendConfirmEmail?: (user: GetUser) => void; } -class UsersTable extends React.Component { - canResendConfirmMail = authentication.hasAccess("ResendConfirmMail"); +const UsersTable: React.FC = ({ + data, + sortColumn, + onChangePage, + onSearch, + onDelete, + onSort, + resendConfirmEmail, +}) => { + const { t } = useTranslation(); + const canResendConfirmMail = authentication.hasAccess("ResendConfirmMail"); - columns: Column[] = [ - { key: "displayName", label: "Name", order: "asc" }, - { key: "email", label: "Email", order: "asc" }, - { key: "domainName", label: "Domain", order: "asc" }, - { key: "created", label: "Created", order: "asc" }, - { key: "lastUpdated", label: "Last Updated", order: "asc" }, - { - key: "emailConfirmed", - label: "Resend Confirm", - order: "asc", - searchable: false, - content: (item) => { - if (!item!.emailConfirmed && this.canResendConfirmMail) { - return ( - <> - - - ); - } - return <>; - }, + const resendConfirmEmailHandler = useCallback( + (keyValue: GetUser) => { + if (resendConfirmEmail != null) resendConfirmEmail(keyValue); + }, + [resendConfirmEmail], + ); + + const columns: Column[] = useMemo( + () => [ + { key: "displayName", label: t("Name"), order: "asc" }, + { key: "email", label: t("Email"), order: "asc" }, + { key: "domainName", label: t("Domain"), order: "asc" }, + { key: "created", label: t("Created"), order: "asc" }, + { key: "lastUpdated", label: t("LastUpdated"), order: "asc" }, + { + key: "emailConfirmed", + label: t("ResendConfirm"), + order: "asc", + searchable: false, + content: (item) => { + if (!item.emailConfirmed && canResendConfirmMail) { + return ( + + ); + } + return <>; }, - ]; + }, + ], + [t, canResendConfirmMail, resendConfirmEmailHandler], + ); - resendConfirmEmail = (keyValue: GetUser) => { - const { resendConfirmEmail } = this.props; + const raiseSort = (sortCol: Column) => { + if (onSort !== undefined) onSort(sortCol); + }; - if (resendConfirmEmail != null) resendConfirmEmail(keyValue!); + const handleAuditParams = (item: any) => { + return { + entityName: "e_suite.Database.Core.Tables.UserManager.User", + primaryKey: `{"Id":${item.id}}`, }; + }; - raiseSort = (sortColumn: Column) => { - this.setState({ sortColumn }); - if (this.props.onSort !== undefined) this.props.onSort(sortColumn); - }; + const canDelete = (item: GetUser) => { + const user = authentication.getCurrentUser(); + return item.id !== user!.primarysid; + }; - handleAuditParams = (item: any) => { - return { - entityName: "e_suite.Database.Core.Tables.UserManager.User", - primaryKey: '{"Id":' + item.id + "}", - }; - }; + const editPath = authentication.hasAccess("EditUser") + ? "edit/{0}" + : undefined; + const doDelete = authentication.hasAccess("DeleteUser") + ? onDelete + : undefined; + const showAudit = authentication.hasAccess("ViewAuditLog") + ? handleAuditParams + : undefined; - canDelete = (item: GetUser) => { - const user = authentication.getCurrentUser(); - return item.id != user!.primarysid; - }; - - render() { - const { data, sortColumn, onChangePage, onSearch, onDelete } = this.props; - const editPath = authentication.hasAccess("EditUser") ? "edit/{0}" : undefined; - const doDelete = authentication.hasAccess("DeleteUser") ? onDelete : undefined; - const showAudit = authentication.hasAccess("ViewAuditLog") ? this.handleAuditParams : undefined; - - return ( -
- ); - } -} + return ( +
+ ); +}; export default UsersTable; diff --git a/src/modules/manager/users/users.tsx b/src/modules/manager/users/users.tsx index 42f96cf..7b0270a 100644 --- a/src/modules/manager/users/users.tsx +++ b/src/modules/manager/users/users.tsx @@ -1,103 +1,131 @@ -import React, { Component } from 'react'; -import Column from '../../../components/common/columns'; -import { Paginated } from '../../../services/Paginated'; -import UsersTable from './components/usersTable'; -import userService, { GetUser } from './services/usersService'; -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 React, { useCallback, useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; +import Column from "../../../components/common/columns"; +import { Paginated } from "../../../services/Paginated"; +import UsersTable from "./components/usersTable"; +import userService, { GetUser } from "./services/usersService"; +import Button, { ButtonType } from "../../../components/common/Button"; +import { toast } from "react-toastify"; +import Loading from "../../../components/common/Loading"; +import Permission from "../../../components/common/Permission"; -interface UsersState{ - loaded: boolean, - pagedData : Paginated, - sortColumn : Column, - filters: Map; -} +const Users: 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: "displayName", + label: t("Name"), + order: "asc", + }); + const [filters, setFilters] = useState>( + new Map(), + ); -class Users extends Component< any, any, UsersState> { - state = { - loaded: false, - pagedData : { page: 1, - pageSize : 10, - count: 0, - totalPages: 1, - data: [] }, - sortColumn: { key: "displayName", label: "Name", order: "asc" }, - filters: new Map() + const changePage = useCallback( + async (page: number, pageSize: number) => { + const data = await userService.getUsers( + 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 userService.getUsers( + page, + pageSize, + newSortColumn.key, + newSortColumn.order === "asc", + filters, + ); + + if (data) { + setLoaded(true); + setPagedData(data); + setSortColumn(newSortColumn); + } else { + setLoaded(false); } + }; - componentDidMount = async () => { - const { page, pageSize } = this.state.pagedData; + const onSearch = async (name: string, value: string) => { + const { page, pageSize } = pagedData; + const newFilters = new Map(filters); + newFilters.set(name, value); + const data = await userService.getUsers( + page, + pageSize, + sortColumn.key, + sortColumn.order === "asc", + newFilters, + ); - await this.changePage(page, pageSize); + if (data) { + setLoaded(true); + setFilters(newFilters); + setPagedData(data); + } else { + setLoaded(false); } + }; - changePage = async(page: number, pageSize : number) =>{ - const { sortColumn, filters } = this.state; - - const pagedData = await userService.getUsers(page, pageSize, sortColumn.key, sortColumn.order === "asc", filters); - if(pagedData) { - this.setState({ loaded: true, pagedData }); - } else { - this.setState({ loaded: false }); - } + const onDelete = async (item?: GetUser) => { + const response = await userService.deleteUser(item?.id, item?.guid); + if (response) { + await changePage(pagedData.page, pagedData.pageSize); } + }; - onSort = async(sortColumn : Column) => { - const {page, pageSize } = this.state.pagedData; - const { filters } = this.state; - const pagedData = await userService.getUsers(page, pageSize, sortColumn.key, sortColumn.order === "asc", filters); - - if (pagedData) { - this.setState({ loaded: true, pagedData, sortColumn}); - } else { - this.setState({ loaded: false }); - } + const resentConfirmEmail = async (user: GetUser) => { + const response = await userService.resendConfirmEmail(user.id, user.guid); + if (response) { + toast.info(t("ConfirmEmailResent")); } + }; - onSearch = async ( name: string, value: string) => { - const {page, pageSize } = this.state.pagedData; - const {sortColumn, filters } = this.state; - filters.set(name, value); - const pagedData = await userService.getUsers(page, pageSize, sortColumn.key, sortColumn.order === "asc", filters); + useEffect(() => { + changePage(pagedData.page, pagedData.pageSize); + }, [changePage, pagedData.page, pagedData.pageSize]); - if (pagedData) { - this.setState( { loaded: true, filters, pagedData }); - } else { - this.setState({ loaded: false }); - } - }; - - onDelete = async ( item? : GetUser) => { - const response = await userService.deleteUser( item?.id, item?.guid); - if (response) { - this.componentDidMount(); - } - } - - resentConfirmEmail = async (user: GetUser) => { - const response = await userService.resendConfirmEmail( user.id, user.guid); - if (response) { - toast.info("Confirm e-mail resent"); - } - } - - render(): JSX.Element { - const { loaded, pagedData, sortColumn } = this.state; - - return ( - - -
- -
-
-
- -
- ); - } + return ( + + +
+ +
+
+
+ +
+ ); }; export default Users;