Next round of refactoring done

This commit is contained in:
Colin Dawson 2026-01-30 23:54:14 +00:00
parent 9c7959cec8
commit 81a01fe9f3
15 changed files with 769 additions and 612 deletions

View File

@ -2,6 +2,7 @@
"Activate": "Activate", "Activate": "Activate",
"Add": "Add", "Add": "Add",
"AddDomain": "Add Domain", "AddDomain": "Add Domain",
"AddUser": "Add User",
"Address": "Address", "Address": "Address",
"Admin": "Admin", "Admin": "Admin",
"AnEmailWithPasswordResetLinkHasBeenSent": "An email with a password reset link has been sent.", "AnEmailWithPasswordResetLinkHasBeenSent": "An email with a password reset link has been sent.",
@ -15,16 +16,22 @@
"BlockedIPs": "Blocked IPs", "BlockedIPs": "Blocked IPs",
"Cancel": "Cancel", "Cancel": "Cancel",
"Changes": "Changes", "Changes": "Changes",
"Confirm": "Confirm",
"ConfirmEmailResent": "Confirm e-mail resent",
"ClientDomainManager": "Client Domain Manager", "ClientDomainManager": "Client Domain Manager",
"ClientDomains": "Client Domains", "ClientDomains": "Client Domains",
"Comment": "Comment", "Comment": "Comment",
"ConfirmPassword": "Confirm Password", "ConfirmPassword": "Confirm Password",
"CustomFieldManager": "Custom Field Manager", "CustomFieldManager": "Custom Field Manager",
"CustomFields": "Custom Fields", "CustomFields": "Custom Fields",
"Created": "Created",
"DisableAuthenticator": "Disable Authenticator", "DisableAuthenticator": "Disable Authenticator",
"DisplayName": "Display Name", "DisplayName": "Display Name",
"Domain": "Domain",
"Email": "Email",
"Edit": "Edit", "Edit": "Edit",
"EditDomain": "Edit Domain", "EditDomain": "Edit Domain",
"EditUser": "Edit User",
"e-print": "e-print", "e-print": "e-print",
"e-suite": "e-suite", "e-suite": "e-suite",
"e-suiteLogo": "e-suite logo", "e-suiteLogo": "e-suite logo",
@ -45,6 +52,7 @@
"IPAddress": "IP Address", "IPAddress": "IP Address",
"IPAddressUnblocked": "IP Address '{{ip}}' unblocked.", "IPAddressUnblocked": "IP Address '{{ip}}' unblocked.",
"Items": "Items", "Items": "Items",
"LastUpdated": "Last Updated",
"Loading": "Loading", "Loading": "Loading",
"LoggingOut": "Logging out", "LoggingOut": "Logging out",
"MailTemplates": "Mail Templates", "MailTemplates": "Mail Templates",
@ -62,6 +70,7 @@
"PasswordsMustMatch": "You need to confirm by typing exactly the same as the new password", "PasswordsMustMatch": "You need to confirm by typing exactly the same as the new password",
"PressAgainToUnblock": "Press again to unblock", "PressAgainToUnblock": "Press again to unblock",
"ResetPassword": "Reset Password", "ResetPassword": "Reset Password",
"ResendConfirm": "Resend Confirm",
"RoleAccess": "Role Access", "RoleAccess": "Role Access",
"RoleAccessUpdated": "Role access updated successfully.", "RoleAccessUpdated": "Role access updated successfully.",
"SecurityRoles": "Security Roles", "SecurityRoles": "Security Roles",

View File

@ -1,4 +1,4 @@
import React, { useEffect, useState } from "react"; import React, { useCallback, useEffect, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import Column from "../../../components/common/columns"; import Column from "../../../components/common/columns";
import { Paginated } from "../../../services/Paginated"; import { Paginated } from "../../../services/Paginated";
@ -30,15 +30,8 @@ const Domains: React.FC = () => {
() => new Map<string, string>(), () => new Map<string, string>(),
); );
useEffect(() => { const changePage = useCallback(
const loadInitial = async () => { async (page: number, pageSize: number) => {
await changePage(initialPagedData.page, initialPagedData.pageSize);
};
void loadInitial();
}, []);
const changePage = async (page: number, pageSize: number) => {
const pagedDataResult = await domainsService.getDomains( const pagedDataResult = await domainsService.getDomains(
page, page,
pageSize, pageSize,
@ -52,8 +45,18 @@ const Domains: React.FC = () => {
} else { } else {
setLoaded(false); setLoaded(false);
} }
},
[filters, sortColumn.key, sortColumn.order],
);
useEffect(() => {
const loadInitial = async () => {
await changePage(initialPagedData.page, initialPagedData.pageSize);
}; };
void loadInitial();
}, [changePage]);
const onSort = async (nextSortColumn: Column<GetDomain>) => { const onSort = async (nextSortColumn: Column<GetDomain>) => {
const { page, pageSize } = pagedData; const { page, pageSize } = pagedData;
const pagedDataResult = await domainsService.getDomains( const pagedDataResult = await domainsService.getDomains(

View File

@ -1,7 +1,6 @@
import React, { useEffect, useState } from "react"; import React, { useCallback, useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { toast } from "react-toastify"; import { toast } from "react-toastify";
import Column from "../../../../components/common/columns";
import { Paginated } from "../../../../services/Paginated"; import { Paginated } from "../../../../services/Paginated";
import { MakeGeneralIdRef } from "../../../../utils/GeneralIdRef"; import { MakeGeneralIdRef } from "../../../../utils/GeneralIdRef";
import withRouter, { RouterProps } from "../../../../utils/withRouter"; import withRouter, { RouterProps } from "../../../../utils/withRouter";
@ -40,17 +39,15 @@ const RoleAccessEditorNoRouter: React.FC<RoleAccessEditorProps> = ({
const [loaded, setLoaded] = useState(false); const [loaded, setLoaded] = useState(false);
const [accessList, setAccessList] = const [accessList, setAccessList] =
useState<Paginated<GetSecurityAccess>>(initialAccessList); useState<Paginated<GetSecurityAccess>>(initialAccessList);
const [accessRightsForRole, setAccessRightsForRole] =
useState<Paginated<GetRoleSecurityAccess>>(initialPagedData);
const [pagedData, setPagedData] = const [pagedData, setPagedData] =
useState<Paginated<GetRoleSecurityAccess>>(initialPagedData); useState<Paginated<GetRoleSecurityAccess>>(initialPagedData);
const [sortColumn] = useState<Column<GetRoleSecurityAccess>>({ const roleGeneralIdRef = useMemo(
key: "name", () => MakeGeneralIdRef(role?.id, role?.guid),
label: t("Name"), [role?.id, role?.guid],
order: "asc", );
});
const isItemSelected = ( const isItemSelected = useCallback(
(
securityAccess: string, securityAccess: string,
roleAccessList: unknown[] | undefined, roleAccessList: unknown[] | undefined,
): boolean => { ): boolean => {
@ -60,9 +57,12 @@ const RoleAccessEditorNoRouter: React.FC<RoleAccessEditorProps> = ({
(x) => (x as any).securityAccess === securityAccess, (x) => (x as any).securityAccess === securityAccess,
); );
return filtered.length > 0; return filtered.length > 0;
}; },
[],
);
const compileAccessRightsPagedData = ( const compileAccessRightsPagedData = useCallback(
(
masterList: GetSecurityAccess[] | undefined, masterList: GetSecurityAccess[] | undefined,
roleAccessList: unknown[] | undefined, roleAccessList: unknown[] | undefined,
): Paginated<GetRoleSecurityAccess> => { ): Paginated<GetRoleSecurityAccess> => {
@ -93,9 +93,12 @@ const RoleAccessEditorNoRouter: React.FC<RoleAccessEditorProps> = ({
totalPages: 1, totalPages: 1,
data: accessRightsForRoleData, data: accessRightsForRoleData,
}; };
}; },
[isItemSelected],
);
const changePage = async (nextAccessList?: Paginated<GetSecurityAccess>) => { const changePage = useCallback(
async (nextAccessList?: Paginated<GetSecurityAccess>) => {
const list = nextAccessList || accessList; const list = nextAccessList || accessList;
const roleAccessFilters = new Map<string, string>(); const roleAccessFilters = new Map<string, string>();
@ -115,15 +118,17 @@ const RoleAccessEditorNoRouter: React.FC<RoleAccessEditorProps> = ({
); );
if (nextPagedData) { if (nextPagedData) {
setLoaded(true); setLoaded(true);
setAccessRightsForRole(accessRightsResponse);
setPagedData(nextPagedData); setPagedData(nextPagedData);
} }
} else { } else {
setLoaded(false); setLoaded(false);
} }
}; },
[accessList, compileAccessRightsPagedData, role?.id],
);
const updatePage = async (nextAccessList?: Paginated<GetSecurityAccess>) => { const updatePage = useCallback(
async (nextAccessList?: Paginated<GetSecurityAccess>) => {
if (nextAccessList && nextAccessList.count === 0) { if (nextAccessList && nextAccessList.count === 0) {
const list = await roleService.getAccessList(0, 10, "name", true); const list = await roleService.getAccessList(0, 10, "name", true);
setAccessList(list); setAccessList(list);
@ -131,7 +136,9 @@ const RoleAccessEditorNoRouter: React.FC<RoleAccessEditorProps> = ({
} else { } else {
await changePage(nextAccessList); await changePage(nextAccessList);
} }
}; },
[changePage],
);
useEffect(() => { useEffect(() => {
const loadInitial = async () => { const loadInitial = async () => {
@ -144,10 +151,9 @@ const RoleAccessEditorNoRouter: React.FC<RoleAccessEditorProps> = ({
}; };
void loadInitial(); void loadInitial();
}, [role?.id]); }, [accessList, updatePage, role?.id]);
const handleSave = async (additions: string[], deletions: string[]) => { const handleSave = async (additions: string[], deletions: string[]) => {
const roleGeneralIdRef = MakeGeneralIdRef(role?.id, role?.guid);
let response = undefined; let response = undefined;
if (additions.length > 0) { if (additions.length > 0) {

View File

@ -1,4 +1,4 @@
import React, { useEffect, useState } from "react"; import React, { useCallback, useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import Column from "../../../../components/common/columns"; import Column from "../../../../components/common/columns";
import { Paginated } from "../../../../services/Paginated"; import { Paginated } from "../../../../services/Paginated";
@ -44,17 +44,13 @@ const RolesEditorTabNoRouter: React.FC<RolesEditorProps> = ({
); );
const { domainId } = router.params; const { domainId } = router.params;
const domainGeneralIdRef = MakeGeneralIdRef(domainId); const domainGeneralIdRef = useMemo(
() => MakeGeneralIdRef(domainId),
[domainId],
);
useEffect(() => { const changePage = useCallback(
const loadInitial = async () => { async (page: number, pageSize: number) => {
await changePage(initialPagedData.page, initialPagedData.pageSize);
};
void loadInitial();
}, [domainId]);
const changePage = async (page: number, pageSize: number) => {
const pagedDataResult = await roleService.getRoles( const pagedDataResult = await roleService.getRoles(
page, page,
pageSize, pageSize,
@ -69,8 +65,18 @@ const RolesEditorTabNoRouter: React.FC<RolesEditorProps> = ({
} else { } else {
setLoaded(false); setLoaded(false);
} }
},
[domainGeneralIdRef, filters, sortColumn.key, sortColumn.order],
);
useEffect(() => {
const loadInitial = async () => {
await changePage(initialPagedData.page, initialPagedData.pageSize);
}; };
void loadInitial();
}, [changePage, domainId]);
const onSort = async (nextSortColumn: Column<GetRoleResponse>) => { const onSort = async (nextSortColumn: Column<GetRoleResponse>) => {
const { page, pageSize } = pagedData; const { page, pageSize } = pagedData;

View File

@ -1,4 +1,4 @@
import React, { useEffect, useState } from "react"; import React, { useCallback, useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import Column from "../../../../components/common/columns"; import Column from "../../../../components/common/columns";
import { Paginated } from "../../../../services/Paginated"; import { Paginated } from "../../../../services/Paginated";
@ -39,9 +39,13 @@ const UserRoleEditorNoRouter: React.FC<UserRoleEditorProps> = ({
() => new Map<string, string>(), () => new Map<string, string>(),
); );
const roleGeneralIdRef = MakeGeneralIdRef(role?.id, role?.guid); const roleGeneralIdRef = useMemo(
() => MakeGeneralIdRef(role?.id, role?.guid),
[role?.id, role?.guid],
);
const getRoleUsers = async ( const getRoleUsers = useCallback(
async (
page: number, page: number,
pageSize: number, pageSize: number,
nextSortColumn: Column<RoleUser>, nextSortColumn: Column<RoleUser>,
@ -63,7 +67,9 @@ const UserRoleEditorNoRouter: React.FC<UserRoleEditorProps> = ({
} else { } else {
setLoaded(false); setLoaded(false);
} }
}; },
[roleGeneralIdRef],
);
useEffect(() => { useEffect(() => {
const loadInitial = async () => { const loadInitial = async () => {
@ -76,7 +82,7 @@ const UserRoleEditorNoRouter: React.FC<UserRoleEditorProps> = ({
}; };
void loadInitial(); void loadInitial();
}, [role?.id]); }, [getRoleUsers, role?.id, sortColumn]);
const changePage = async (page: number, pageSize: number) => { const changePage = async (page: number, pageSize: number) => {
await getRoleUsers(page, pageSize, sortColumn, filters); await getRoleUsers(page, pageSize, sortColumn, filters);

View File

@ -1,4 +1,4 @@
import { useState, useEffect } from "react"; import { useCallback, useEffect, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import Button, { ButtonType } from "../../../components/common/Button"; import Button, { ButtonType } from "../../../components/common/Button";
import Column from "../../../components/common/columns"; import Column from "../../../components/common/columns";
@ -28,7 +28,8 @@ const Forms: React.FC = () => {
new Map<string, string>(), new Map<string, string>(),
); );
const changePage = async (page: number, pageSize: number) => { const changePage = useCallback(
async (page: number, pageSize: number) => {
const data = await formsService.getForms( const data = await formsService.getForms(
page, page,
pageSize, pageSize,
@ -42,7 +43,9 @@ const Forms: React.FC = () => {
} else { } else {
setLoaded(false); setLoaded(false);
} }
}; },
[filters, sortColumn.key, sortColumn.order],
);
const onSort = async (newSortColumn: Column<GetFormResponse>) => { const onSort = async (newSortColumn: Column<GetFormResponse>) => {
const { page, pageSize } = pagedData; const { page, pageSize } = pagedData;
@ -91,9 +94,8 @@ const Forms: React.FC = () => {
}; };
useEffect(() => { useEffect(() => {
const { page, pageSize } = pagedData; changePage(pagedData.page, pagedData.pageSize);
changePage(page, pageSize); }, [changePage, pagedData.page, pagedData.pageSize]);
}, [pagedData]);
return ( return (
<Loading loaded={loaded}> <Loading loaded={loaded}>

View File

@ -1,4 +1,4 @@
import React, { useEffect, useState } from "react"; import React, { useCallback, useEffect, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import sequenceService, { ReadSequence } from "./services/sequenceService"; import sequenceService, { ReadSequence } from "./services/sequenceService";
import SequenceTable from "./components/squenceTable"; import SequenceTable from "./components/squenceTable";
@ -27,7 +27,8 @@ const Sequence: React.FC = () => {
new Map<string, string>(), new Map<string, string>(),
); );
const changePage = async (page: number, pageSize: number) => { const changePage = useCallback(
async (page: number, pageSize: number) => {
const data = await sequenceService.getSequences( const data = await sequenceService.getSequences(
page, page,
pageSize, pageSize,
@ -41,7 +42,9 @@ const Sequence: React.FC = () => {
} else { } else {
setLoaded(false); setLoaded(false);
} }
}; },
[filters, sortColumn.key, sortColumn.order],
);
const onSort = async (newSortColumn: Column<ReadSequence>) => { const onSort = async (newSortColumn: Column<ReadSequence>) => {
const { page, pageSize } = pagedData; const { page, pageSize } = pagedData;
@ -90,9 +93,8 @@ const Sequence: React.FC = () => {
}; };
useEffect(() => { useEffect(() => {
const { page, pageSize } = pagedData; changePage(pagedData.page, pagedData.pageSize);
changePage(page, pageSize); }, [changePage, pagedData.page, pagedData.pageSize]);
}, []);
return ( return (
<Loading loaded={loaded}> <Loading loaded={loaded}>

View File

@ -17,7 +17,6 @@ const SitesTable: React.FC<PublishedTableProps<ReadSite>> = ({
onSort, onSort,
}) => { }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const canViewSpecification = authentication.hasAccess("ViewSpecification");
const columns: Column<ReadSite>[] = useMemo( const columns: Column<ReadSite>[] = useMemo(
() => [ () => [
@ -37,7 +36,7 @@ const SitesTable: React.FC<PublishedTableProps<ReadSite>> = ({
{ key: "address", label: t("Address"), order: "asc" }, { key: "address", label: t("Address"), order: "asc" },
{ key: "status", label: t("Status"), order: "asc" }, { key: "status", label: t("Status"), order: "asc" },
], ],
[t, canViewSpecification], [t],
); );
const raiseSort = (sortCol: Column<ReadSite>) => { const raiseSort = (sortCol: Column<ReadSite>) => {

View File

@ -1,51 +1,53 @@
import React, { Component } from 'react'; import React, { Component } from "react";
import Column from '../../../components/common/columns'; import Column from "../../../components/common/columns";
import { Paginated } from '../../../services/Paginated'; import { Paginated } from "../../../services/Paginated";
import Button, { ButtonType } from '../../../components/common/Button'; import Button, { ButtonType } from "../../../components/common/Button";
import withRouter from '../../../utils/withRouter'; import withRouter from "../../../utils/withRouter";
import specificationService, { ReadSpecification } from './services/specificationService'; import specificationService, {
import SpecificationsTable from './components/SpecificationsTable'; ReadSpecification,
import Loading from '../../../components/common/Loading'; } from "./services/specificationService";
import Permission from '../../../components/common/Permission'; import SpecificationsTable from "./components/SpecificationsTable";
import Loading from "../../../components/common/Loading";
import Permission from "../../../components/common/Permission";
interface SpecificationsState { interface SpecificationsState {
loaded: boolean; loaded: boolean;
pagedData : Paginated<ReadSpecification>, pagedData: Paginated<ReadSpecification>;
sortColumn : Column<ReadSpecification>, sortColumn: Column<ReadSpecification>;
filters: Map<string, string>; filters: Map<string, string>;
} }
class LocSpecifications extends Component<any, any, SpecificationsState> { class LocSpecifications extends Component<any, any, SpecificationsState> {
state = { state = {
loaded: false, loaded: false,
pagedData : { page: 1, pagedData: { page: 1, pageSize: 10, count: 0, totalPages: 1, data: [] },
pageSize : 10,
count: 0,
totalPages: 1,
data: []
},
sortColumn: { key: "name", label: "Name", order: "asc" }, sortColumn: { key: "name", label: "Name", order: "asc" },
filters: new Map<string, string>() filters: new Map<string, string>(),
} };
componentDidMount = async () => { componentDidMount = async () => {
const { page, pageSize } = this.state.pagedData; const { page, pageSize } = this.state.pagedData;
await this.changePage(page, pageSize); await this.changePage(page, pageSize);
} };
changePage = async (page: number, pageSize: number) => { changePage = async (page: number, pageSize: number) => {
const { sortColumn, filters } = this.state; const { sortColumn, filters } = this.state;
const { siteId } = this.props.router.params; const { siteId } = this.props.router.params;
filters.set("site.id", siteId); filters.set("site.id", siteId);
const pagedData = await specificationService.GetSSpecifications(page, pageSize, sortColumn.key, sortColumn.order === "asc", filters); const pagedData = await specificationService.GetSSpecifications(
page,
pageSize,
sortColumn.key,
sortColumn.order === "asc",
filters,
);
if (pagedData) { if (pagedData) {
this.setState({ loaded: true, pagedData, filters }); this.setState({ loaded: true, pagedData, filters });
} } else {
else {
this.setState({ loaded: false }); this.setState({ loaded: false });
} }
} };
onSort = async (sortColumn: Column<ReadSpecification>) => { onSort = async (sortColumn: Column<ReadSpecification>) => {
const { page, pageSize } = this.state.pagedData; const { page, pageSize } = this.state.pagedData;
@ -54,14 +56,19 @@ class LocSpecifications extends Component<any, any, SpecificationsState> {
const { siteId } = this.props.router.params; const { siteId } = this.props.router.params;
filters.set("site.id", siteId); filters.set("site.id", siteId);
const pagedData = await specificationService.GetSSpecifications(page, pageSize, sortColumn.key, sortColumn.order === "asc", filters); const pagedData = await specificationService.GetSSpecifications(
page,
pageSize,
sortColumn.key,
sortColumn.order === "asc",
filters,
);
if (pagedData) { if (pagedData) {
this.setState({ loaded: true, pagedData, sortColumn }); this.setState({ loaded: true, pagedData, sortColumn });
} } else {
else {
this.setState({ loaded: false }); this.setState({ loaded: false });
} }
} };
onSearch = async (name: string, value: string) => { onSearch = async (name: string, value: string) => {
const { page, pageSize } = this.state.pagedData; const { page, pageSize } = this.state.pagedData;
@ -71,21 +78,29 @@ class LocSpecifications extends Component<any, any, SpecificationsState> {
const { siteId } = this.props.router.params; const { siteId } = this.props.router.params;
filters.set("site.id", siteId); filters.set("site.id", siteId);
const pagedData = await specificationService.GetSSpecifications(page, pageSize, sortColumn.key, sortColumn.order === "asc", filters); const pagedData = await specificationService.GetSSpecifications(
page,
pageSize,
sortColumn.key,
sortColumn.order === "asc",
filters,
);
if (pagedData) { if (pagedData) {
this.setState({ loaded: true, filters, pagedData }); this.setState({ loaded: true, filters, pagedData });
} } else {
else {
this.setState({ loaded: false }); this.setState({ loaded: false });
} }
}; };
onDelete = async (item?: ReadSpecification) => { onDelete = async (item?: ReadSpecification) => {
const response = await specificationService.DeleteSpecification(item?.id, item?.guid); const response = await specificationService.DeleteSpecification(
item?.id,
item?.guid,
);
if (response) { if (response) {
this.componentDidMount(); this.componentDidMount();
} }
} };
render(): JSX.Element { render(): JSX.Element {
const { loaded, pagedData, sortColumn } = this.state; const { loaded, pagedData, sortColumn } = this.state;
@ -93,14 +108,23 @@ class LocSpecifications extends Component<any, any, SpecificationsState> {
return ( return (
<Loading loaded={loaded}> <Loading loaded={loaded}>
<Permission privilegeKey="AddSpecification"> <Permission privilegeKey="AddSpecification">
<Button buttonType={ButtonType.primary} to="add">Add</Button> <Button buttonType={ButtonType.primary} to="add">
Add
</Button>
</Permission> </Permission>
<hr /> <hr />
<SpecificationsTable data={pagedData} sortColumn={sortColumn} onChangePage={this.changePage} onSort={this.onSort} onSearch={this.onSearch} onDelete={this.onDelete}/> <SpecificationsTable
data={pagedData}
sortColumn={sortColumn}
onChangePage={this.changePage}
onSort={this.onSort}
onSearch={this.onSearch}
onDelete={this.onDelete}
/>
</Loading> </Loading>
); );
} }
}; }
const Specifications = withRouter(LocSpecifications); const Specifications = withRouter(LocSpecifications);

View File

@ -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 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 authentication from "../../../frame/services/authenticationService";
import { ReadSpecification } from "../services/specificationService"; import { ReadSpecification } from "../services/specificationService";
class SpecificationsTable extends React.Component<PublishedTableProps<ReadSpecification>> { const SpecificationsTable: React.FC<PublishedTableProps<ReadSpecification>> = ({
columns: Column<ReadSpecification>[] = [{ key: "name", label: "Name", order: "asc" }]; data,
sortColumn,
onChangePage,
onSearch,
onDelete,
onSort,
}) => {
const { t } = useTranslation();
raiseSort = (sortColumn: Column<ReadSpecification>) => { const columns: Column<ReadSpecification>[] = useMemo(
this.setState({ sortColumn }); () => [{ key: "name", label: t("Name"), order: "asc" }],
if (this.props.onSort !== undefined) this.props.onSort(sortColumn); [t],
);
const raiseSort = (sortCol: Column<ReadSpecification>) => {
if (onSort !== undefined) onSort(sortCol);
}; };
handleAuditParams = (item: any) => { const handleAuditParams = (item: any) => {
return { return {
entityName: "e_suite.Database.Core.Tables.Printer.Specification", entityName: "e_suite.Database.Core.Tables.Printer.Specification",
primaryKey: '{"Id":' + item.id + "}", primaryKey: `{"Id":${item.id}}`,
}; };
}; };
render() { const editPath = authentication.hasAccess("EditSpecification")
const { data, sortColumn, onChangePage, onSearch, onDelete } = this.props; ? "{0}"
const editPath = authentication.hasAccess("EditSpecification") ? "{0}" : undefined; : undefined;
const doDelete = authentication.hasAccess("DeleteSpecification") ? onDelete : undefined; const doDelete = authentication.hasAccess("DeleteSpecification")
const showAudit = authentication.hasAccess("ViewAuditLog") ? this.handleAuditParams : undefined; ? onDelete
: undefined;
const showAudit = authentication.hasAccess("ViewAuditLog")
? handleAuditParams
: undefined;
return ( return (
<Table <Table
data={data} data={data}
keyName="id" keyName="id"
columns={this.columns} columns={columns}
sortColumn={sortColumn} sortColumn={sortColumn}
editPath={editPath} editPath={editPath}
onSort={this.raiseSort} onSort={raiseSort}
onChangePage={onChangePage} onChangePage={onChangePage}
onSearch={onSearch} onSearch={onSearch}
onDelete={doDelete} onDelete={doDelete}
onAuditParams={showAudit} onAuditParams={showAudit}
/> />
); );
} };
}
export default SpecificationsTable; export default SpecificationsTable;

View File

@ -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 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 authentication from "../../../frame/services/authenticationService";
import { GetSsoProvider } from "../services/ssoManagerService"; import { GetSsoProvider } from "../services/ssoManagerService";
class SsoManagerTable extends React.Component<PublishedTableProps<GetSsoProvider>> { const SsoManagerTable: React.FC<PublishedTableProps<GetSsoProvider>> = ({
columns: Column<GetSsoProvider>[] = [{ key: "name", label: "Name", order: "asc" }]; data,
sortColumn,
onChangePage,
onSearch,
onDelete,
onSort,
}) => {
const { t } = useTranslation();
raiseSort = (sortColumn: Column<GetSsoProvider>) => { const columns: Column<GetSsoProvider>[] = useMemo(
this.setState({ sortColumn }); () => [{ key: "name", label: t("Name"), order: "asc" }],
if (this.props.onSort !== undefined) this.props.onSort(sortColumn); [t],
);
const raiseSort = (sortCol: Column<GetSsoProvider>) => {
if (onSort !== undefined) onSort(sortCol);
}; };
handleAuditParams = (item: any) => { const handleAuditParams = (item: any) => {
return { return {
entityName: "e_suite.Database.Core.Tables.UserManager.SsoProvider", entityName: "e_suite.Database.Core.Tables.UserManager.SsoProvider",
primaryKey: '{"Id":' + item.id + "}", primaryKey: `{"Id":${item.id}}`,
}; };
}; };
render() { const editPath = authentication.hasAccess("EditSsoProvider")
const { data, sortColumn, onChangePage, onSearch, onDelete } = this.props; ? "edit/{0}"
const editPath = authentication.hasAccess("EditSsoProvider") ? "edit/{0}" : undefined; : undefined;
const doDelete = authentication.hasAccess("DeleteSsoProvider") ? onDelete : undefined; const doDelete = authentication.hasAccess("DeleteSsoProvider")
const showAudit = authentication.hasAccess("ViewAuditLog") ? this.handleAuditParams : undefined; ? onDelete
: undefined;
const showAudit = authentication.hasAccess("ViewAuditLog")
? handleAuditParams
: undefined;
return ( return (
<Table <Table
data={data} data={data}
keyName="id" keyName="id"
columns={this.columns} columns={columns}
sortColumn={sortColumn} sortColumn={sortColumn}
editPath={editPath} editPath={editPath}
onSort={this.raiseSort} onSort={raiseSort}
onChangePage={onChangePage} onChangePage={onChangePage}
onSearch={onSearch} onSearch={onSearch}
onDelete={doDelete} onDelete={doDelete}
onAuditParams={showAudit} onAuditParams={showAudit}
/> />
); );
} };
}
export default SsoManagerTable; export default SsoManagerTable;

View File

@ -1,97 +1,126 @@
import React, { Component } from 'react'; import React, { useCallback, useEffect, useState } from "react";
import Column from '../../../components/common/columns'; import { useTranslation } from "react-i18next";
import { Paginated } from '../../../services/Paginated'; import Column from "../../../components/common/columns";
import SsoManagerTable from './components/ssoManagerTable'; import { Paginated } from "../../../services/Paginated";
import ssoManagerService, { GetSsoProvider } from './services/ssoManagerService'; import SsoManagerTable from "./components/ssoManagerTable";
import Button, { ButtonType } from '../../../components/common/Button'; import ssoManagerService, {
import Loading from '../../../components/common/Loading'; GetSsoProvider,
import Permission from '../../../components/common/Permission'; } from "./services/ssoManagerService";
import Button, { ButtonType } from "../../../components/common/Button";
import Loading from "../../../components/common/Loading";
import Permission from "../../../components/common/Permission";
interface SsoManagerState{ const SsoManager: React.FC = () => {
loaded: boolean; const { t } = useTranslation();
pagedData : Paginated<GetSsoProvider>, const [loaded, setLoaded] = useState(false);
sortColumn : Column<GetSsoProvider>, const [pagedData, setPagedData] = useState<Paginated<GetSsoProvider>>({
filters: Map<string, string>; page: 1,
}
class SsoManager extends Component< any, any, SsoManagerState> {
state = {
loaded : false,
pagedData : { page: 1,
pageSize: 10, pageSize: 10,
count: 0, count: 0,
totalPages: 1, totalPages: 1,
data: [] }, data: [],
sortColumn: { key: "name", label: "Name", order: "asc" }, });
filters: new Map<string, string>() const [sortColumn, setSortColumn] = useState<Column<GetSsoProvider>>({
} key: "name",
label: t("Name"),
order: "asc",
});
const [filters, setFilters] = useState<Map<string, string>>(
new Map<string, string>(),
);
componentDidMount = async () => { const changePage = useCallback(
const { page, pageSize } = this.state.pagedData; 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],
);
await this.changePage(page, pageSize); const onSort = async (newSortColumn: Column<GetSsoProvider>) => {
} const { page, pageSize } = pagedData;
const data = await ssoManagerService.getSsoProviders(
changePage = async(page: number, pageSize : number) =>{ page,
const { sortColumn, filters } = this.state; pageSize,
newSortColumn.key,
const pagedData = await ssoManagerService.getSsoProviders(page, pageSize, sortColumn.key, sortColumn.order === "asc", filters); newSortColumn.order === "asc",
if (pagedData) { filters,
this.setState({ loaded: true, pagedData }); );
} if (data) {
else { setLoaded(true);
this.setState({ loaded: false }); setPagedData(data);
} setSortColumn(newSortColumn);
} } else {
setLoaded(false);
onSort = async(sortColumn : Column<GetSsoProvider>) => {
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 });
}
}
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 onSearch = async (name: string, value: string) => {
const response = await ssoManagerService.deleteSsoProvider( keyValue?.id, keyValue?.guid); const { page, pageSize } = pagedData;
if (response) { const newFilters = new Map(filters);
this.componentDidMount(); newFilters.set(name, value);
}
}
render(): JSX.Element { const data = await ssoManagerService.getSsoProviders(
const { loaded, pagedData, sortColumn } = this.state; page,
pageSize,
sortColumn.key,
sortColumn.order === "asc",
newFilters,
);
if (data) {
setLoaded(true);
setFilters(newFilters);
setPagedData(data);
} else {
setLoaded(false);
}
};
const onDelete = async (keyValue?: GetSsoProvider) => {
const response = await ssoManagerService.deleteSsoProvider(
keyValue?.id,
keyValue?.guid,
);
if (response) {
await changePage(pagedData.page, pagedData.pageSize);
}
};
useEffect(() => {
changePage(pagedData.page, pagedData.pageSize);
}, [changePage, pagedData.page, pagedData.pageSize]);
return ( return (
<Loading loaded={loaded}> <Loading loaded={loaded}>
<Permission privilegeKey="AddSsoProvider"> <Permission privilegeKey="AddSsoProvider">
<div> <div>
<Button buttonType={ButtonType.primary} to="add">Add</Button> <Button buttonType={ButtonType.primary} to="add">
{t("Add")}
</Button>
</div> </div>
</Permission> </Permission>
<hr /> <hr />
<SsoManagerTable data={pagedData} sortColumn={sortColumn} onChangePage={this.changePage} onSort={this.onSort} onSearch={this.onSearch} onDelete={this.onDelete}/> <SsoManagerTable
data={pagedData}
sortColumn={sortColumn}
onChangePage={changePage}
onSort={onSort}
onSearch={onSearch}
onDelete={onDelete}
/>
</Loading> </Loading>
); );
}
}; };
export default SsoManager; export default SsoManager;

View File

@ -1,4 +1,5 @@
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next";
import HorizontalTabs from "../../../components/common/HorizionalTabs"; import HorizontalTabs from "../../../components/common/HorizionalTabs";
import Tab from "../../../components/common/Tab"; import Tab from "../../../components/common/Tab";
import GeneralTab from "./components/GeneralTab"; import GeneralTab from "./components/GeneralTab";
@ -7,34 +8,23 @@ interface UserDetailsProps {
editMode: boolean; editMode: boolean;
} }
class UserDetails extends React.Component<UserDetailsProps> { const UserDetails: React.FC<UserDetailsProps> = ({ editMode }) => {
isEditMode = () => { const { t } = useTranslation();
const { editMode } = this.props;
return editMode;
};
render() { const heading = editMode ? t("EditUser") : t("AddUser");
const isEditMode = this.isEditMode();
let mode = "Add"; const tabs: JSX.Element[] = [
if (isEditMode) mode = "Edit"; <Tab key={1} label={t("General")}>
<GeneralTab isEditMode={editMode} />
</Tab>,
let tabs : JSX.Element[] = []; ];
tabs.push( <Tab key={1} label="General">
<GeneralTab isEditMode={isEditMode}/>
</Tab> );
return ( return (
<div> <div>
<h1>{mode} User</h1> <h1>{heading}</h1>
<HorizontalTabs> <HorizontalTabs>{tabs}</HorizontalTabs>
{tabs}
</HorizontalTabs>
</div> </div>
); );
} };
}
export default UserDetails; export default UserDetails;

View File

@ -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 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 { GetUser } from "../services/usersService";
import Button, { ButtonType } from "../../../../components/common/Button"; import Button, { ButtonType } from "../../../../components/common/Button";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
@ -11,80 +14,96 @@ export interface UsersTableProps extends PublishedTableProps<GetUser> {
resendConfirmEmail?: (user: GetUser) => void; resendConfirmEmail?: (user: GetUser) => void;
} }
class UsersTable extends React.Component<UsersTableProps> { const UsersTable: React.FC<UsersTableProps> = ({
canResendConfirmMail = authentication.hasAccess("ResendConfirmMail"); data,
sortColumn,
onChangePage,
onSearch,
onDelete,
onSort,
resendConfirmEmail,
}) => {
const { t } = useTranslation();
const canResendConfirmMail = authentication.hasAccess("ResendConfirmMail");
columns: Column<GetUser>[] = [ const resendConfirmEmailHandler = useCallback(
{ key: "displayName", label: "Name", order: "asc" }, (keyValue: GetUser) => {
{ key: "email", label: "Email", order: "asc" }, if (resendConfirmEmail != null) resendConfirmEmail(keyValue);
{ key: "domainName", label: "Domain", order: "asc" }, },
{ key: "created", label: "Created", order: "asc" }, [resendConfirmEmail],
{ key: "lastUpdated", label: "Last Updated", order: "asc" }, );
const columns: Column<GetUser>[] = 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", key: "emailConfirmed",
label: "Resend Confirm", label: t("ResendConfirm"),
order: "asc", order: "asc",
searchable: false, searchable: false,
content: (item) => { content: (item) => {
if (!item!.emailConfirmed && this.canResendConfirmMail) { if (!item.emailConfirmed && canResendConfirmMail) {
return ( return (
<> <Button
<Button buttonType={ButtonType.secondary} onClick={() => this.resendConfirmEmail(item)}> buttonType={ButtonType.secondary}
<FontAwesomeIcon icon={faEnvelope} /> Confirm onClick={() => resendConfirmEmailHandler(item)}
>
<FontAwesomeIcon icon={faEnvelope} /> {t("Confirm")}
</Button> </Button>
</>
); );
} }
return <></>; return <></>;
}, },
}, },
]; ],
[t, canResendConfirmMail, resendConfirmEmailHandler],
);
resendConfirmEmail = (keyValue: GetUser) => { const raiseSort = (sortCol: Column<GetUser>) => {
const { resendConfirmEmail } = this.props; if (onSort !== undefined) onSort(sortCol);
if (resendConfirmEmail != null) resendConfirmEmail(keyValue!);
}; };
raiseSort = (sortColumn: Column<GetUser>) => { const handleAuditParams = (item: any) => {
this.setState({ sortColumn });
if (this.props.onSort !== undefined) this.props.onSort(sortColumn);
};
handleAuditParams = (item: any) => {
return { return {
entityName: "e_suite.Database.Core.Tables.UserManager.User", entityName: "e_suite.Database.Core.Tables.UserManager.User",
primaryKey: '{"Id":' + item.id + "}", primaryKey: `{"Id":${item.id}}`,
}; };
}; };
canDelete = (item: GetUser) => { const canDelete = (item: GetUser) => {
const user = authentication.getCurrentUser(); const user = authentication.getCurrentUser();
return item.id != user!.primarysid; return item.id !== user!.primarysid;
}; };
render() { const editPath = authentication.hasAccess("EditUser")
const { data, sortColumn, onChangePage, onSearch, onDelete } = this.props; ? "edit/{0}"
const editPath = authentication.hasAccess("EditUser") ? "edit/{0}" : undefined; : undefined;
const doDelete = authentication.hasAccess("DeleteUser") ? onDelete : undefined; const doDelete = authentication.hasAccess("DeleteUser")
const showAudit = authentication.hasAccess("ViewAuditLog") ? this.handleAuditParams : undefined; ? onDelete
: undefined;
const showAudit = authentication.hasAccess("ViewAuditLog")
? handleAuditParams
: undefined;
return ( return (
<Table <Table
data={data} data={data}
keyName="id" keyName="id"
columns={this.columns} columns={columns}
sortColumn={sortColumn} sortColumn={sortColumn}
editPath={editPath} editPath={editPath}
onSort={this.raiseSort} onSort={raiseSort}
onChangePage={onChangePage} onChangePage={onChangePage}
onSearch={onSearch} onSearch={onSearch}
onDelete={doDelete} onDelete={doDelete}
onAuditParams={showAudit} onAuditParams={showAudit}
canDelete={this.canDelete} canDelete={canDelete}
/> />
); );
} };
}
export default UsersTable; export default UsersTable;

View File

@ -1,103 +1,131 @@
import React, { Component } from 'react'; import React, { useCallback, useEffect, useState } from "react";
import Column from '../../../components/common/columns'; import { useTranslation } from "react-i18next";
import { Paginated } from '../../../services/Paginated'; import Column from "../../../components/common/columns";
import UsersTable from './components/usersTable'; import { Paginated } from "../../../services/Paginated";
import userService, { GetUser } from './services/usersService'; import UsersTable from "./components/usersTable";
import Button, { ButtonType } from '../../../components/common/Button'; import userService, { GetUser } from "./services/usersService";
import { toast } from 'react-toastify'; import Button, { ButtonType } from "../../../components/common/Button";
import Loading from '../../../components/common/Loading'; import { toast } from "react-toastify";
import Permission from '../../../components/common/Permission'; import Loading from "../../../components/common/Loading";
import Permission from "../../../components/common/Permission";
interface UsersState{ const Users: React.FC = () => {
loaded: boolean, const { t } = useTranslation();
pagedData : Paginated<GetUser>, const [loaded, setLoaded] = useState(false);
sortColumn : Column<GetUser>, const [pagedData, setPagedData] = useState<Paginated<GetUser>>({
filters: Map<string, string>; page: 1,
}
class Users extends Component< any, any, UsersState> {
state = {
loaded: false,
pagedData : { page: 1,
pageSize: 10, pageSize: 10,
count: 0, count: 0,
totalPages: 1, totalPages: 1,
data: [] }, data: [],
sortColumn: { key: "displayName", label: "Name", order: "asc" }, });
filters: new Map<string, string>() const [sortColumn, setSortColumn] = useState<Column<GetUser>>({
} key: "displayName",
label: t("Name"),
order: "asc",
});
const [filters, setFilters] = useState<Map<string, string>>(
new Map<string, string>(),
);
componentDidMount = async () => { const changePage = useCallback(
const { page, pageSize } = this.state.pagedData; async (page: number, pageSize: number) => {
const data = await userService.getUsers(
await this.changePage(page, pageSize); page,
} pageSize,
sortColumn.key,
changePage = async(page: number, pageSize : number) =>{ sortColumn.order === "asc",
const { sortColumn, filters } = this.state; filters,
);
const pagedData = await userService.getUsers(page, pageSize, sortColumn.key, sortColumn.order === "asc", filters); if (data) {
if(pagedData) { setLoaded(true);
this.setState({ loaded: true, pagedData }); setPagedData(data);
} else { } else {
this.setState({ loaded: false }); setLoaded(false);
}
} }
},
[filters, sortColumn.key, sortColumn.order],
);
onSort = async(sortColumn : Column<GetUser>) => { const onSort = async (newSortColumn: Column<GetUser>) => {
const {page, pageSize } = this.state.pagedData; const { page, pageSize } = pagedData;
const { filters } = this.state; const data = await userService.getUsers(
const pagedData = await userService.getUsers(page, pageSize, sortColumn.key, sortColumn.order === "asc", filters); page,
pageSize,
newSortColumn.key,
newSortColumn.order === "asc",
filters,
);
if (pagedData) { if (data) {
this.setState({ loaded: true, pagedData, sortColumn}); setLoaded(true);
setPagedData(data);
setSortColumn(newSortColumn);
} else { } else {
this.setState({ loaded: false }); setLoaded(false);
}
}
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);
if (pagedData) {
this.setState( { loaded: true, filters, pagedData });
} else {
this.setState({ loaded: false });
} }
}; };
onDelete = async ( item? : GetUser) => { 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,
);
if (data) {
setLoaded(true);
setFilters(newFilters);
setPagedData(data);
} else {
setLoaded(false);
}
};
const onDelete = async (item?: GetUser) => {
const response = await userService.deleteUser(item?.id, item?.guid); const response = await userService.deleteUser(item?.id, item?.guid);
if (response) { if (response) {
this.componentDidMount(); await changePage(pagedData.page, pagedData.pageSize);
}
} }
};
resentConfirmEmail = async (user: GetUser) => { const resentConfirmEmail = async (user: GetUser) => {
const response = await userService.resendConfirmEmail(user.id, user.guid); const response = await userService.resendConfirmEmail(user.id, user.guid);
if (response) { if (response) {
toast.info("Confirm e-mail resent"); toast.info(t("ConfirmEmailResent"));
}
} }
};
render(): JSX.Element { useEffect(() => {
const { loaded, pagedData, sortColumn } = this.state; changePage(pagedData.page, pagedData.pageSize);
}, [changePage, pagedData.page, pagedData.pageSize]);
return ( return (
<Loading loaded={loaded}> <Loading loaded={loaded}>
<Permission privilegeKey="AddUser"> <Permission privilegeKey="AddUser">
<div> <div>
<Button buttonType={ButtonType.primary} to="add">Add</Button> <Button buttonType={ButtonType.primary} to="add">
{t("Add")}
</Button>
</div> </div>
</Permission> </Permission>
<hr /> <hr />
<UsersTable data={pagedData} sortColumn={sortColumn} onChangePage={this.changePage} onSort={this.onSort} onSearch={this.onSearch} onDelete={this.onDelete} resendConfirmEmail={this.resentConfirmEmail}/> <UsersTable
data={pagedData}
sortColumn={sortColumn}
onChangePage={changePage}
onSort={onSort}
onSearch={onSearch}
onDelete={onDelete}
resendConfirmEmail={resentConfirmEmail}
/>
</Loading> </Loading>
); );
}
}; };
export default Users; export default Users;