Refactored all class components to be function components
This commit is contained in:
parent
adffa4f448
commit
dce95c8345
@ -1,19 +1,36 @@
|
||||
@import './_esuiteVariables.scss';
|
||||
@import "./_esuiteVariables.scss";
|
||||
|
||||
.two-column-grid-1-1 {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-gap: $gridGap;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-gap: $gridGap;
|
||||
}
|
||||
|
||||
.two-column-grid-1-3 {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 3fr;
|
||||
grid-gap: $gridGap;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 3fr;
|
||||
grid-gap: $gridGap;
|
||||
}
|
||||
|
||||
.mail-types {
|
||||
padding-left: 0rem;
|
||||
list-style: none;
|
||||
width: $mailtemplateNameListWidth;
|
||||
padding-left: 0rem;
|
||||
list-style: none;
|
||||
width: $mailtemplateNameListWidth;
|
||||
|
||||
li {
|
||||
cursor: pointer;
|
||||
padding: 0.5rem 0.75rem;
|
||||
border-radius: 4px;
|
||||
transition: background-color 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
&.selected {
|
||||
background-color: #0078d4;
|
||||
color: white;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3,17 +3,22 @@ import TabHeader from "./TabHeader";
|
||||
|
||||
interface HorizontalTabsProps {
|
||||
children: JSX.Element[];
|
||||
initialTab?: string;
|
||||
}
|
||||
|
||||
const HorizontalTabs: React.FC<HorizontalTabsProps> = ({ children }) => {
|
||||
const HorizontalTabs: React.FC<HorizontalTabsProps> = ({
|
||||
children,
|
||||
initialTab,
|
||||
}) => {
|
||||
const [activeTab, setActiveTab] = useState<string>("");
|
||||
|
||||
// Set initial tab on mount
|
||||
useEffect(() => {
|
||||
if (children.length > 0) {
|
||||
setActiveTab(children[0].props.label);
|
||||
const tabToSelect = initialTab || children[0].props.label;
|
||||
setActiveTab(tabToSelect);
|
||||
}
|
||||
}, [children]);
|
||||
}, [children, initialTab]);
|
||||
|
||||
const onClickTabItem = useCallback((tab: string) => {
|
||||
setActiveTab((prev) => (prev !== tab ? tab : prev));
|
||||
|
||||
644
src/components/common/formHelpers.ts
Normal file
644
src/components/common/formHelpers.ts
Normal file
@ -0,0 +1,644 @@
|
||||
export * from "./formHelpers.tsx";
|
||||
/*
|
||||
import React from "react";
|
||||
import Input, { InputType } from "./Input";
|
||||
import ToggleSlider from "./ToggleSlider";
|
||||
import Select from "./Select";
|
||||
import Option from "./option";
|
||||
import { GeneralIdRef } from "../../utils/GeneralIdRef";
|
||||
import SequencePicker from "../pickers/SequencePicker";
|
||||
import GlossaryPicker from "../pickers/GlossaryPicker";
|
||||
import CustomFieldsEditor, { CustomFieldEditorAdd, CustomFieldEditorDelete } from "./CustomFieldsEditor";
|
||||
import { CustomField, numberParams, textParams } from "../../modules/manager/customfields/services/customFieldsService";
|
||||
import FormTemplatePicker from "../pickers/FormTemplatePicker";
|
||||
import { CustomFieldValue } from "../../modules/manager/glossary/services/glossaryService";
|
||||
import TemplateEditor from "./TemplateEditor";
|
||||
import DomainPicker from "../pickers/DomainPicker";
|
||||
import UserPicker from "../pickers/UserPicker";
|
||||
import Button, { ButtonType } from "./Button";
|
||||
import Expando from "./expando";
|
||||
import ErrorBlock from "./ErrorBlock";
|
||||
import SsoProviderPicker from "../pickers/SsoProviderPicker";
|
||||
import { FormData, FormError } from "./useForm";
|
||||
|
||||
export const renderButton = (
|
||||
label: string,
|
||||
errors: FormError,
|
||||
name?: string,
|
||||
onClick?: (keyValue: any) => void,
|
||||
testid?: string,
|
||||
enabled: boolean = true,
|
||||
buttonType: ButtonType = ButtonType.primary,
|
||||
overrideErrorChecking: boolean = false
|
||||
) => {
|
||||
let disabled = !enabled || Object.keys(errors).filter((x) => !x.startsWith("_")).length > 0;
|
||||
|
||||
if (overrideErrorChecking) disabled = !enabled;
|
||||
|
||||
return (
|
||||
<Button testid={testid} disabled={disabled} name={name ?? label} buttonType={buttonType} onClick={onClick}>
|
||||
{label}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export const renderError = (name: string, errors: FormError) => {
|
||||
return <ErrorBlock error={errors[name]} />;
|
||||
};
|
||||
|
||||
export const renderInput = (
|
||||
name: string,
|
||||
label: string,
|
||||
data: FormData,
|
||||
errors: FormError,
|
||||
type: InputType = InputType.text,
|
||||
readOnly = false,
|
||||
defaultValue: string = "",
|
||||
placeHolder: string = "",
|
||||
maxLength: number = 0,
|
||||
visible: boolean = true,
|
||||
autoComplete: string | undefined = undefined,
|
||||
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void
|
||||
) => {
|
||||
let value = data[name];
|
||||
|
||||
let cleanValue: string | undefined;
|
||||
if (value === undefined) {
|
||||
cleanValue = defaultValue;
|
||||
} else if (typeof value === "string") {
|
||||
cleanValue = value as string;
|
||||
} else if (typeof value === "number") {
|
||||
cleanValue = String(value);
|
||||
} else if (typeof value === "boolean") {
|
||||
cleanValue = String(value);
|
||||
} else if (value as CustomFieldValue) {
|
||||
cleanValue = (value as CustomFieldValue).displayValue ?? (value as CustomFieldValue).value.toString();
|
||||
}
|
||||
|
||||
if (readOnly) {
|
||||
return (
|
||||
<Input
|
||||
includeLabel={true}
|
||||
type={type}
|
||||
name={name}
|
||||
label={label}
|
||||
value={cleanValue}
|
||||
error={errors[name]}
|
||||
maxLength={maxLength}
|
||||
readOnly
|
||||
placeHolder={placeHolder}
|
||||
hidden={!visible}
|
||||
autoComplete={autoComplete}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Input
|
||||
includeLabel={true}
|
||||
type={type}
|
||||
name={name}
|
||||
label={label}
|
||||
value={cleanValue}
|
||||
error={errors[name]}
|
||||
maxLength={maxLength}
|
||||
onChange={onChange}
|
||||
placeHolder={placeHolder}
|
||||
hidden={!visible}
|
||||
autoComplete={autoComplete}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export const renderInputWithChangeEvent = (
|
||||
name: string,
|
||||
label: string,
|
||||
data: FormData,
|
||||
errors: FormError,
|
||||
type: InputType = InputType.text,
|
||||
readOnly = false,
|
||||
handleChangeEvent?: (e: React.ChangeEvent<HTMLInputElement>) => void,
|
||||
defaultValue: string = "",
|
||||
placeHolder: string = "",
|
||||
maxLength: number = 0
|
||||
) => {
|
||||
let value = data[name];
|
||||
|
||||
let cleanValue: string | undefined;
|
||||
if (value === undefined) {
|
||||
cleanValue = defaultValue;
|
||||
} else if (typeof value === "string") {
|
||||
cleanValue = value as string;
|
||||
} else if (typeof value === "number") {
|
||||
cleanValue = String(value);
|
||||
} else if (typeof value === "boolean") {
|
||||
cleanValue = String(value);
|
||||
} else if (value as CustomFieldValue) {
|
||||
cleanValue = (value as CustomFieldValue).displayValue ?? (value as CustomFieldValue).value.toString();
|
||||
}
|
||||
|
||||
if (readOnly) {
|
||||
return (
|
||||
<Input
|
||||
includeLabel={true}
|
||||
type={type}
|
||||
name={name}
|
||||
label={label}
|
||||
value={cleanValue}
|
||||
error={errors[name]}
|
||||
maxLength={maxLength}
|
||||
readOnly
|
||||
placeHolder={placeHolder}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Input
|
||||
includeLabel={true}
|
||||
type={type}
|
||||
name={name}
|
||||
label={label}
|
||||
value={cleanValue}
|
||||
error={errors[name]}
|
||||
maxLength={maxLength}
|
||||
onChange={handleChangeEvent}
|
||||
placeHolder={placeHolder}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export const renderInputNumber = (
|
||||
name: string,
|
||||
label: string,
|
||||
data: FormData,
|
||||
errors: FormError,
|
||||
readOnly = false,
|
||||
defaultValue: string = "",
|
||||
min?: number,
|
||||
max?: number,
|
||||
step: number = 1,
|
||||
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void
|
||||
) => {
|
||||
let value = data[name];
|
||||
|
||||
let cleanValue: string | undefined;
|
||||
if (value === undefined) {
|
||||
cleanValue = defaultValue;
|
||||
} else if (typeof value === "string") {
|
||||
cleanValue = value as string;
|
||||
} else if (typeof value === "number") {
|
||||
cleanValue = String(value);
|
||||
} else if (typeof value === "boolean") {
|
||||
cleanValue = String(value);
|
||||
} else if (value as CustomFieldValue) {
|
||||
cleanValue = (value as CustomFieldValue).displayValue ?? (value as CustomFieldValue).value.toString();
|
||||
}
|
||||
|
||||
if (readOnly) {
|
||||
return <Input includeLabel={true} type={InputType.number} name={name} label={label} value={cleanValue} error={errors[name]} readOnly />;
|
||||
} else {
|
||||
return (
|
||||
<Input
|
||||
includeLabel={true}
|
||||
type={InputType.number}
|
||||
name={name}
|
||||
label={label}
|
||||
value={cleanValue}
|
||||
error={errors[name]}
|
||||
min={min}
|
||||
max={max}
|
||||
step={step}
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export const renderInputTextarea = (
|
||||
includeLabel: boolean,
|
||||
name: string,
|
||||
label: string,
|
||||
data: FormData,
|
||||
errors: FormError,
|
||||
readOnly = false,
|
||||
defaultValue: string = "",
|
||||
onTextAreaChange?: (e: React.ChangeEvent<HTMLTextAreaElement>) => void
|
||||
) => {
|
||||
let value = data[name];
|
||||
|
||||
let cleanValue: string | undefined;
|
||||
if (value === undefined) {
|
||||
cleanValue = defaultValue;
|
||||
} else if (typeof value === "string") {
|
||||
cleanValue = value as string;
|
||||
}
|
||||
|
||||
if (readOnly) {
|
||||
return (
|
||||
<Input
|
||||
includeLabel={includeLabel}
|
||||
type={InputType.textarea}
|
||||
key={name}
|
||||
name={name}
|
||||
label={label}
|
||||
value={cleanValue}
|
||||
error={errors[name]}
|
||||
readOnly
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Input
|
||||
includeLabel={includeLabel}
|
||||
type={InputType.textarea}
|
||||
key={name}
|
||||
name={name}
|
||||
label={label}
|
||||
value={cleanValue}
|
||||
error={errors[name]}
|
||||
onTextAreaChange={onTextAreaChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export const renderCustomFieldInput = (
|
||||
includeLabel: boolean,
|
||||
name: string,
|
||||
label: string,
|
||||
data: FormData,
|
||||
errors: FormError,
|
||||
type: InputType = InputType.text,
|
||||
readOnly = false,
|
||||
defaultValue: string = "",
|
||||
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void
|
||||
) => {
|
||||
let value = data[name];
|
||||
|
||||
let cleanValue: string | undefined;
|
||||
if (value === undefined) {
|
||||
cleanValue = defaultValue;
|
||||
} else if (typeof value === "string") {
|
||||
cleanValue = value as string;
|
||||
} else if (typeof value === "number") {
|
||||
cleanValue = String(value);
|
||||
} else if (typeof value === "boolean") {
|
||||
cleanValue = String(value);
|
||||
} else if (value as CustomFieldValue) {
|
||||
const customFieldValue = value as CustomFieldValue[];
|
||||
cleanValue = customFieldValue[0].displayValue ?? customFieldValue[0].value?.toString();
|
||||
}
|
||||
|
||||
if (readOnly) {
|
||||
return <Input includeLabel={includeLabel} type={type} name={name} label={label} value={cleanValue} error={errors[name]} readOnly />;
|
||||
} else {
|
||||
return (
|
||||
<Input
|
||||
includeLabel={includeLabel}
|
||||
type={type}
|
||||
name={name}
|
||||
label={label}
|
||||
value={cleanValue}
|
||||
error={errors[name]}
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export const renderCustomFieldNumber = (
|
||||
includeLabel: boolean,
|
||||
name: string,
|
||||
label: string,
|
||||
data: FormData,
|
||||
errors: FormError,
|
||||
readOnly = false,
|
||||
defaultValue: string = "",
|
||||
min?: number,
|
||||
max?: number,
|
||||
step: number = 1,
|
||||
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void
|
||||
) => {
|
||||
let values: CustomFieldValue[] = data[name] as CustomFieldValue[];
|
||||
|
||||
let value: CustomFieldValue | undefined = undefined;
|
||||
|
||||
if (values) {
|
||||
if (values.length > 0) {
|
||||
value = values[0];
|
||||
}
|
||||
}
|
||||
|
||||
let cleanValue: string | undefined;
|
||||
if (value === undefined) {
|
||||
cleanValue = defaultValue;
|
||||
} else if (typeof value === "string") {
|
||||
cleanValue = value as string;
|
||||
} else if (typeof value === "number") {
|
||||
cleanValue = String(value);
|
||||
} else if (value as CustomFieldValue) {
|
||||
cleanValue = (value as CustomFieldValue).displayValue ?? (value as CustomFieldValue).value?.toString();
|
||||
}
|
||||
|
||||
if (readOnly) {
|
||||
return <Input includeLabel={includeLabel} type={InputType.number} name={name} label={label} value={cleanValue} error={errors[name]} readOnly />;
|
||||
} else {
|
||||
return (
|
||||
<Input
|
||||
includeLabel={includeLabel}
|
||||
type={InputType.number}
|
||||
name={name}
|
||||
label={label}
|
||||
value={cleanValue}
|
||||
error={errors[name]}
|
||||
min={min}
|
||||
max={max}
|
||||
step={step}
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export const renderTemplateEditor = (
|
||||
className: string,
|
||||
name: string,
|
||||
label: string,
|
||||
data: FormData,
|
||||
allowCustomFields: boolean,
|
||||
onChange?: (name: string, value: string) => void
|
||||
) => {
|
||||
let value = data[name] as string;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<label htmlFor={name}>{label}</label>
|
||||
<TemplateEditor className={className} name={name} data={value} onChange={onChange} showFields={allowCustomFields} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const renderSelect = (
|
||||
name: string,
|
||||
label: string,
|
||||
data: FormData,
|
||||
errors: FormError,
|
||||
options: Option[],
|
||||
onChange?: (e: React.ChangeEvent<HTMLSelectElement>) => void
|
||||
) => {
|
||||
return <Select name={name} label={label} value={data[name]} options={options} error={errors[name]} onChange={onChange} />;
|
||||
};
|
||||
|
||||
export const renderToggle = (
|
||||
name: string,
|
||||
label: string,
|
||||
data: FormData,
|
||||
errors: FormError,
|
||||
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void
|
||||
) => {
|
||||
return <ToggleSlider name={name} label={label} defaultChecked={Boolean(data[name])} error={errors[name]} onChange={onChange} />;
|
||||
};
|
||||
|
||||
export const renderSequencePicker = (
|
||||
includeLabel: boolean,
|
||||
name: string,
|
||||
label: string,
|
||||
data: FormData,
|
||||
errors: FormError,
|
||||
onChange?: (name: string, value: GeneralIdRef) => void
|
||||
) => {
|
||||
return (
|
||||
<SequencePicker includeLabel={includeLabel} name={name} label={label} value={data[name]} error={errors[name]} onChange={onChange} />
|
||||
);
|
||||
};
|
||||
|
||||
export const renderGlossaryPicker = (
|
||||
includeLabel: boolean,
|
||||
name: string,
|
||||
label: string,
|
||||
data: FormData,
|
||||
errors: FormError,
|
||||
maxEntries?: number,
|
||||
refElementId?: GeneralIdRef,
|
||||
onChange?: (name: string, values: CustomFieldValue[]) => void
|
||||
) => {
|
||||
const glossaryValues: CustomFieldValue[] | undefined = data[name] as any as CustomFieldValue[];
|
||||
|
||||
return (
|
||||
<GlossaryPicker
|
||||
includeLabel={includeLabel}
|
||||
name={name}
|
||||
label={label}
|
||||
maxEntries={maxEntries}
|
||||
values={glossaryValues}
|
||||
error={errors[name]}
|
||||
rootItem={refElementId}
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const renderDomainPicker = (
|
||||
includeLabel: boolean,
|
||||
name: string,
|
||||
label: string,
|
||||
data: FormData,
|
||||
errors: FormError,
|
||||
minEntries: number,
|
||||
maxEntries?: number,
|
||||
onChange?: (name: string, values: CustomFieldValue[]) => void
|
||||
) => {
|
||||
const domainValues: CustomFieldValue[] | undefined = data[name] as any as CustomFieldValue[];
|
||||
|
||||
return (
|
||||
<DomainPicker
|
||||
includeLabel={includeLabel}
|
||||
name={name}
|
||||
label={label}
|
||||
minEntries={minEntries}
|
||||
maxEntries={maxEntries}
|
||||
values={domainValues}
|
||||
error={errors[name]}
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const renderTemplatePicker = (
|
||||
includeLabel: boolean,
|
||||
name: string,
|
||||
label: string,
|
||||
data: FormData,
|
||||
errors: FormError,
|
||||
onChange?: (name: string, value: GeneralIdRef) => void
|
||||
) => {
|
||||
const templateValue: GeneralIdRef = data[name] as any as GeneralIdRef;
|
||||
|
||||
return (
|
||||
<FormTemplatePicker
|
||||
includeLabel={includeLabel}
|
||||
name={name}
|
||||
label={label}
|
||||
value={templateValue}
|
||||
error={errors[name]}
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const renderUserPicker = (
|
||||
name: string,
|
||||
label: string,
|
||||
data: FormData,
|
||||
errors: FormError,
|
||||
onChange?: (name: string, value: GeneralIdRef) => void
|
||||
) => {
|
||||
const glossaryValue: GeneralIdRef | undefined = data[name] as any as GeneralIdRef;
|
||||
|
||||
return <UserPicker name={name} label={label} value={glossaryValue} error={errors[name]} onChange={onChange} />;
|
||||
};
|
||||
|
||||
export const renderSsoProviderPicker = (
|
||||
name: string,
|
||||
label: string,
|
||||
data: FormData,
|
||||
errors: FormError,
|
||||
onChange?: (name: string, value: GeneralIdRef) => void
|
||||
) => {
|
||||
const glossaryValue: GeneralIdRef | undefined = data[name] as any as GeneralIdRef;
|
||||
|
||||
return <SsoProviderPicker name={name} label={label} value={glossaryValue} error={errors[name]} onChange={onChange} />;
|
||||
};
|
||||
|
||||
export const renderCustomFieldsEditor = (
|
||||
name: string,
|
||||
label: string,
|
||||
data: FormData,
|
||||
errors: FormError,
|
||||
selected: CustomField[],
|
||||
onAdd: CustomFieldEditorAdd,
|
||||
onDelete: CustomFieldEditorDelete
|
||||
) => {
|
||||
return (
|
||||
<CustomFieldsEditor name={name} label={label} value={data[name] as []} error={errors[name]} exclude={selected} onAdd={onAdd} onDelete={onDelete} />
|
||||
);
|
||||
};
|
||||
|
||||
export const renderCustomField = (
|
||||
customField: CustomField,
|
||||
includeLabel: boolean,
|
||||
data: FormData,
|
||||
errors: FormError,
|
||||
onChange: (e: React.ChangeEvent<HTMLInputElement> | React.ChangeEvent<HTMLTextAreaElement>) => void,
|
||||
onPickerChange: (name: string, value: GeneralIdRef | CustomFieldValue[]) => void,
|
||||
getCustomFieldType: (field: CustomFieldValue, customFields: CustomField[]) => string
|
||||
) => {
|
||||
switch (customField.fieldType.toLowerCase()) {
|
||||
case "text":
|
||||
const textParameters: textParams = JSON.parse(customField.parameters!);
|
||||
if (textParameters.multiLine) {
|
||||
return renderInputTextarea(
|
||||
includeLabel,
|
||||
"customfield_" + customField.id,
|
||||
customField.name,
|
||||
data,
|
||||
errors,
|
||||
false,
|
||||
customField.defaultValue,
|
||||
onChange as (e: React.ChangeEvent<HTMLTextAreaElement>) => void
|
||||
);
|
||||
} else {
|
||||
return renderCustomFieldInput(
|
||||
includeLabel,
|
||||
"customfield_" + customField.id,
|
||||
customField.name,
|
||||
data,
|
||||
errors,
|
||||
InputType.text,
|
||||
false,
|
||||
customField.defaultValue,
|
||||
onChange as (e: React.ChangeEvent<HTMLInputElement>) => void
|
||||
);
|
||||
}
|
||||
case "sequence":
|
||||
return renderCustomFieldInput(includeLabel, "customfield_" + customField.id, customField.name, data, errors, InputType.text, true);
|
||||
case "formtemplate":
|
||||
return renderTemplatePicker(
|
||||
includeLabel,
|
||||
"customfield_" + customField.id,
|
||||
customField.name,
|
||||
data,
|
||||
errors,
|
||||
(name, value) => onPickerChange(name, value)
|
||||
);
|
||||
case "glossary":
|
||||
return renderGlossaryPicker(
|
||||
includeLabel,
|
||||
"customfield_" + customField.id,
|
||||
customField.name,
|
||||
data,
|
||||
errors,
|
||||
customField.maxEntries,
|
||||
customField.refElementId,
|
||||
(name, values) => onPickerChange(name, values)
|
||||
);
|
||||
case "number":
|
||||
const numberParameters: numberParams = JSON.parse(customField.parameters!);
|
||||
return renderCustomFieldNumber(
|
||||
includeLabel,
|
||||
"customfield_" + customField.id,
|
||||
customField.name,
|
||||
data,
|
||||
errors,
|
||||
false,
|
||||
customField.defaultValue,
|
||||
numberParameters.minValue ? Number(numberParameters.minValue) : undefined,
|
||||
numberParameters.maxValue ? Number(numberParameters.maxValue) : undefined,
|
||||
numberParameters.step ? Number(numberParameters.step) : undefined,
|
||||
onChange as (e: React.ChangeEvent<HTMLInputElement>) => void
|
||||
);
|
||||
case "domain":
|
||||
return renderDomainPicker(
|
||||
includeLabel,
|
||||
"customfield_" + customField.id,
|
||||
customField.name,
|
||||
data,
|
||||
errors,
|
||||
customField.minEntries,
|
||||
customField.maxEntries,
|
||||
(name, values) => onPickerChange(name, values)
|
||||
);
|
||||
default:
|
||||
return <>{customField.name + " " + customField.fieldType}</>;
|
||||
}
|
||||
};
|
||||
|
||||
export const renderCustomFields = (
|
||||
customFields: CustomField[] | undefined,
|
||||
data: FormData,
|
||||
errors: FormError,
|
||||
onChange: (e: React.ChangeEvent<HTMLInputElement> | React.ChangeEvent<HTMLTextAreaElement>) => void,
|
||||
onPickerChange: (name: string, value: GeneralIdRef | CustomFieldValue[]) => void,
|
||||
getCustomFieldType: (field: CustomFieldValue, customFields: CustomField[]) => string
|
||||
) => {
|
||||
if (customFields === undefined) return <></>;
|
||||
|
||||
let customFieldsBlock: JSX.Element[] = [];
|
||||
for (const customField of customFields) {
|
||||
customFieldsBlock.push(
|
||||
renderCustomField(customField, true, data, errors, onChange, onPickerChange, getCustomFieldType)
|
||||
);
|
||||
}
|
||||
|
||||
return <>{customFieldsBlock.map((x) => x)}</>;
|
||||
};
|
||||
|
||||
export const renderDropSection = (name: string, title: JSX.Element, content: JSX.Element, errors: FormError) => {
|
||||
return (
|
||||
<Expando name={name} title={title} error={errors[name]}>
|
||||
{content}
|
||||
</Expando>
|
||||
);
|
||||
};
|
||||
*/
|
||||
804
src/components/common/formHelpers.tsx
Normal file
804
src/components/common/formHelpers.tsx
Normal file
@ -0,0 +1,804 @@
|
||||
import React from "react";
|
||||
import Input, { InputType } from "./Input";
|
||||
import ToggleSlider from "./ToggleSlider";
|
||||
import Select from "./Select";
|
||||
import Option from "./option";
|
||||
import { GeneralIdRef } from "../../utils/GeneralIdRef";
|
||||
import SequencePicker from "../pickers/SequencePicker";
|
||||
import GlossaryPicker from "../pickers/GlossaryPicker";
|
||||
import CustomFieldsEditor, {
|
||||
CustomFieldEditorAdd,
|
||||
CustomFieldEditorDelete,
|
||||
} from "./CustomFieldsEditor";
|
||||
import {
|
||||
CustomField,
|
||||
numberParams,
|
||||
textParams,
|
||||
} from "../../modules/manager/customfields/services/customFieldsService";
|
||||
import FormTemplatePicker from "../pickers/FormTemplatePicker";
|
||||
import { CustomFieldValue } from "../../modules/manager/glossary/services/glossaryService";
|
||||
import TemplateEditor from "./TemplateEditor";
|
||||
import DomainPicker from "../pickers/DomainPicker";
|
||||
import UserPicker from "../pickers/UserPicker";
|
||||
import Button, { ButtonType } from "./Button";
|
||||
import Expando from "./expando";
|
||||
import ErrorBlock from "./ErrorBlock";
|
||||
import SsoProviderPicker from "../pickers/SsoProviderPicker";
|
||||
import { FormData, FormError } from "./useForm";
|
||||
|
||||
export const renderButton = (
|
||||
label: string,
|
||||
errors: FormError,
|
||||
name?: string,
|
||||
onClick?: (keyValue: any) => void,
|
||||
testid?: string,
|
||||
enabled: boolean = true,
|
||||
buttonType: ButtonType = ButtonType.primary,
|
||||
overrideErrorChecking: boolean = false,
|
||||
) => {
|
||||
let disabled =
|
||||
!enabled ||
|
||||
Object.keys(errors).filter((x) => !x.startsWith("_")).length > 0;
|
||||
|
||||
if (overrideErrorChecking) disabled = !enabled;
|
||||
|
||||
return (
|
||||
<Button
|
||||
testid={testid}
|
||||
disabled={disabled}
|
||||
name={name ?? label}
|
||||
buttonType={buttonType}
|
||||
onClick={onClick}
|
||||
>
|
||||
{label}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export const renderError = (name: string, errors: FormError) => {
|
||||
return <ErrorBlock error={errors[name]} />;
|
||||
};
|
||||
|
||||
export const renderInput = (
|
||||
name: string,
|
||||
label: string,
|
||||
data: FormData,
|
||||
errors: FormError,
|
||||
type: InputType = InputType.text,
|
||||
readOnly = false,
|
||||
defaultValue: string = "",
|
||||
placeHolder: string = "",
|
||||
maxLength: number = 0,
|
||||
visible: boolean = true,
|
||||
autoComplete: string | undefined = undefined,
|
||||
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void,
|
||||
) => {
|
||||
let value = data[name];
|
||||
|
||||
let cleanValue: string | undefined;
|
||||
if (value === undefined) {
|
||||
cleanValue = defaultValue;
|
||||
} else if (typeof value === "string") {
|
||||
cleanValue = value as string;
|
||||
} else if (typeof value === "number") {
|
||||
cleanValue = String(value);
|
||||
} else if (typeof value === "boolean") {
|
||||
cleanValue = String(value);
|
||||
} else if (value as CustomFieldValue) {
|
||||
cleanValue =
|
||||
(value as CustomFieldValue).displayValue ??
|
||||
(value as CustomFieldValue).value.toString();
|
||||
}
|
||||
|
||||
if (readOnly) {
|
||||
return (
|
||||
<Input
|
||||
includeLabel={true}
|
||||
type={type}
|
||||
name={name}
|
||||
label={label}
|
||||
value={cleanValue}
|
||||
error={errors[name]}
|
||||
maxLength={maxLength}
|
||||
readOnly
|
||||
placeHolder={placeHolder}
|
||||
hidden={!visible}
|
||||
autoComplete={autoComplete}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Input
|
||||
includeLabel={true}
|
||||
type={type}
|
||||
name={name}
|
||||
label={label}
|
||||
value={cleanValue}
|
||||
error={errors[name]}
|
||||
maxLength={maxLength}
|
||||
onChange={onChange}
|
||||
placeHolder={placeHolder}
|
||||
hidden={!visible}
|
||||
autoComplete={autoComplete}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export const renderInputWithChangeEvent = (
|
||||
name: string,
|
||||
label: string,
|
||||
data: FormData,
|
||||
errors: FormError,
|
||||
type: InputType = InputType.text,
|
||||
readOnly = false,
|
||||
handleChangeEvent?: (e: React.ChangeEvent<HTMLInputElement>) => void,
|
||||
defaultValue: string = "",
|
||||
placeHolder: string = "",
|
||||
maxLength: number = 0,
|
||||
) => {
|
||||
let value = data[name];
|
||||
|
||||
let cleanValue: string | undefined;
|
||||
if (value === undefined) {
|
||||
cleanValue = defaultValue;
|
||||
} else if (typeof value === "string") {
|
||||
cleanValue = value as string;
|
||||
} else if (typeof value === "number") {
|
||||
cleanValue = String(value);
|
||||
} else if (typeof value === "boolean") {
|
||||
cleanValue = String(value);
|
||||
} else if (value as CustomFieldValue) {
|
||||
cleanValue =
|
||||
(value as CustomFieldValue).displayValue ??
|
||||
(value as CustomFieldValue).value.toString();
|
||||
}
|
||||
|
||||
if (readOnly) {
|
||||
return (
|
||||
<Input
|
||||
includeLabel={true}
|
||||
type={type}
|
||||
name={name}
|
||||
label={label}
|
||||
value={cleanValue}
|
||||
error={errors[name]}
|
||||
maxLength={maxLength}
|
||||
readOnly
|
||||
placeHolder={placeHolder}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Input
|
||||
includeLabel={true}
|
||||
type={type}
|
||||
name={name}
|
||||
label={label}
|
||||
value={cleanValue}
|
||||
error={errors[name]}
|
||||
maxLength={maxLength}
|
||||
onChange={handleChangeEvent}
|
||||
placeHolder={placeHolder}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export const renderInputNumber = (
|
||||
name: string,
|
||||
label: string,
|
||||
data: FormData,
|
||||
errors: FormError,
|
||||
readOnly = false,
|
||||
defaultValue: string = "",
|
||||
min?: number,
|
||||
max?: number,
|
||||
step: number = 1,
|
||||
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void,
|
||||
) => {
|
||||
let value = data[name];
|
||||
|
||||
let cleanValue: string | undefined;
|
||||
if (value === undefined) {
|
||||
cleanValue = defaultValue;
|
||||
} else if (typeof value === "string") {
|
||||
cleanValue = value as string;
|
||||
} else if (typeof value === "number") {
|
||||
cleanValue = String(value);
|
||||
} else if (typeof value === "boolean") {
|
||||
cleanValue = String(value);
|
||||
} else if (value as CustomFieldValue) {
|
||||
cleanValue =
|
||||
(value as CustomFieldValue).displayValue ??
|
||||
(value as CustomFieldValue).value.toString();
|
||||
}
|
||||
|
||||
if (readOnly) {
|
||||
return (
|
||||
<Input
|
||||
includeLabel={true}
|
||||
type={InputType.number}
|
||||
name={name}
|
||||
label={label}
|
||||
value={cleanValue}
|
||||
error={errors[name]}
|
||||
readOnly
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Input
|
||||
includeLabel={true}
|
||||
type={InputType.number}
|
||||
name={name}
|
||||
label={label}
|
||||
value={cleanValue}
|
||||
error={errors[name]}
|
||||
min={min}
|
||||
max={max}
|
||||
step={step}
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export const renderInputTextarea = (
|
||||
includeLabel: boolean,
|
||||
name: string,
|
||||
label: string,
|
||||
data: FormData,
|
||||
errors: FormError,
|
||||
readOnly = false,
|
||||
defaultValue: string = "",
|
||||
onTextAreaChange?: (e: React.ChangeEvent<HTMLTextAreaElement>) => void,
|
||||
) => {
|
||||
let value = data[name];
|
||||
|
||||
let cleanValue: string | undefined;
|
||||
if (value === undefined) {
|
||||
cleanValue = defaultValue;
|
||||
} else if (typeof value === "string") {
|
||||
cleanValue = value as string;
|
||||
}
|
||||
|
||||
if (readOnly) {
|
||||
return (
|
||||
<Input
|
||||
includeLabel={includeLabel}
|
||||
type={InputType.textarea}
|
||||
key={name}
|
||||
name={name}
|
||||
label={label}
|
||||
value={cleanValue}
|
||||
error={errors[name]}
|
||||
readOnly
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Input
|
||||
includeLabel={includeLabel}
|
||||
type={InputType.textarea}
|
||||
key={name}
|
||||
name={name}
|
||||
label={label}
|
||||
value={cleanValue}
|
||||
error={errors[name]}
|
||||
onTextAreaChange={onTextAreaChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export const renderCustomFieldInput = (
|
||||
includeLabel: boolean,
|
||||
name: string,
|
||||
label: string,
|
||||
data: FormData,
|
||||
errors: FormError,
|
||||
type: InputType = InputType.text,
|
||||
readOnly = false,
|
||||
defaultValue: string = "",
|
||||
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void,
|
||||
) => {
|
||||
let value = data[name];
|
||||
|
||||
let cleanValue: string | undefined;
|
||||
if (value === undefined) {
|
||||
cleanValue = defaultValue;
|
||||
} else if (typeof value === "string") {
|
||||
cleanValue = value as string;
|
||||
} else if (typeof value === "number") {
|
||||
cleanValue = String(value);
|
||||
} else if (typeof value === "boolean") {
|
||||
cleanValue = String(value);
|
||||
} else if (value as CustomFieldValue) {
|
||||
const customFieldValue = value as CustomFieldValue[];
|
||||
cleanValue =
|
||||
customFieldValue[0].displayValue ?? customFieldValue[0].value?.toString();
|
||||
}
|
||||
|
||||
if (readOnly) {
|
||||
return (
|
||||
<Input
|
||||
includeLabel={includeLabel}
|
||||
type={type}
|
||||
name={name}
|
||||
label={label}
|
||||
value={cleanValue}
|
||||
error={errors[name]}
|
||||
readOnly
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Input
|
||||
includeLabel={includeLabel}
|
||||
type={type}
|
||||
name={name}
|
||||
label={label}
|
||||
value={cleanValue}
|
||||
error={errors[name]}
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export const renderCustomFieldNumber = (
|
||||
includeLabel: boolean,
|
||||
name: string,
|
||||
label: string,
|
||||
data: FormData,
|
||||
errors: FormError,
|
||||
readOnly = false,
|
||||
defaultValue: string = "",
|
||||
min?: number,
|
||||
max?: number,
|
||||
step: number = 1,
|
||||
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void,
|
||||
) => {
|
||||
let values: CustomFieldValue[] = data[name] as CustomFieldValue[];
|
||||
|
||||
let value: CustomFieldValue | undefined = undefined;
|
||||
|
||||
if (values) {
|
||||
if (values.length > 0) {
|
||||
value = values[0];
|
||||
}
|
||||
}
|
||||
|
||||
let cleanValue: string | undefined;
|
||||
if (value === undefined) {
|
||||
cleanValue = defaultValue;
|
||||
} else if (typeof value === "string") {
|
||||
cleanValue = value as string;
|
||||
} else if (typeof value === "number") {
|
||||
cleanValue = String(value);
|
||||
} else if (value as CustomFieldValue) {
|
||||
cleanValue =
|
||||
(value as CustomFieldValue).displayValue ??
|
||||
(value as CustomFieldValue).value?.toString();
|
||||
}
|
||||
|
||||
if (readOnly) {
|
||||
return (
|
||||
<Input
|
||||
includeLabel={includeLabel}
|
||||
type={InputType.number}
|
||||
name={name}
|
||||
label={label}
|
||||
value={cleanValue}
|
||||
error={errors[name]}
|
||||
readOnly
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Input
|
||||
includeLabel={includeLabel}
|
||||
type={InputType.number}
|
||||
name={name}
|
||||
label={label}
|
||||
value={cleanValue}
|
||||
error={errors[name]}
|
||||
min={min}
|
||||
max={max}
|
||||
step={step}
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export const renderTemplateEditor = (
|
||||
className: string,
|
||||
name: string,
|
||||
label: string,
|
||||
data: FormData,
|
||||
allowCustomFields: boolean,
|
||||
onChange?: (name: string, value: string) => void,
|
||||
) => {
|
||||
let value = data[name] as string;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<label htmlFor={name}>{label}</label>
|
||||
<TemplateEditor
|
||||
className={className}
|
||||
name={name}
|
||||
data={value}
|
||||
onChange={onChange ?? (() => {})}
|
||||
showFields={allowCustomFields}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const renderSelect = (
|
||||
name: string,
|
||||
label: string,
|
||||
data: FormData,
|
||||
errors: FormError,
|
||||
options: Option[],
|
||||
onChange?: (e: React.ChangeEvent<HTMLSelectElement>) => void,
|
||||
) => {
|
||||
return (
|
||||
<Select
|
||||
name={name}
|
||||
label={label}
|
||||
value={data[name]}
|
||||
options={options}
|
||||
error={errors[name]}
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const renderToggle = (
|
||||
name: string,
|
||||
label: string,
|
||||
data: FormData,
|
||||
errors: FormError,
|
||||
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void,
|
||||
) => {
|
||||
return (
|
||||
<ToggleSlider
|
||||
name={name}
|
||||
label={label}
|
||||
defaultChecked={Boolean(data[name])}
|
||||
error={errors[name]}
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const renderSequencePicker = (
|
||||
includeLabel: boolean,
|
||||
name: string,
|
||||
label: string,
|
||||
data: FormData,
|
||||
errors: FormError,
|
||||
onChange?: (name: string, value: GeneralIdRef) => void,
|
||||
) => {
|
||||
return (
|
||||
<SequencePicker
|
||||
includeLabel={includeLabel}
|
||||
name={name}
|
||||
label={label}
|
||||
value={data[name]}
|
||||
error={errors[name]}
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const renderGlossaryPicker = (
|
||||
includeLabel: boolean,
|
||||
name: string,
|
||||
label: string,
|
||||
data: FormData,
|
||||
errors: FormError,
|
||||
maxEntries?: number,
|
||||
refElementId?: GeneralIdRef,
|
||||
onChange?: (name: string, values: CustomFieldValue[]) => void,
|
||||
) => {
|
||||
const glossaryValues: CustomFieldValue[] | undefined = data[
|
||||
name
|
||||
] as any as CustomFieldValue[];
|
||||
|
||||
return (
|
||||
<GlossaryPicker
|
||||
includeLabel={includeLabel}
|
||||
name={name}
|
||||
label={label}
|
||||
maxEntries={maxEntries}
|
||||
values={glossaryValues}
|
||||
error={errors[name]}
|
||||
rootItem={refElementId}
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const renderDomainPicker = (
|
||||
includeLabel: boolean,
|
||||
name: string,
|
||||
label: string,
|
||||
data: FormData,
|
||||
errors: FormError,
|
||||
minEntries: number,
|
||||
maxEntries?: number,
|
||||
onChange?: (name: string, values: CustomFieldValue[]) => void,
|
||||
) => {
|
||||
const domainValues: CustomFieldValue[] | undefined = data[
|
||||
name
|
||||
] as any as CustomFieldValue[];
|
||||
|
||||
return (
|
||||
<DomainPicker
|
||||
includeLabel={includeLabel}
|
||||
name={name}
|
||||
label={label}
|
||||
minEntries={minEntries}
|
||||
maxEntries={maxEntries}
|
||||
values={domainValues}
|
||||
error={errors[name]}
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const renderTemplatePicker = (
|
||||
includeLabel: boolean,
|
||||
name: string,
|
||||
label: string,
|
||||
data: FormData,
|
||||
errors: FormError,
|
||||
onChange?: (name: string, value: GeneralIdRef) => void,
|
||||
) => {
|
||||
const templateValue: GeneralIdRef = data[name] as any as GeneralIdRef;
|
||||
|
||||
return (
|
||||
<FormTemplatePicker
|
||||
includeLabel={includeLabel}
|
||||
name={name}
|
||||
label={label}
|
||||
value={templateValue}
|
||||
error={errors[name]}
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const renderUserPicker = (
|
||||
name: string,
|
||||
label: string,
|
||||
data: FormData,
|
||||
errors: FormError,
|
||||
onChange?: (name: string, value: GeneralIdRef) => void,
|
||||
) => {
|
||||
const glossaryValue: GeneralIdRef | undefined = data[
|
||||
name
|
||||
] as any as GeneralIdRef;
|
||||
|
||||
return (
|
||||
<UserPicker
|
||||
name={name}
|
||||
label={label}
|
||||
value={glossaryValue}
|
||||
error={errors[name]}
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const renderSsoProviderPicker = (
|
||||
name: string,
|
||||
label: string,
|
||||
data: FormData,
|
||||
errors: FormError,
|
||||
onChange?: (name: string, value: GeneralIdRef) => void,
|
||||
) => {
|
||||
const glossaryValue: GeneralIdRef | undefined = data[
|
||||
name
|
||||
] as any as GeneralIdRef;
|
||||
|
||||
return (
|
||||
<SsoProviderPicker
|
||||
name={name}
|
||||
label={label}
|
||||
value={glossaryValue}
|
||||
error={errors[name]}
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const renderCustomFieldsEditor = (
|
||||
name: string,
|
||||
label: string,
|
||||
data: FormData,
|
||||
errors: FormError,
|
||||
selected: CustomField[],
|
||||
onAdd: CustomFieldEditorAdd,
|
||||
onDelete: CustomFieldEditorDelete,
|
||||
) => {
|
||||
return (
|
||||
<CustomFieldsEditor
|
||||
name={name}
|
||||
label={label}
|
||||
value={data[name] as []}
|
||||
error={errors[name]}
|
||||
exclude={selected}
|
||||
onAdd={onAdd}
|
||||
onDelete={onDelete}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const renderCustomField = (
|
||||
customField: CustomField,
|
||||
includeLabel: boolean,
|
||||
data: FormData,
|
||||
errors: FormError,
|
||||
onChange: (
|
||||
e:
|
||||
| React.ChangeEvent<HTMLInputElement>
|
||||
| React.ChangeEvent<HTMLTextAreaElement>,
|
||||
) => void,
|
||||
onPickerChange: (
|
||||
name: string,
|
||||
value: GeneralIdRef | CustomFieldValue[],
|
||||
) => void,
|
||||
getCustomFieldType: (
|
||||
field: CustomFieldValue,
|
||||
customFields: CustomField[],
|
||||
) => string,
|
||||
) => {
|
||||
switch (customField.fieldType.toLowerCase()) {
|
||||
case "text":
|
||||
const textParameters: textParams = JSON.parse(customField.parameters!);
|
||||
if (textParameters.multiLine) {
|
||||
return renderInputTextarea(
|
||||
includeLabel,
|
||||
"customfield_" + customField.id,
|
||||
customField.name,
|
||||
data,
|
||||
errors,
|
||||
false,
|
||||
customField.defaultValue,
|
||||
onChange as (e: React.ChangeEvent<HTMLTextAreaElement>) => void,
|
||||
);
|
||||
} else {
|
||||
return renderCustomFieldInput(
|
||||
includeLabel,
|
||||
"customfield_" + customField.id,
|
||||
customField.name,
|
||||
data,
|
||||
errors,
|
||||
InputType.text,
|
||||
false,
|
||||
customField.defaultValue,
|
||||
onChange as (e: React.ChangeEvent<HTMLInputElement>) => void,
|
||||
);
|
||||
}
|
||||
case "sequence":
|
||||
return renderCustomFieldInput(
|
||||
includeLabel,
|
||||
"customfield_" + customField.id,
|
||||
customField.name,
|
||||
data,
|
||||
errors,
|
||||
InputType.text,
|
||||
true,
|
||||
);
|
||||
case "formtemplate":
|
||||
return renderTemplatePicker(
|
||||
includeLabel,
|
||||
"customfield_" + customField.id,
|
||||
customField.name,
|
||||
data,
|
||||
errors,
|
||||
(name, value) => onPickerChange(name, value),
|
||||
);
|
||||
case "glossary":
|
||||
return renderGlossaryPicker(
|
||||
includeLabel,
|
||||
"customfield_" + customField.id,
|
||||
customField.name,
|
||||
data,
|
||||
errors,
|
||||
customField.maxEntries,
|
||||
customField.refElementId,
|
||||
(name, values) => onPickerChange(name, values),
|
||||
);
|
||||
case "number":
|
||||
const numberParameters: numberParams = JSON.parse(
|
||||
customField.parameters!,
|
||||
);
|
||||
return renderCustomFieldNumber(
|
||||
includeLabel,
|
||||
"customfield_" + customField.id,
|
||||
customField.name,
|
||||
data,
|
||||
errors,
|
||||
false,
|
||||
customField.defaultValue,
|
||||
numberParameters.minValue
|
||||
? Number(numberParameters.minValue)
|
||||
: undefined,
|
||||
numberParameters.maxValue
|
||||
? Number(numberParameters.maxValue)
|
||||
: undefined,
|
||||
numberParameters.step ? Number(numberParameters.step) : undefined,
|
||||
onChange as (e: React.ChangeEvent<HTMLInputElement>) => void,
|
||||
);
|
||||
case "domain":
|
||||
return renderDomainPicker(
|
||||
includeLabel,
|
||||
"customfield_" + customField.id,
|
||||
customField.name,
|
||||
data,
|
||||
errors,
|
||||
customField.minEntries,
|
||||
customField.maxEntries,
|
||||
(name, values) => onPickerChange(name, values),
|
||||
);
|
||||
default:
|
||||
return <>{customField.name + " " + customField.fieldType}</>;
|
||||
}
|
||||
};
|
||||
|
||||
export const renderCustomFields = (
|
||||
customFields: CustomField[] | undefined,
|
||||
data: FormData,
|
||||
errors: FormError,
|
||||
onChange: (
|
||||
e:
|
||||
| React.ChangeEvent<HTMLInputElement>
|
||||
| React.ChangeEvent<HTMLTextAreaElement>,
|
||||
) => void,
|
||||
onPickerChange: (
|
||||
name: string,
|
||||
value: GeneralIdRef | CustomFieldValue[],
|
||||
) => void,
|
||||
getCustomFieldType: (
|
||||
field: CustomFieldValue,
|
||||
customFields: CustomField[],
|
||||
) => string,
|
||||
) => {
|
||||
if (customFields === undefined) return <></>;
|
||||
|
||||
let customFieldsBlock: JSX.Element[] = [];
|
||||
for (const customField of customFields) {
|
||||
customFieldsBlock.push(
|
||||
renderCustomField(
|
||||
customField,
|
||||
true,
|
||||
data,
|
||||
errors,
|
||||
onChange,
|
||||
onPickerChange,
|
||||
getCustomFieldType,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return <>{customFieldsBlock.map((x) => x)}</>;
|
||||
};
|
||||
|
||||
export const renderDropSection = (
|
||||
name: string,
|
||||
title: JSX.Element,
|
||||
content: JSX.Element,
|
||||
errors: FormError,
|
||||
) => {
|
||||
return (
|
||||
<Expando name={name} title={title} error={errors[name]}>
|
||||
{content}
|
||||
</Expando>
|
||||
);
|
||||
};
|
||||
588
src/components/common/useForm.ts
Normal file
588
src/components/common/useForm.ts
Normal file
@ -0,0 +1,588 @@
|
||||
import { useState, useCallback, useRef } from "react";
|
||||
import Joi from "joi";
|
||||
import { GeneralIdRef } from "../../utils/GeneralIdRef";
|
||||
import {
|
||||
CustomField,
|
||||
numberParams,
|
||||
textParams,
|
||||
} from "../../modules/manager/customfields/services/customFieldsService";
|
||||
import {
|
||||
CustomFieldValue,
|
||||
CustomFieldValues,
|
||||
Glossary,
|
||||
} from "../../modules/manager/glossary/services/glossaryService";
|
||||
import { InputType } from "./Input";
|
||||
|
||||
export interface FormError {
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
export interface FormData {
|
||||
[key: string]:
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| CustomFieldValue[]
|
||||
| GeneralIdRef
|
||||
| CustomField[]
|
||||
| bigint
|
||||
| Glossary
|
||||
| null
|
||||
| undefined;
|
||||
}
|
||||
|
||||
export interface businessValidationError {
|
||||
path: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface businessValidationResult {
|
||||
details: businessValidationError[];
|
||||
}
|
||||
|
||||
export interface joiSchema {
|
||||
[key: string]: object;
|
||||
}
|
||||
|
||||
export interface FormState {
|
||||
loaded: boolean;
|
||||
data: FormData;
|
||||
customFields?: CustomField[];
|
||||
errors: FormError;
|
||||
redirect?: string;
|
||||
}
|
||||
|
||||
interface UseFormReturn {
|
||||
state: FormState;
|
||||
schema: joiSchema;
|
||||
validate: (data: FormData) => FormError;
|
||||
GetCustomFieldValues: (customField: CustomField) => CustomFieldValue[];
|
||||
CustomFieldValues: () => CustomFieldValues[];
|
||||
setCustomFieldValues: (
|
||||
data: object,
|
||||
customFieldValues: CustomFieldValues[],
|
||||
customFields: CustomField[],
|
||||
) => void;
|
||||
getCustomFieldType: (
|
||||
field: CustomFieldValues,
|
||||
childCustomFieldDefinition: CustomField[],
|
||||
) => string;
|
||||
handleSubmit: (
|
||||
e: React.FormEvent<HTMLFormElement>,
|
||||
doSubmit: (buttonName: string) => Promise<void>,
|
||||
) => void;
|
||||
handleGeneralError: (ex: any) => void;
|
||||
handleChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
||||
handleTextAreaChange: (e: React.ChangeEvent<HTMLTextAreaElement>) => void;
|
||||
handleCustomFieldChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
||||
handleTemplateEditorChange: (name: string, value: string) => void;
|
||||
handleSelectChange: (e: React.ChangeEvent<HTMLSelectElement>) => void;
|
||||
handlePickerChange: (name: string, value: GeneralIdRef) => void;
|
||||
handleDomainPickerChange: (name: string, values: CustomFieldValue[]) => void;
|
||||
handleGlossaryPickerChange: (
|
||||
name: string,
|
||||
values: CustomFieldValue[],
|
||||
) => void;
|
||||
handleTemplateFormPickerChange: (name: string, value: GeneralIdRef) => void;
|
||||
handleUserPickerChange: (name: string, value: GeneralIdRef) => void;
|
||||
handleSsoProviderPickerChange: (name: string, value: GeneralIdRef) => void;
|
||||
handleToggleChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
||||
setState: (updates: Partial<FormState>) => void;
|
||||
}
|
||||
|
||||
export const useForm = (initialState: FormState): UseFormReturn => {
|
||||
const [state, setStateInternal] = useState<FormState>(initialState);
|
||||
const schemaRef = useRef<joiSchema>({});
|
||||
|
||||
const setState = useCallback((updates: Partial<FormState>) => {
|
||||
setStateInternal((prev) => ({ ...prev, ...updates }));
|
||||
}, []);
|
||||
|
||||
const validate = useCallback(
|
||||
(data: FormData): FormError => {
|
||||
let options: Joi.ValidationOptions = {
|
||||
context: {},
|
||||
abortEarly: false,
|
||||
};
|
||||
|
||||
const customFields = state.customFields;
|
||||
|
||||
let validationSchema = schemaRef.current;
|
||||
if (customFields !== undefined) {
|
||||
for (const customfield of customFields) {
|
||||
const name = "customfield_" + customfield.id;
|
||||
switch (customfield.fieldType) {
|
||||
case "Number":
|
||||
if (customfield.parameters !== undefined) {
|
||||
const parameters: numberParams = JSON.parse(
|
||||
customfield.parameters!,
|
||||
);
|
||||
|
||||
options.context![name + "_minEntries"] = customfield.minEntries;
|
||||
if (parameters.minValue)
|
||||
options.context![name + "_minValue"] = Number(
|
||||
parameters.minValue,
|
||||
);
|
||||
if (parameters.maxValue)
|
||||
options.context![name + "_maxValue"] = Number(
|
||||
parameters.maxValue,
|
||||
);
|
||||
|
||||
let minCheck = options.context![name + "_minValue"]
|
||||
? Joi.number()
|
||||
.empty("")
|
||||
.min(options.context![name + "_minValue"])
|
||||
: Joi.number().empty("");
|
||||
let maxCheck = options.context![name + "_maxValue"]
|
||||
? Joi.number()
|
||||
.empty("")
|
||||
.max(options.context![name + "_maxValue"])
|
||||
: Joi.number().empty("");
|
||||
|
||||
validationSchema[name] = Joi.array()
|
||||
.min(1)
|
||||
.items(
|
||||
Joi.object({
|
||||
displayValue: Joi.string().allow(""),
|
||||
value: Joi.when("$" + name + "_minEntries", {
|
||||
is: 0,
|
||||
then: Joi.number().empty(""),
|
||||
otherwise: Joi.number().required(),
|
||||
})
|
||||
.when("$" + name + "_minValue", {
|
||||
is: Joi.number(),
|
||||
then: minCheck,
|
||||
})
|
||||
.when("$" + name + "_maxValue", {
|
||||
is: Joi.number(),
|
||||
then: maxCheck,
|
||||
})
|
||||
.label(customfield.name),
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
validationSchema[name] = Joi.optional().label(customfield.name);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
validationSchema[name] = Joi.optional().label(customfield.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const joiSchema = Joi.object(validationSchema);
|
||||
const { error } = joiSchema.validate(data, options);
|
||||
let errors: FormError = {};
|
||||
if (error) {
|
||||
if (error.details === undefined) {
|
||||
errors[error.name] = error.message;
|
||||
} else {
|
||||
for (let item of error.details) {
|
||||
errors[item.path[0]] = item.message;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
},
|
||||
[state.customFields],
|
||||
);
|
||||
|
||||
const GetCustomFieldValues = useCallback(
|
||||
(customField: CustomField): CustomFieldValue[] => {
|
||||
const name = "customfield_" + customField.id;
|
||||
const codedValue = state.data[name];
|
||||
|
||||
let values: CustomFieldValue[] = [];
|
||||
|
||||
switch (customField.fieldType) {
|
||||
case "FormTemplate":
|
||||
if (codedValue !== undefined) {
|
||||
const formTemplateValue = {
|
||||
value: JSON.stringify(codedValue as GeneralIdRef),
|
||||
};
|
||||
values.push(formTemplateValue);
|
||||
}
|
||||
break;
|
||||
case "Sequence":
|
||||
if (codedValue !== undefined) {
|
||||
values = codedValue as CustomFieldValue[];
|
||||
}
|
||||
break;
|
||||
case "Glossary":
|
||||
if (codedValue !== undefined) {
|
||||
values = codedValue as CustomFieldValue[];
|
||||
}
|
||||
break;
|
||||
case "Domain":
|
||||
if (codedValue !== undefined) {
|
||||
values = codedValue as CustomFieldValue[];
|
||||
}
|
||||
break;
|
||||
case "Text":
|
||||
const textParameters: textParams = JSON.parse(
|
||||
customField.parameters!,
|
||||
);
|
||||
if (textParameters.multiLine) {
|
||||
const textValue = {
|
||||
value:
|
||||
codedValue === undefined
|
||||
? customField.defaultValue
|
||||
: codedValue,
|
||||
displayValue:
|
||||
codedValue === undefined
|
||||
? customField.defaultValue
|
||||
: codedValue,
|
||||
} as CustomFieldValue;
|
||||
values.push(textValue);
|
||||
} else {
|
||||
if (codedValue === undefined) {
|
||||
const numberValue = {
|
||||
value: customField.defaultValue,
|
||||
displayValue: customField.defaultValue,
|
||||
} as CustomFieldValue;
|
||||
values.push(numberValue);
|
||||
} else {
|
||||
values = codedValue as CustomFieldValue[];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "Number":
|
||||
if (codedValue === undefined) {
|
||||
const numberValue = {
|
||||
value: customField.defaultValue,
|
||||
displayValue: customField.defaultValue,
|
||||
} as CustomFieldValue;
|
||||
values.push(numberValue);
|
||||
} else {
|
||||
values = codedValue as CustomFieldValue[];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
const textValue = {
|
||||
value:
|
||||
codedValue === undefined
|
||||
? customField.defaultValue
|
||||
: String((codedValue as CustomFieldValue[])[0].displayValue),
|
||||
};
|
||||
values.push(textValue);
|
||||
break;
|
||||
}
|
||||
|
||||
return values;
|
||||
},
|
||||
[state.data],
|
||||
);
|
||||
|
||||
const CustomFieldValues = useCallback((): CustomFieldValues[] => {
|
||||
const customFields = state.customFields;
|
||||
let result: CustomFieldValues[] = [];
|
||||
|
||||
if (customFields === undefined) {
|
||||
return result;
|
||||
}
|
||||
|
||||
for (const customfield of customFields) {
|
||||
const values = GetCustomFieldValues(customfield);
|
||||
|
||||
const id: GeneralIdRef = {
|
||||
id: customfield.id,
|
||||
guid: customfield.guid,
|
||||
};
|
||||
|
||||
const newItem: CustomFieldValues = {
|
||||
id,
|
||||
values,
|
||||
};
|
||||
|
||||
result.push(newItem);
|
||||
}
|
||||
|
||||
return result;
|
||||
}, [state.customFields, GetCustomFieldValues]);
|
||||
|
||||
const getCustomFieldType = useCallback(
|
||||
(
|
||||
field: CustomFieldValues,
|
||||
childCustomFieldDefinition: CustomField[],
|
||||
): string => {
|
||||
const fieldDefinition = childCustomFieldDefinition.filter(
|
||||
(x) => x.id === field.id.id,
|
||||
)[0];
|
||||
|
||||
if (fieldDefinition.parameters) {
|
||||
const textParameters: textParams = JSON.parse(
|
||||
fieldDefinition.parameters!,
|
||||
);
|
||||
if (textParameters.multiLine) return "multilinetext";
|
||||
}
|
||||
|
||||
return fieldDefinition.fieldType;
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const setCustomFieldValues = useCallback(
|
||||
(
|
||||
data: object,
|
||||
customFieldValues: CustomFieldValues[],
|
||||
customFields: CustomField[],
|
||||
) => {
|
||||
if (customFieldValues !== undefined) {
|
||||
for (const x of customFieldValues) {
|
||||
const customfieldName = "customfield_" + x.id.id;
|
||||
|
||||
switch (getCustomFieldType(x, customFields).toLowerCase()) {
|
||||
case "glossary":
|
||||
case "domain":
|
||||
case "number":
|
||||
case "text":
|
||||
(data as any)[customfieldName] = x.values.map((x) => {
|
||||
return {
|
||||
displayValue: x.displayValue,
|
||||
value: x.value,
|
||||
};
|
||||
});
|
||||
break;
|
||||
case "formtemplate":
|
||||
case "multilinetext":
|
||||
(data as any)[customfieldName] = x.values[0].value;
|
||||
break;
|
||||
default:
|
||||
(data as any)[customfieldName] = x.values;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
[getCustomFieldType],
|
||||
);
|
||||
|
||||
const handleSubmit = useCallback(
|
||||
(
|
||||
e: React.FormEvent<HTMLFormElement>,
|
||||
doSubmit: (buttonName: string) => Promise<void>,
|
||||
) => {
|
||||
e.preventDefault();
|
||||
|
||||
const submitEvent = e.nativeEvent as SubmitEvent;
|
||||
const submitter = submitEvent.submitter as any;
|
||||
|
||||
const errors = validate(state.data);
|
||||
setState({ errors });
|
||||
|
||||
const disabled = Object.keys(errors).length > 0;
|
||||
|
||||
if (disabled) return;
|
||||
|
||||
void doSubmit(submitter.name);
|
||||
},
|
||||
[state.data, validate, setState],
|
||||
);
|
||||
|
||||
const handleGeneralError = useCallback(
|
||||
(ex: any) => {
|
||||
const errors: FormError = { ...state.errors };
|
||||
|
||||
if (ex.response) {
|
||||
errors._general = ex.response.data.detail;
|
||||
} else {
|
||||
errors._general = ex.message;
|
||||
}
|
||||
|
||||
setState({ errors });
|
||||
},
|
||||
[state.errors, setState],
|
||||
);
|
||||
|
||||
const handleChange = useCallback(
|
||||
(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const input = e.currentTarget;
|
||||
const data: FormData = { ...state.data };
|
||||
|
||||
if ((input as any).type === InputType.checkbox) {
|
||||
data[input.name] = !data[input.name];
|
||||
} else data[input.name] = input.value;
|
||||
|
||||
const errors = validate(data);
|
||||
setState({ data, errors });
|
||||
},
|
||||
[state.data, validate, setState],
|
||||
);
|
||||
|
||||
const handleTextAreaChange = useCallback(
|
||||
(e: React.ChangeEvent<HTMLTextAreaElement>) => {
|
||||
const input = e.currentTarget;
|
||||
const data: FormData = { ...state.data };
|
||||
|
||||
data[input.name] = input.value;
|
||||
|
||||
const errors = validate(data);
|
||||
setState({ data, errors });
|
||||
},
|
||||
[state.data, validate, setState],
|
||||
);
|
||||
|
||||
const handleCustomFieldChange = useCallback(
|
||||
(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const input = e.currentTarget;
|
||||
const data: FormData = { ...state.data };
|
||||
|
||||
switch ((input as any).type) {
|
||||
case InputType.checkbox:
|
||||
data[input.name] = !data[input.name];
|
||||
break;
|
||||
default:
|
||||
const customFieldValue: CustomFieldValue = {
|
||||
displayValue: input.value,
|
||||
value: input.value,
|
||||
};
|
||||
|
||||
data[input.name] = [customFieldValue];
|
||||
break;
|
||||
}
|
||||
|
||||
const errors = validate(data);
|
||||
setState({ data, errors });
|
||||
},
|
||||
[state.data, validate, setState],
|
||||
);
|
||||
|
||||
const handleTemplateEditorChange = useCallback(
|
||||
(name: string, value: string) => {
|
||||
const data: FormData = { ...state.data };
|
||||
|
||||
data[name] = value;
|
||||
|
||||
const errors = validate(data);
|
||||
setState({ data, errors });
|
||||
},
|
||||
[state.data, validate, setState],
|
||||
);
|
||||
|
||||
const handleSelectChange = useCallback(
|
||||
(e: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
const input = e.currentTarget;
|
||||
|
||||
const data: FormData = { ...state.data };
|
||||
data[input.name] = input.value;
|
||||
const errors = validate(data);
|
||||
|
||||
setState({ data, errors });
|
||||
},
|
||||
[state.data, validate, setState],
|
||||
);
|
||||
|
||||
const handlePickerChange = useCallback(
|
||||
(name: string, value: GeneralIdRef) => {
|
||||
const data: FormData = { ...state.data };
|
||||
data[name] = value;
|
||||
const errors = validate(data);
|
||||
|
||||
setState({ data, errors });
|
||||
},
|
||||
[state.data, validate, setState],
|
||||
);
|
||||
|
||||
const handleDomainPickerChange = useCallback(
|
||||
(name: string, values: CustomFieldValue[]) => {
|
||||
const data: FormData = { ...state.data };
|
||||
data[name] = values;
|
||||
const errors = validate(data);
|
||||
|
||||
setState({ data, errors });
|
||||
},
|
||||
[state.data, validate, setState],
|
||||
);
|
||||
|
||||
const handleGlossaryPickerChange = useCallback(
|
||||
(name: string, values: CustomFieldValue[]) => {
|
||||
const data: FormData = { ...state.data };
|
||||
data[name] = values;
|
||||
const errors = validate(data);
|
||||
|
||||
setState({ data, errors });
|
||||
},
|
||||
[state.data, validate, setState],
|
||||
);
|
||||
|
||||
const handleTemplateFormPickerChange = useCallback(
|
||||
(name: string, value: GeneralIdRef) => {
|
||||
const data: FormData = { ...state.data };
|
||||
data[name] = value;
|
||||
const errors = validate(data);
|
||||
|
||||
setState({ data, errors });
|
||||
},
|
||||
[state.data, validate, setState],
|
||||
);
|
||||
|
||||
const handleUserPickerChange = useCallback(
|
||||
(name: string, value: GeneralIdRef) => {
|
||||
const data: FormData = { ...state.data };
|
||||
data[name] = value;
|
||||
const errors = validate(data);
|
||||
|
||||
setState({ data, errors });
|
||||
},
|
||||
[state.data, validate, setState],
|
||||
);
|
||||
|
||||
const handleSsoProviderPickerChange = useCallback(
|
||||
(name: string, value: GeneralIdRef) => {
|
||||
const data: FormData = { ...state.data };
|
||||
data[name] = value;
|
||||
const errors = validate(data);
|
||||
|
||||
setState({ data, errors });
|
||||
},
|
||||
[state.data, validate, setState],
|
||||
);
|
||||
|
||||
const handleToggleChange = useCallback(
|
||||
(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const input = e.currentTarget;
|
||||
const { name, checked } = input;
|
||||
|
||||
const data: FormData = { ...state.data };
|
||||
data[name] = checked;
|
||||
const errors = validate(data);
|
||||
|
||||
setState({ data, errors });
|
||||
},
|
||||
[state.data, validate, setState],
|
||||
);
|
||||
|
||||
const api: any = {
|
||||
state,
|
||||
schema: schemaRef.current,
|
||||
validate,
|
||||
GetCustomFieldValues,
|
||||
CustomFieldValues,
|
||||
setCustomFieldValues,
|
||||
getCustomFieldType,
|
||||
handleSubmit,
|
||||
handleGeneralError,
|
||||
handleChange,
|
||||
handleTextAreaChange,
|
||||
handleCustomFieldChange,
|
||||
handleTemplateEditorChange,
|
||||
handleSelectChange,
|
||||
handlePickerChange,
|
||||
handleDomainPickerChange,
|
||||
handleGlossaryPickerChange,
|
||||
handleTemplateFormPickerChange,
|
||||
handleUserPickerChange,
|
||||
handleSsoProviderPickerChange,
|
||||
handleToggleChange,
|
||||
setState,
|
||||
};
|
||||
Object.defineProperty(api, "schema", {
|
||||
get: () => schemaRef.current,
|
||||
set: (value: joiSchema) => {
|
||||
schemaRef.current = value || {};
|
||||
},
|
||||
});
|
||||
|
||||
return api as UseFormReturn;
|
||||
};
|
||||
@ -1,11 +1,19 @@
|
||||
import Joi from "joi";
|
||||
import React from "react";
|
||||
import { Navigate } from "react-router-dom";
|
||||
import React, { useEffect } from "react";
|
||||
import { Navigate, useParams } from "react-router-dom";
|
||||
import { toast } from "react-toastify";
|
||||
import Form from "../../../components/common/Form";
|
||||
import { InputType } from "../../../components/common/Input";
|
||||
import { FormState } from "../../../components/common/Form";
|
||||
import withRouter from "../../../utils/withRouter";
|
||||
import { useForm } from "../../../components/common/useForm";
|
||||
import {
|
||||
renderInput,
|
||||
renderButton,
|
||||
renderError,
|
||||
renderSelect,
|
||||
renderInputNumber,
|
||||
renderInputTextarea,
|
||||
renderGlossaryPicker,
|
||||
renderSequencePicker,
|
||||
} from "../../../components/common/formHelpers";
|
||||
import { MakeGeneralIdRef } from "../../../utils/GeneralIdRef";
|
||||
import customFieldsService, {
|
||||
numberParams,
|
||||
@ -19,25 +27,31 @@ import {
|
||||
} from "../glossary/services/glossaryService";
|
||||
import Loading from "../../../components/common/Loading";
|
||||
|
||||
interface CustomFieldDetailsState extends FormState {
|
||||
data: {
|
||||
name: string;
|
||||
fieldType: string;
|
||||
multiLine: boolean;
|
||||
defaultValue: string;
|
||||
minEntries: number;
|
||||
maxEntries: string | number | undefined;
|
||||
refElementId: CustomFieldValue[] | GeneralIdRef | undefined;
|
||||
minValue: number | undefined;
|
||||
maxValue: number | undefined;
|
||||
step: number | undefined;
|
||||
required: boolean;
|
||||
};
|
||||
redirect: string;
|
||||
interface CustomFieldDetailsProps {
|
||||
editMode?: boolean;
|
||||
}
|
||||
|
||||
class CustomFieldDetails extends Form<any, any, CustomFieldDetailsState> {
|
||||
state: CustomFieldDetailsState = {
|
||||
const CustomFieldDetails: React.FC<CustomFieldDetailsProps> = ({
|
||||
editMode = false,
|
||||
}) => {
|
||||
const { customFieldId } = useParams<{ customFieldId: string }>();
|
||||
|
||||
const labelName = "Name";
|
||||
const labelFieldType = "Field Type";
|
||||
const labelMultiLine = "Multi-line";
|
||||
const labelDefaultValue = "Default Value";
|
||||
const labelMinValue = "Minimum Value";
|
||||
const labelMaxValue = "Maximum Value";
|
||||
const labelStep = "Step";
|
||||
const labelRequired = "Required";
|
||||
const labelMinEntries = "Min Entries";
|
||||
const labelMaxEntries = "Max Entries (empty=unlimited)";
|
||||
let labelRefElementId = "Sequence/Form/Glossary";
|
||||
|
||||
const labelApply = "Save";
|
||||
const labelSave = "Save and close";
|
||||
|
||||
const form = useForm({
|
||||
loaded: false,
|
||||
data: {
|
||||
name: "",
|
||||
@ -54,29 +68,14 @@ class CustomFieldDetails extends Form<any, any, CustomFieldDetailsState> {
|
||||
},
|
||||
errors: {},
|
||||
redirect: "",
|
||||
};
|
||||
});
|
||||
|
||||
labelName = "Name";
|
||||
labelFieldType = "Field Type";
|
||||
labelMultiLine = "Multi-line";
|
||||
labelDefaultValue = "Default Value";
|
||||
labelMinValue = "Minimum Value";
|
||||
labelMaxValue = "Maximum Value";
|
||||
labelStep = "Step";
|
||||
labelRequired = "Required";
|
||||
labelMinEntries = "Min Entries";
|
||||
labelMaxEntries = "Max Entries (empty=unlimited)";
|
||||
labelRefElementId = "Sequence/Form/Glossary";
|
||||
|
||||
labelApply = "Save";
|
||||
labelSave = "Save and close";
|
||||
|
||||
schema = {
|
||||
name: Joi.string().required().max(450).label(this.labelName),
|
||||
fieldType: Joi.string().required().label(this.labelFieldType),
|
||||
multiLine: Joi.boolean().label(this.labelMultiLine),
|
||||
minEntries: Joi.number().min(0).label(this.labelMinEntries),
|
||||
maxEntries: Joi.number().empty("").label(this.labelMaxEntries),
|
||||
form.schema = {
|
||||
name: Joi.string().required().max(450).label(labelName),
|
||||
fieldType: Joi.string().required().label(labelFieldType),
|
||||
multiLine: Joi.boolean().label(labelMultiLine),
|
||||
minEntries: Joi.number().min(0).label(labelMinEntries),
|
||||
maxEntries: Joi.number().empty("").label(labelMaxEntries),
|
||||
refElementId: Joi.when("fieldType", {
|
||||
is: Joi.string().valid("Sequence"),
|
||||
then: Joi.object({
|
||||
@ -98,12 +97,12 @@ class CustomFieldDetails extends Form<any, any, CustomFieldDetailsState> {
|
||||
)
|
||||
.required(),
|
||||
}),
|
||||
minValue: Joi.number().allow("").label(this.labelMinValue),
|
||||
maxValue: Joi.number().allow("").label(this.labelMaxValue),
|
||||
step: Joi.number().optional().allow("").min(0).label(this.labelStep),
|
||||
required: Joi.boolean().label(this.labelRequired),
|
||||
minValue: Joi.number().allow("").label(labelMinValue),
|
||||
maxValue: Joi.number().allow("").label(labelMaxValue),
|
||||
step: Joi.number().optional().allow("").min(0).label(labelStep),
|
||||
required: Joi.boolean().label(labelRequired),
|
||||
|
||||
//defaultValue: Joi.string().allow("").label(this.labelDefaultValue)
|
||||
//defaultValue: Joi.string().allow("").label(labelDefaultValue)
|
||||
|
||||
defaultValue: Joi.when("fieldType", {
|
||||
is: Joi.string().valid("Number"),
|
||||
@ -114,7 +113,7 @@ class CustomFieldDetails extends Form<any, any, CustomFieldDetailsState> {
|
||||
.min(Joi.ref("minValue"))
|
||||
.message(
|
||||
'"Default Value" must be greater than or equal to "' +
|
||||
this.labelMinValue +
|
||||
labelMinValue +
|
||||
'"',
|
||||
),
|
||||
})
|
||||
@ -125,26 +124,99 @@ class CustomFieldDetails extends Form<any, any, CustomFieldDetailsState> {
|
||||
.max(Joi.ref("maxValue"))
|
||||
.message(
|
||||
'"Default Value" must be less than or equal to "' +
|
||||
this.labelMaxValue +
|
||||
labelMaxValue +
|
||||
'"',
|
||||
),
|
||||
})
|
||||
.allow(""),
|
||||
otherwise: Joi.string().allow(""),
|
||||
}).label(this.labelDefaultValue),
|
||||
}).label(labelDefaultValue),
|
||||
};
|
||||
|
||||
doSubmit = async (buttonName: string) => {
|
||||
const isEditMode = () => {
|
||||
return editMode;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const loadData = async () => {
|
||||
if (customFieldId !== undefined) {
|
||||
try {
|
||||
const loadedData = await customFieldsService.getField(
|
||||
BigInt(customFieldId),
|
||||
);
|
||||
|
||||
if (loadedData) {
|
||||
const newData = { ...form.state.data };
|
||||
newData.name = loadedData.name;
|
||||
newData.fieldType = loadedData.fieldType;
|
||||
newData.defaultValue = loadedData.defaultValue;
|
||||
newData.minEntries = loadedData.minEntries;
|
||||
newData.maxEntries = loadedData.maxEntries;
|
||||
switch (newData.fieldType) {
|
||||
case "Glossary":
|
||||
let convertedRefElementId: CustomFieldValue = {
|
||||
value: loadedData.refElementId,
|
||||
};
|
||||
|
||||
newData.refElementId = [convertedRefElementId];
|
||||
newData.required = loadedData.minEntries > 0;
|
||||
break;
|
||||
case "Sequence":
|
||||
newData.refElementId = loadedData.refElementId;
|
||||
break;
|
||||
case "Domain":
|
||||
newData.required = loadedData.minEntries > 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (loadedData.parameters !== undefined) {
|
||||
switch (newData.fieldType) {
|
||||
case "Number":
|
||||
newData.required = loadedData.minEntries > 0;
|
||||
const parameters: numberParams = JSON.parse(
|
||||
loadedData.parameters,
|
||||
);
|
||||
newData.minValue = parameters.minValue ?? undefined;
|
||||
newData.maxValue = parameters.maxValue ?? undefined;
|
||||
newData.step = parameters.step ?? undefined;
|
||||
break;
|
||||
case "Text":
|
||||
const textParameters: textParams = JSON.parse(
|
||||
loadedData.parameters,
|
||||
);
|
||||
newData.multiLine = textParameters.multiLine ?? false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
form.setState({ loaded: true, data: newData });
|
||||
} else {
|
||||
form.setState({ loaded: false });
|
||||
}
|
||||
} catch (ex: any) {
|
||||
form.handleGeneralError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (!editMode) form.setState({ loaded: true });
|
||||
};
|
||||
|
||||
loadData();
|
||||
}, [customFieldId, editMode]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
const doSubmit = async (buttonName: string) => {
|
||||
try {
|
||||
const { name, fieldType } = this.state.data;
|
||||
const { name, fieldType } = form.state.data;
|
||||
const nameStr = typeof name === "string" ? name : "";
|
||||
const fieldTypeStr = typeof fieldType === "string" ? fieldType : "";
|
||||
let { refElementId, defaultValue, minEntries, maxEntries, required } =
|
||||
this.state.data;
|
||||
form.state.data;
|
||||
let numberParams: numberParams | undefined = undefined;
|
||||
let textParams: textParams | undefined = undefined;
|
||||
let params;
|
||||
let refElementIdValue: GeneralIdRef | undefined;
|
||||
|
||||
switch (fieldType) {
|
||||
switch (fieldTypeStr) {
|
||||
case "Sequence":
|
||||
minEntries = 1;
|
||||
maxEntries = 1;
|
||||
@ -171,15 +243,31 @@ class CustomFieldDetails extends Form<any, any, CustomFieldDetailsState> {
|
||||
case "Text":
|
||||
minEntries = 1;
|
||||
maxEntries = 1;
|
||||
let { multiLine } = this.state.data;
|
||||
textParams = { multiLine };
|
||||
let { multiLine } = form.state.data;
|
||||
textParams = { multiLine: Boolean(multiLine) };
|
||||
params = textParams;
|
||||
refElementIdValue = undefined;
|
||||
break;
|
||||
case "Number":
|
||||
refElementIdValue = undefined;
|
||||
let { minValue, maxValue, step } = this.state.data;
|
||||
numberParams = { minValue, maxValue, step };
|
||||
let { minValue, maxValue, step } = form.state.data;
|
||||
const minValueNum =
|
||||
minValue === null || minValue === undefined || minValue === ""
|
||||
? undefined
|
||||
: Number(minValue);
|
||||
const maxValueNum =
|
||||
maxValue === null || maxValue === undefined || maxValue === ""
|
||||
? undefined
|
||||
: Number(maxValue);
|
||||
const stepNum =
|
||||
step === null || step === undefined || step === ""
|
||||
? undefined
|
||||
: Number(step);
|
||||
numberParams = {
|
||||
minValue: minValueNum,
|
||||
maxValue: maxValueNum,
|
||||
step: stepNum,
|
||||
};
|
||||
params = numberParams;
|
||||
minEntries = required ? 1 : 0;
|
||||
maxEntries = 1;
|
||||
@ -188,19 +276,30 @@ class CustomFieldDetails extends Form<any, any, CustomFieldDetailsState> {
|
||||
refElementIdValue = undefined;
|
||||
}
|
||||
|
||||
const minEntriesValue =
|
||||
typeof minEntries === "number"
|
||||
? minEntries
|
||||
: minEntries === undefined || minEntries === null || minEntries === ""
|
||||
? 0
|
||||
: Number(minEntries);
|
||||
const cleanMaxEntries: Number | undefined =
|
||||
maxEntries === "" ? undefined : Number(maxEntries);
|
||||
|
||||
if (this.isEditMode()) {
|
||||
const { customFieldId } = this.props.router.params;
|
||||
const defaultValueStr =
|
||||
typeof defaultValue === "string"
|
||||
? defaultValue
|
||||
: defaultValue === undefined || defaultValue === null
|
||||
? ""
|
||||
: String(defaultValue);
|
||||
|
||||
var generalIdRef = MakeGeneralIdRef(customFieldId);
|
||||
if (isEditMode()) {
|
||||
var generalIdRef = MakeGeneralIdRef(BigInt(customFieldId!));
|
||||
const response = await customFieldsService.putField(
|
||||
generalIdRef,
|
||||
name,
|
||||
fieldType,
|
||||
defaultValue,
|
||||
minEntries,
|
||||
nameStr,
|
||||
fieldTypeStr,
|
||||
defaultValueStr,
|
||||
minEntriesValue,
|
||||
cleanMaxEntries,
|
||||
refElementIdValue,
|
||||
params,
|
||||
@ -210,10 +309,10 @@ class CustomFieldDetails extends Form<any, any, CustomFieldDetailsState> {
|
||||
}
|
||||
} else {
|
||||
const response = await customFieldsService.postField(
|
||||
name,
|
||||
fieldType,
|
||||
defaultValue,
|
||||
minEntries,
|
||||
nameStr,
|
||||
fieldTypeStr,
|
||||
defaultValueStr,
|
||||
minEntriesValue,
|
||||
cleanMaxEntries,
|
||||
refElementIdValue,
|
||||
params,
|
||||
@ -223,262 +322,324 @@ class CustomFieldDetails extends Form<any, any, CustomFieldDetailsState> {
|
||||
}
|
||||
}
|
||||
|
||||
if (buttonName === this.labelSave)
|
||||
this.setState({ redirect: "/customfields" });
|
||||
if (buttonName === "save") form.setState({ redirect: "/customfields" });
|
||||
} catch (ex: any) {
|
||||
this.handleGeneralError(ex);
|
||||
form.handleGeneralError(ex);
|
||||
}
|
||||
};
|
||||
|
||||
isEditMode = () => {
|
||||
const { editMode } = this.props;
|
||||
return editMode;
|
||||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||
form.handleSubmit(e, doSubmit);
|
||||
};
|
||||
|
||||
componentDidMount = async () => {
|
||||
const { customFieldId } = this.props.router.params;
|
||||
if (form.state.redirect) return <Navigate to={form.state.redirect} />;
|
||||
|
||||
if (customFieldId !== undefined) {
|
||||
try {
|
||||
const loadedData = await customFieldsService.getField(customFieldId);
|
||||
const { fieldType } = form.state.data;
|
||||
const fieldTypeValue = typeof fieldType === "string" ? fieldType : "";
|
||||
|
||||
const { data } = this.state;
|
||||
if (loadedData) {
|
||||
data.name = loadedData.name;
|
||||
data.fieldType = loadedData.fieldType;
|
||||
data.defaultValue = loadedData.defaultValue;
|
||||
data.minEntries = loadedData.minEntries;
|
||||
data.maxEntries = loadedData.maxEntries;
|
||||
switch (data.fieldType) {
|
||||
case "Glossary":
|
||||
let convertedRefElementId: CustomFieldValue = {
|
||||
value: loadedData.refElementId,
|
||||
};
|
||||
let mode = "Add";
|
||||
if (isEditMode()) mode = "Edit";
|
||||
|
||||
data.refElementId = [convertedRefElementId];
|
||||
data.required = loadedData.minEntries > 0;
|
||||
break;
|
||||
case "Sequence":
|
||||
data.refElementId = loadedData.refElementId;
|
||||
break;
|
||||
case "Domain":
|
||||
data.required = loadedData.minEntries > 0;
|
||||
break;
|
||||
}
|
||||
const fieldTypeOptions: Option[] = [
|
||||
{ _id: "Text", name: "Text" },
|
||||
{ _id: "Number", name: "Number" },
|
||||
{ _id: "Sequence", name: "Sequence" },
|
||||
{ _id: "FormTemplate", name: "Form Template" },
|
||||
{ _id: "Glossary", name: "Glossary" },
|
||||
{ _id: "Domain", name: "Domain" },
|
||||
];
|
||||
|
||||
if (loadedData.parameters !== undefined) {
|
||||
switch (data.fieldType) {
|
||||
case "Number":
|
||||
data.required = loadedData.minEntries > 0;
|
||||
const parameters: numberParams = JSON.parse(
|
||||
loadedData.parameters,
|
||||
);
|
||||
data.minValue = parameters.minValue ?? undefined;
|
||||
data.maxValue = parameters.maxValue ?? undefined;
|
||||
data.step = parameters.step ?? undefined;
|
||||
break;
|
||||
case "Text":
|
||||
const textParameters: textParams = JSON.parse(
|
||||
loadedData.parameters,
|
||||
);
|
||||
data.multiLine = textParameters.multiLine ?? false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({ loaded: true, data });
|
||||
} else {
|
||||
this.setState({ loaded: false });
|
||||
}
|
||||
} catch (ex: any) {
|
||||
this.handleGeneralError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.isEditMode()) this.setState({ loaded: true });
|
||||
};
|
||||
|
||||
render() {
|
||||
const { loaded, redirect } = this.state;
|
||||
if (redirect !== "") return <Navigate to={redirect} />;
|
||||
|
||||
const { fieldType, minValue, maxValue, step } = this.state.data;
|
||||
|
||||
let mode = "Add";
|
||||
if (this.isEditMode()) mode = "Edit";
|
||||
|
||||
const fieldTypeOptions: Option[] = [
|
||||
{ _id: "Text", name: "Text" },
|
||||
{ _id: "Number", name: "Number" },
|
||||
// { _id: "Boolean", name: "Boolean" },
|
||||
// { _id: "Date", name: "Date" },
|
||||
// { _id: "Time", name: "Time" },
|
||||
// { _id: "DateTime", name: "DateTime" },
|
||||
{ _id: "Sequence", name: "Sequence" },
|
||||
{ _id: "FormTemplate", name: "Form Template" },
|
||||
{ _id: "Glossary", name: "Glossary" },
|
||||
{ _id: "Domain", name: "Domain" },
|
||||
];
|
||||
|
||||
switch (fieldType) {
|
||||
case "Sequence":
|
||||
this.labelRefElementId = "Sequence";
|
||||
break;
|
||||
case "FormTemplate":
|
||||
this.labelRefElementId = "Form";
|
||||
break;
|
||||
case "Glossary":
|
||||
this.labelRefElementId = "Glossary";
|
||||
break;
|
||||
}
|
||||
|
||||
return (
|
||||
<Loading loaded={loaded}>
|
||||
<h1>{mode} Custom Field</h1>
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
{this.renderError("_general")}
|
||||
{this.renderInput("name", this.labelName, InputType.text)}
|
||||
{this.renderSelect(
|
||||
"fieldType",
|
||||
this.labelFieldType,
|
||||
fieldTypeOptions,
|
||||
)}
|
||||
{this.state.data.fieldType === "Domain" && (
|
||||
<>
|
||||
{this.renderInput(
|
||||
"required",
|
||||
this.labelRequired,
|
||||
InputType.checkbox,
|
||||
)}
|
||||
{this.renderInput(
|
||||
"maxEntries",
|
||||
this.labelMaxEntries,
|
||||
InputType.number,
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{this.state.data.fieldType === "Glossary" && (
|
||||
<>
|
||||
{this.renderGlossaryPicker(
|
||||
true,
|
||||
"refElementId",
|
||||
this.labelRefElementId,
|
||||
1,
|
||||
SystemGlossaries,
|
||||
)}
|
||||
{this.renderInput(
|
||||
"required",
|
||||
this.labelRequired,
|
||||
InputType.checkbox,
|
||||
)}
|
||||
{this.renderInput(
|
||||
"maxEntries",
|
||||
this.labelMaxEntries,
|
||||
InputType.number,
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{this.state.data.fieldType === "Sequence" && (
|
||||
<>
|
||||
{this.renderSequencePicker(
|
||||
true,
|
||||
"refElementId",
|
||||
this.labelRefElementId,
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{this.state.data.fieldType === "Text" && (
|
||||
<>
|
||||
{this.renderInput(
|
||||
"multiLine",
|
||||
this.labelMultiLine,
|
||||
InputType.checkbox,
|
||||
)}
|
||||
{this.state.data.multiLine === true &&
|
||||
this.renderInputTextarea(
|
||||
true,
|
||||
"defaultValue",
|
||||
this.labelDefaultValue,
|
||||
)}
|
||||
{this.state.data.multiLine === false &&
|
||||
this.renderInput(
|
||||
"defaultValue",
|
||||
this.labelDefaultValue,
|
||||
InputType.text,
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{this.state.data.fieldType === "Number" && (
|
||||
<>
|
||||
{this.renderInput(
|
||||
"required",
|
||||
this.labelRequired,
|
||||
InputType.checkbox,
|
||||
)}
|
||||
{this.renderInputNumber(
|
||||
"minValue",
|
||||
this.labelMinValue,
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
maxValue,
|
||||
undefined,
|
||||
)}
|
||||
{this.renderInputNumber(
|
||||
"maxValue",
|
||||
this.labelMaxValue,
|
||||
false,
|
||||
undefined,
|
||||
minValue,
|
||||
undefined,
|
||||
undefined,
|
||||
)}
|
||||
{this.renderInput("step", this.labelStep, InputType.number)}
|
||||
{this.renderInputNumber(
|
||||
"defaultValue",
|
||||
this.labelDefaultValue,
|
||||
false,
|
||||
undefined,
|
||||
minValue,
|
||||
maxValue,
|
||||
step,
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{![
|
||||
"Domain",
|
||||
"Glossary",
|
||||
"Sequence",
|
||||
"FormTemplate",
|
||||
"Text",
|
||||
"Number",
|
||||
].includes(this.state.data.fieldType) && (
|
||||
<>
|
||||
{this.renderInput(
|
||||
"defaultValue",
|
||||
this.labelDefaultValue,
|
||||
InputType.text,
|
||||
)}
|
||||
{this.renderInput(
|
||||
"minEntries",
|
||||
this.labelMinEntries,
|
||||
InputType.number,
|
||||
)}
|
||||
{this.renderInput(
|
||||
"maxEntries",
|
||||
this.labelMaxEntries,
|
||||
InputType.number,
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{this.isEditMode() && this.renderButton(this.labelApply)}
|
||||
{this.renderButton(this.labelSave)}
|
||||
</form>
|
||||
</Loading>
|
||||
);
|
||||
switch (fieldTypeValue) {
|
||||
case "Sequence":
|
||||
labelRefElementId = "Sequence";
|
||||
break;
|
||||
case "FormTemplate":
|
||||
labelRefElementId = "Form";
|
||||
break;
|
||||
case "Glossary":
|
||||
labelRefElementId = "Glossary";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const HOCCustomFieldDetails = withRouter(CustomFieldDetails);
|
||||
return (
|
||||
<Loading loaded={form.state.loaded}>
|
||||
<h1>{mode} Custom Field</h1>
|
||||
<form onSubmit={handleSubmit}>
|
||||
{renderError("_general", form.state.errors)}
|
||||
{renderInput(
|
||||
"name",
|
||||
labelName,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.text,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
{renderSelect(
|
||||
"fieldType",
|
||||
labelFieldType,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
fieldTypeOptions,
|
||||
form.handleSelectChange,
|
||||
)}
|
||||
{fieldTypeValue === "Domain" && (
|
||||
<>
|
||||
{renderInput(
|
||||
"required",
|
||||
labelRequired,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.checkbox,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
{renderInputNumber(
|
||||
"maxEntries",
|
||||
labelMaxEntries,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
false,
|
||||
"",
|
||||
undefined,
|
||||
undefined,
|
||||
1,
|
||||
form.handleChange,
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{fieldTypeValue === "Glossary" && (
|
||||
<>
|
||||
{renderGlossaryPicker(
|
||||
true,
|
||||
"refElementId",
|
||||
labelRefElementId,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
1,
|
||||
SystemGlossaries,
|
||||
form.handleGlossaryPickerChange,
|
||||
)}
|
||||
{renderInput(
|
||||
"required",
|
||||
labelRequired,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.checkbox,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
{renderInputNumber(
|
||||
"maxEntries",
|
||||
labelMaxEntries,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
false,
|
||||
"",
|
||||
undefined,
|
||||
undefined,
|
||||
1,
|
||||
form.handleChange,
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{fieldTypeValue === "Sequence" && (
|
||||
<>
|
||||
{renderSequencePicker(
|
||||
true,
|
||||
"refElementId",
|
||||
labelRefElementId,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
form.handlePickerChange,
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{fieldTypeValue === "Text" && (
|
||||
<>
|
||||
{renderInput(
|
||||
"multiLine",
|
||||
labelMultiLine,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.checkbox,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
{form.state.data.multiLine === true &&
|
||||
renderInputTextarea(
|
||||
true,
|
||||
"defaultValue",
|
||||
labelDefaultValue,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
false,
|
||||
"",
|
||||
form.handleTextAreaChange,
|
||||
)}
|
||||
{form.state.data.multiLine === false &&
|
||||
renderInput(
|
||||
"defaultValue",
|
||||
labelDefaultValue,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.text,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{fieldTypeValue === "Number" && (
|
||||
<>
|
||||
{renderInput(
|
||||
"required",
|
||||
labelRequired,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.checkbox,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
{renderInputNumber(
|
||||
"minValue",
|
||||
labelMinValue,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
false,
|
||||
"",
|
||||
undefined,
|
||||
undefined,
|
||||
1,
|
||||
form.handleChange,
|
||||
)}
|
||||
{renderInputNumber(
|
||||
"maxValue",
|
||||
labelMaxValue,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
false,
|
||||
"",
|
||||
undefined,
|
||||
undefined,
|
||||
1,
|
||||
form.handleChange,
|
||||
)}
|
||||
{renderInput(
|
||||
"step",
|
||||
labelStep,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.number,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
{renderInputNumber(
|
||||
"defaultValue",
|
||||
labelDefaultValue,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
false,
|
||||
"",
|
||||
undefined,
|
||||
undefined,
|
||||
1,
|
||||
form.handleChange,
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{![
|
||||
"Domain",
|
||||
"Glossary",
|
||||
"Sequence",
|
||||
"FormTemplate",
|
||||
"Text",
|
||||
"Number",
|
||||
].includes(fieldTypeValue) && (
|
||||
<>
|
||||
{renderInput(
|
||||
"defaultValue",
|
||||
labelDefaultValue,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.text,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
{renderInput(
|
||||
"minEntries",
|
||||
labelMinEntries,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.number,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
{renderInput(
|
||||
"maxEntries",
|
||||
labelMaxEntries,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.number,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{isEditMode() && renderButton(labelApply, form.state.errors, "apply")}
|
||||
{renderButton(labelSave, form.state.errors, "save")}
|
||||
</form>
|
||||
</Loading>
|
||||
);
|
||||
};
|
||||
|
||||
export default HOCCustomFieldDetails;
|
||||
export default CustomFieldDetails;
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useSearchParams } from "react-router-dom";
|
||||
import HorizontalTabs from "../../../components/common/HorizionalTabs";
|
||||
import Tab from "../../../components/common/Tab";
|
||||
import authentication from "../../frame/services/authenticationService";
|
||||
@ -13,11 +14,15 @@ interface DomainsDetailsProps {
|
||||
|
||||
const DomainsDetails: React.FC<DomainsDetailsProps> = ({ editMode }) => {
|
||||
const { t } = useTranslation();
|
||||
const [searchParams] = useSearchParams();
|
||||
|
||||
const canViewMailTemplates = authentication.hasAccess("ViewDomain");
|
||||
const canViewSecurityRoles = authentication.hasAccess("ViewRole");
|
||||
|
||||
const heading = editMode ? t("EditDomain") : t("AddDomain");
|
||||
const initialTab = searchParams.get("tab") || undefined;
|
||||
const roleId = searchParams.get("roleId") || undefined;
|
||||
const innerTab = searchParams.get("innerTab") || undefined;
|
||||
|
||||
const tabs: JSX.Element[] = [];
|
||||
|
||||
@ -38,7 +43,7 @@ const DomainsDetails: React.FC<DomainsDetailsProps> = ({ editMode }) => {
|
||||
if (canViewSecurityRoles) {
|
||||
tabs.push(
|
||||
<Tab key={3} label={t("SecurityRoles")}>
|
||||
<SecurityRolesTab />
|
||||
<SecurityRolesTab initialRoleId={roleId} initialInnerTab={innerTab} />
|
||||
</Tab>,
|
||||
);
|
||||
}
|
||||
@ -47,7 +52,7 @@ const DomainsDetails: React.FC<DomainsDetailsProps> = ({ editMode }) => {
|
||||
return (
|
||||
<div>
|
||||
<h1>{heading}</h1>
|
||||
<HorizontalTabs>{tabs}</HorizontalTabs>
|
||||
<HorizontalTabs initialTab={initialTab}>{tabs}</HorizontalTabs>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,82 +1,89 @@
|
||||
import Joi from "joi";
|
||||
import React from "react";
|
||||
import { Navigate } from "react-router-dom";
|
||||
import { Navigate, useParams } from "react-router-dom";
|
||||
import { toast } from "react-toastify";
|
||||
import Form, { FormState } from "../../../../components/common/Form";
|
||||
import { GeneralIdRef, MakeGeneralIdRef } from "../../../../utils/GeneralIdRef";
|
||||
import withRouter, { RouterProps } from "../../../../utils/withRouter";
|
||||
import { useForm } from "../../../../components/common/useForm";
|
||||
import { MakeGeneralIdRef } from "../../../../utils/GeneralIdRef";
|
||||
import roleService from "../serrvices/rolesService";
|
||||
import Loading from "../../../../components/common/Loading";
|
||||
import {
|
||||
renderError,
|
||||
renderButton,
|
||||
renderUserPicker,
|
||||
} from "../../../../components/common/formHelpers";
|
||||
|
||||
interface LocAddUserToRoleProps extends RouterProps {
|
||||
isEditMode : boolean;
|
||||
interface LocAddUserToRoleProps {
|
||||
isEditMode: boolean;
|
||||
}
|
||||
|
||||
interface LocAddUserToRoleState extends FormState {
|
||||
const AddUserToRole: React.FC<LocAddUserToRoleProps> = ({ isEditMode }) => {
|
||||
const { domainId, roleId } = useParams<{
|
||||
domainId: string;
|
||||
roleId: string;
|
||||
}>();
|
||||
|
||||
const labelUserId = "User";
|
||||
const labelApply = "Save";
|
||||
const labelSave = "Save and close";
|
||||
|
||||
const form = useForm({
|
||||
loaded: true,
|
||||
data: {
|
||||
userId?: GeneralIdRef;
|
||||
};
|
||||
redirect: string;
|
||||
}
|
||||
userId: undefined,
|
||||
},
|
||||
errors: {},
|
||||
redirect: "",
|
||||
});
|
||||
|
||||
class LocAddUserToRole extends Form<LocAddUserToRoleProps, any, LocAddUserToRoleState> {
|
||||
state: LocAddUserToRoleState = {
|
||||
loaded: true,
|
||||
data: {
|
||||
//userId: null;
|
||||
},
|
||||
errors: {},
|
||||
redirect: "",
|
||||
};
|
||||
form.schema = {
|
||||
userId: Joi.any().required().label(labelUserId),
|
||||
};
|
||||
|
||||
labelUserId = "User";
|
||||
const doSubmit = async (buttonName: string) => {
|
||||
try {
|
||||
const { userId } = form.state.data;
|
||||
const userIdValue = userId as any;
|
||||
const response = await roleService.postRoleUser(
|
||||
userIdValue,
|
||||
MakeGeneralIdRef(BigInt(roleId!)),
|
||||
);
|
||||
if (response) {
|
||||
toast.info("User added to role");
|
||||
|
||||
labelApply = "Save";
|
||||
labelSave = "Save and close";
|
||||
|
||||
|
||||
schema = {
|
||||
userId: Joi.any().required().label(this.labelUserId),
|
||||
};
|
||||
|
||||
doSubmit = async (buttonName : string) => {
|
||||
try {
|
||||
const { userId } = this.state.data;
|
||||
const { domainId, roleId } = this.props.router.params;
|
||||
|
||||
const response = await roleService.postRoleUser(userId!, MakeGeneralIdRef(roleId));
|
||||
if (response) {
|
||||
toast.info("User added to role");
|
||||
|
||||
if (buttonName === this.labelSave)
|
||||
this.setState({ redirect: "/domains/edit/" + domainId });
|
||||
}
|
||||
}
|
||||
catch(ex: any) {
|
||||
this.handleGeneralError(ex);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { loaded, redirect } = this.state;
|
||||
if (redirect !== "") return <Navigate to={redirect} />;
|
||||
|
||||
const { isEditMode } = this.props;
|
||||
|
||||
return (
|
||||
<Loading loaded={loaded}>
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
{this.renderError("_general")}
|
||||
{this.renderUserPicker("userId", this.labelUserId)}
|
||||
|
||||
{isEditMode && this.renderButton(this.labelApply)}
|
||||
{this.renderButton(this.labelSave)}
|
||||
</form>
|
||||
</Loading>
|
||||
);
|
||||
if (buttonName === labelSave)
|
||||
form.setState({
|
||||
redirect: `/domains/edit/${domainId}?tab=SecurityRoles&roleId=${roleId}&innerTab=Users`,
|
||||
});
|
||||
}
|
||||
} catch (ex: any) {
|
||||
form.handleGeneralError(ex);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const AddUserToRole = withRouter(LocAddUserToRole);
|
||||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||
form.handleSubmit(e, doSubmit);
|
||||
};
|
||||
|
||||
const { loaded, redirect } = form.state;
|
||||
if (redirect) return <Navigate to={redirect} />;
|
||||
|
||||
return (
|
||||
<Loading loaded={loaded}>
|
||||
<form onSubmit={handleSubmit}>
|
||||
{renderError("_general", form.state.errors)}
|
||||
{renderUserPicker(
|
||||
"userId",
|
||||
labelUserId,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
form.handleUserPickerChange,
|
||||
)}
|
||||
|
||||
{isEditMode && renderButton(labelApply, form.state.errors, "apply")}
|
||||
{renderButton(labelSave, form.state.errors, "save")}
|
||||
</form>
|
||||
</Loading>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddUserToRole;
|
||||
|
||||
@ -1,130 +1,172 @@
|
||||
import Joi from "joi";
|
||||
import React from "react";
|
||||
import React, { useEffect } from "react";
|
||||
import { Navigate } from "react-router-dom";
|
||||
import { toast } from "react-toastify";
|
||||
import Form, { FormState } from "../../../../components/common/Form";
|
||||
import { useForm } from "../../../../components/common/useForm";
|
||||
import { InputType } from "../../../../components/common/Input";
|
||||
import { MakeGeneralIdRef } from "../../../../utils/GeneralIdRef";
|
||||
import withRouter from "../../../../utils/withRouter";
|
||||
import mailTemplatesService from "../serrvices/mailTemplatesService";
|
||||
import Loading from "../../../../components/common/Loading";
|
||||
import {
|
||||
renderError,
|
||||
renderButton,
|
||||
renderInput,
|
||||
renderTemplateEditor,
|
||||
} from "../../../../components/common/formHelpers";
|
||||
|
||||
interface EmailTemplateEditorProps{
|
||||
domainId : number,
|
||||
currentMailType : string
|
||||
interface EmailTemplateEditorProps {
|
||||
domainId?: string;
|
||||
currentMailType: string;
|
||||
}
|
||||
|
||||
interface EmailTemplateEditorState extends FormState {
|
||||
const EmailTemplateEditor: React.FC<EmailTemplateEditorProps> = ({
|
||||
domainId,
|
||||
currentMailType,
|
||||
}) => {
|
||||
const labelName = "Subject";
|
||||
const labelDefinition = "Definition";
|
||||
const labelApply = "Save";
|
||||
const labelSave = "Save and close";
|
||||
|
||||
const form = useForm({
|
||||
loaded: false,
|
||||
data: {
|
||||
currentMailType? : string
|
||||
isOverridden : boolean
|
||||
subject: string;
|
||||
definition: string;
|
||||
};
|
||||
redirect: string;
|
||||
}
|
||||
currentMailType: undefined,
|
||||
isOverridden: false,
|
||||
subject: "",
|
||||
definition: "",
|
||||
},
|
||||
errors: {},
|
||||
redirect: "",
|
||||
});
|
||||
|
||||
class EmailTemplateEditor extends Form<EmailTemplateEditorProps, any, EmailTemplateEditorState> {
|
||||
state: EmailTemplateEditorState = {
|
||||
loaded : false,
|
||||
data: {
|
||||
currentMailType : undefined,
|
||||
isOverridden : false,
|
||||
form.schema = {
|
||||
currentMailType: Joi.optional(),
|
||||
isOverridden: Joi.optional(),
|
||||
subject: Joi.string().required().max(450).label(labelName),
|
||||
definition: Joi.string().required().label(labelDefinition),
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const loadTemplate = async () => {
|
||||
try {
|
||||
if (!domainId) return;
|
||||
|
||||
// Reset form state while loading
|
||||
form.setState({
|
||||
loaded: false,
|
||||
data: {
|
||||
currentMailType: undefined,
|
||||
isOverridden: false,
|
||||
subject: "",
|
||||
definition: "",
|
||||
},
|
||||
errors: {},
|
||||
redirect: "",
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
labelName = "Subject";
|
||||
labelDefinition = "Definition";
|
||||
|
||||
labelApply = "Save";
|
||||
labelSave = "Save and close";
|
||||
|
||||
schema = {
|
||||
currentMailType : Joi.optional(),
|
||||
isOverridden : Joi.optional(),
|
||||
subject: Joi.string().required().max(450).label(this.labelName),
|
||||
definition: Joi.string().required().label(this.labelDefinition),
|
||||
};
|
||||
|
||||
componentDidMount = async () => {
|
||||
this.handleTemplateChange();
|
||||
};
|
||||
|
||||
componentDidUpdate = async (prevProps : EmailTemplateEditorProps) => {
|
||||
if (prevProps.domainId !== this.props.domainId || prevProps.currentMailType !== this.props.currentMailType ) {
|
||||
this.handleTemplateChange();
|
||||
}
|
||||
}
|
||||
|
||||
handleTemplateChange = async() => {
|
||||
const { domainId, currentMailType } = this.props;
|
||||
|
||||
try{
|
||||
var mailTemplate = await mailTemplatesService.getTemplate( MakeGeneralIdRef(domainId, undefined), currentMailType )
|
||||
|
||||
if (mailTemplate !== null)
|
||||
{
|
||||
this.setState({
|
||||
loaded: true,
|
||||
data : {
|
||||
currentMailType : currentMailType,
|
||||
isOverridden : mailTemplate.isOverridden,
|
||||
subject : mailTemplate.subject,
|
||||
definition : mailTemplate.templateDefinition
|
||||
}});
|
||||
}
|
||||
}
|
||||
catch(ex: any) {
|
||||
this.handleGeneralError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
doSubmit = async (buttonName : string) => {
|
||||
try {
|
||||
const { domainId, currentMailType } = this.props;
|
||||
const { subject, definition } = this.state.data;
|
||||
|
||||
var domainGeneralIdRef = MakeGeneralIdRef(domainId);
|
||||
const response = await mailTemplatesService.postTemplate(domainGeneralIdRef, currentMailType, subject, definition);
|
||||
if (response) {
|
||||
toast.info("Email Template saved");
|
||||
if (buttonName === this.labelSave)
|
||||
this.setState({ redirect: "/domains" });
|
||||
}
|
||||
}
|
||||
catch(ex: any) {
|
||||
this.handleGeneralError(ex);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { loaded, redirect } = this.state;
|
||||
const { currentMailType, isOverridden } = this.state.data;
|
||||
if (redirect !== "") return <Navigate to={redirect} />;
|
||||
|
||||
|
||||
return (
|
||||
<Loading loaded={loaded}>
|
||||
{isOverridden && <p>This template is custom for this domain only</p>}
|
||||
{!isOverridden && <p>The details below are loaded from the master template. Saving this template will mean that any changes to the master template will not automatically appear here.</p>}
|
||||
|
||||
<form onSubmit={this.handleSubmit} template-name={currentMailType}>
|
||||
{this.renderError("_general")}
|
||||
{this.renderInput("subject", this.labelName, InputType.text)}
|
||||
{this.renderTemplateEditor("mailTemplate-editor","definition", this.labelDefinition, false)}
|
||||
|
||||
{this.renderButton(this.labelApply)}
|
||||
{this.renderButton(this.labelSave)}
|
||||
</form>
|
||||
</Loading>
|
||||
const domainIdValue = BigInt(domainId);
|
||||
var mailTemplate = await mailTemplatesService.getTemplate(
|
||||
MakeGeneralIdRef(domainIdValue),
|
||||
currentMailType,
|
||||
);
|
||||
|
||||
if (mailTemplate !== null) {
|
||||
form.setState({
|
||||
loaded: true,
|
||||
data: {
|
||||
currentMailType: currentMailType,
|
||||
isOverridden: mailTemplate.isOverridden,
|
||||
subject: mailTemplate.subject,
|
||||
definition: mailTemplate.templateDefinition,
|
||||
},
|
||||
});
|
||||
}
|
||||
} catch (ex: any) {
|
||||
form.handleGeneralError(ex);
|
||||
}
|
||||
};
|
||||
|
||||
void loadTemplate();
|
||||
}, [domainId, currentMailType]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
const doSubmit = async (buttonName: string) => {
|
||||
try {
|
||||
const { subject, definition } = form.state.data;
|
||||
if (!domainId) return;
|
||||
const domainGeneralIdRef = MakeGeneralIdRef(BigInt(domainId));
|
||||
const subjectStr = typeof subject === "string" ? subject : "";
|
||||
const definitionStr = typeof definition === "string" ? definition : "";
|
||||
const response = await mailTemplatesService.postTemplate(
|
||||
domainGeneralIdRef,
|
||||
currentMailType,
|
||||
subjectStr,
|
||||
definitionStr,
|
||||
);
|
||||
if (response) {
|
||||
toast.info("Email Template saved");
|
||||
if (buttonName === labelSave) form.setState({ redirect: "/domains" });
|
||||
}
|
||||
} catch (ex: any) {
|
||||
form.handleGeneralError(ex);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const HOCEmailTemplateEditor = withRouter(EmailTemplateEditor);
|
||||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||
form.handleSubmit(e, doSubmit);
|
||||
};
|
||||
|
||||
export default HOCEmailTemplateEditor;
|
||||
const { redirect } = form.state;
|
||||
const { isOverridden } = form.state.data;
|
||||
const isOverriddenValue = Boolean(isOverridden);
|
||||
if (redirect) return <Navigate to={redirect} />;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div style={{ position: "relative" }}>
|
||||
{isOverriddenValue && (
|
||||
<p>This template is custom for this domain only</p>
|
||||
)}
|
||||
{!isOverriddenValue && (
|
||||
<p>
|
||||
The details below are loaded from the master template. Saving this
|
||||
template will mean that any changes to the master template will not
|
||||
automatically appear here.
|
||||
</p>
|
||||
)}
|
||||
|
||||
<form
|
||||
onSubmit={handleSubmit}
|
||||
template-name={currentMailType}
|
||||
key={currentMailType}
|
||||
>
|
||||
{renderError("_general", form.state.errors)}
|
||||
{renderInput(
|
||||
"subject",
|
||||
labelName,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.text,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
{renderTemplateEditor(
|
||||
"mailTemplate-editor",
|
||||
"definition",
|
||||
labelDefinition,
|
||||
form.state.data,
|
||||
false,
|
||||
form.handleTemplateEditorChange,
|
||||
)}
|
||||
|
||||
{renderButton(labelApply, form.state.errors, "apply")}
|
||||
{renderButton(labelSave, form.state.errors, "save")}
|
||||
</form>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default EmailTemplateEditor;
|
||||
|
||||
@ -1,148 +1,247 @@
|
||||
import Joi from "joi";
|
||||
import React from "react";
|
||||
import { Navigate } from "react-router-dom";
|
||||
import React, { useEffect } from "react";
|
||||
import { Navigate, useParams } from "react-router-dom";
|
||||
import { toast } from "react-toastify";
|
||||
import Form, { FormState } from "../../../../components/common/Form";
|
||||
import { useForm } from "../../../../components/common/useForm";
|
||||
import { InputType } from "../../../../components/common/Input";
|
||||
import { GeneralIdRef, MakeGeneralIdRef } from "../../../../utils/GeneralIdRef";
|
||||
import withRouter, { RouterProps } from "../../../../utils/withRouter";
|
||||
import { MakeGeneralIdRef } from "../../../../utils/GeneralIdRef";
|
||||
import domainsService from "../serrvices/domainsService";
|
||||
import Loading from "../../../../components/common/Loading";
|
||||
import {
|
||||
renderError,
|
||||
renderButton,
|
||||
renderInput,
|
||||
renderSsoProviderPicker,
|
||||
} from "../../../../components/common/formHelpers";
|
||||
|
||||
interface GeneralTabProps extends RouterProps {
|
||||
isEditMode: boolean;
|
||||
interface GeneralTabProps {
|
||||
isEditMode: boolean;
|
||||
}
|
||||
|
||||
interface GeneralTabState extends FormState {
|
||||
const GeneralTab: React.FC<GeneralTabProps> = ({ isEditMode }) => {
|
||||
const { domainId } = useParams<{ domainId: string }>();
|
||||
|
||||
const labelName = "Name";
|
||||
const labelSsoProvider = "Sso Provider";
|
||||
const labelSunriseHostName = "e-flow hostname";
|
||||
const labelSunriseAppId = "e-flow AppId";
|
||||
const labelSunriseCategoryId = "e-flow CategoryId";
|
||||
const labelSigmaId = "Sigma Id";
|
||||
|
||||
const labelApply = "Save";
|
||||
const labelSave = "Save and close";
|
||||
|
||||
const form = useForm({
|
||||
loaded: false,
|
||||
data: {
|
||||
name: string;
|
||||
ssoProviderId: GeneralIdRef | null;
|
||||
sunriseHostName: string;
|
||||
sunriseAppId: string;
|
||||
sunriseCategoryId: string;
|
||||
sigmaId: bigint | null;
|
||||
};
|
||||
redirect: string;
|
||||
}
|
||||
name: "",
|
||||
ssoProviderId: null,
|
||||
sunriseHostName: "",
|
||||
sunriseAppId: "",
|
||||
sunriseCategoryId: "",
|
||||
sigmaId: null,
|
||||
},
|
||||
errors: {},
|
||||
redirect: "",
|
||||
});
|
||||
|
||||
class LocGeneralTab extends Form<GeneralTabProps, any, GeneralTabState> {
|
||||
state: GeneralTabState = {
|
||||
loaded: false,
|
||||
data: {
|
||||
name: "",
|
||||
ssoProviderId: null,
|
||||
sunriseHostName: "",
|
||||
sunriseAppId: "",
|
||||
sunriseCategoryId: "",
|
||||
sigmaId: null,
|
||||
},
|
||||
errors: {},
|
||||
redirect: "",
|
||||
};
|
||||
form.schema = {
|
||||
name: Joi.string().required().max(450).label(labelName),
|
||||
ssoProviderId: Joi.object().allow(null).optional().label(labelSsoProvider),
|
||||
sunriseHostName: Joi.string()
|
||||
.required()
|
||||
.allow("")
|
||||
.max(16)
|
||||
.label(labelSunriseHostName),
|
||||
sunriseAppId: Joi.string().required().allow("").label(labelSunriseAppId),
|
||||
sunriseCategoryId: Joi.string()
|
||||
.required()
|
||||
.allow("")
|
||||
.label(labelSunriseCategoryId),
|
||||
sigmaId: Joi.number().allow(null).optional().label(labelSigmaId),
|
||||
};
|
||||
|
||||
labelName = "Name";
|
||||
labelSsoProvider = "Sso Provider";
|
||||
labelSunriseHostName = "e-flow hostname";
|
||||
labelSunriseAppId = "e-flow AppId";
|
||||
labelSunriseCategoryId = "e-flow CategoryId";
|
||||
labelSigmaId = "Sigma Id";
|
||||
const doSubmit = async (buttonName: string) => {
|
||||
try {
|
||||
const {
|
||||
name,
|
||||
ssoProviderId,
|
||||
sunriseHostName,
|
||||
sunriseAppId,
|
||||
sunriseCategoryId,
|
||||
sigmaId,
|
||||
} = form.state.data;
|
||||
const nameStr = typeof name === "string" ? name : "";
|
||||
const sunriseHostNameStr =
|
||||
typeof sunriseHostName === "string" ? sunriseHostName : "";
|
||||
const sunriseAppIdStr =
|
||||
typeof sunriseAppId === "string" ? sunriseAppId : "";
|
||||
const sunriseCategoryIdStr =
|
||||
typeof sunriseCategoryId === "string" ? sunriseCategoryId : "";
|
||||
const sigmaIdValue =
|
||||
sigmaId === null || sigmaId === undefined || sigmaId === ""
|
||||
? null
|
||||
: typeof sigmaId === "bigint"
|
||||
? sigmaId
|
||||
: BigInt(sigmaId as string | number);
|
||||
|
||||
labelApply = "Save";
|
||||
labelSave = "Save and close";
|
||||
|
||||
schema = {
|
||||
name: Joi.string().required().max(450).label(this.labelName),
|
||||
ssoProviderId: Joi.object().allow(null).optional().label(this.labelSsoProvider),
|
||||
sunriseHostName: Joi.string().required().allow("").max(16).label(this.labelSunriseHostName),
|
||||
sunriseAppId: Joi.string().required().allow("").label(this.labelSunriseAppId),
|
||||
sunriseCategoryId: Joi.string().required().allow("").label(this.labelSunriseCategoryId),
|
||||
sigmaId: Joi.number().allow(null).optional().label(this.labelSigmaId),
|
||||
};
|
||||
|
||||
doSubmit = async (buttonName: string) => {
|
||||
try {
|
||||
const { name, ssoProviderId, sunriseHostName, sunriseAppId, sunriseCategoryId, sigmaId } = this.state.data;
|
||||
const { isEditMode } = this.props;
|
||||
|
||||
if (isEditMode) {
|
||||
const { domainId } = this.props.router.params;
|
||||
|
||||
var generalIdRef = MakeGeneralIdRef(domainId);
|
||||
const response = await domainsService.putDomain(generalIdRef, name, sunriseHostName, sunriseAppId, sunriseCategoryId, ssoProviderId, sigmaId);
|
||||
if (response) {
|
||||
toast.info("Domain edited");
|
||||
}
|
||||
} else {
|
||||
const response = await domainsService.postDomain(name, sunriseHostName, sunriseAppId, sunriseCategoryId, ssoProviderId, sigmaId);
|
||||
if (response) {
|
||||
toast.info("New Domain added");
|
||||
}
|
||||
}
|
||||
|
||||
if (buttonName === this.labelSave) this.setState({ redirect: "/domains" });
|
||||
} catch (ex: any) {
|
||||
this.handleGeneralError(ex);
|
||||
}
|
||||
};
|
||||
|
||||
isEditMode = () => {
|
||||
const { editMode } = this.props;
|
||||
return editMode;
|
||||
};
|
||||
|
||||
componentDidMount = async () => {
|
||||
const { domainId } = this.props.router.params;
|
||||
try {
|
||||
if (domainId !== undefined) {
|
||||
const loadedData = await domainsService.getDomain(domainId);
|
||||
if (loadedData) {
|
||||
const { data } = this.state;
|
||||
|
||||
data.name = loadedData.name;
|
||||
data.ssoProviderId = loadedData.ssoProviderId;
|
||||
data.sunriseHostName = loadedData.sunriseHostName;
|
||||
data.sunriseAppId = loadedData.sunriseAppId;
|
||||
data.sunriseCategoryId = loadedData.sunriseCategoryId;
|
||||
data.sigmaId = loadedData.sigmaId;
|
||||
|
||||
this.setState({ loaded: true, data });
|
||||
} else {
|
||||
this.setState({ loaded: false });
|
||||
}
|
||||
}
|
||||
} catch (ex: any) {
|
||||
this.handleGeneralError(ex);
|
||||
}
|
||||
|
||||
if (!this.isEditMode()) this.setState({ loaded: true });
|
||||
};
|
||||
|
||||
render() {
|
||||
const { loaded } = this.state;
|
||||
const isEditMode = this.isEditMode();
|
||||
|
||||
const { redirect } = this.state;
|
||||
if (redirect !== "") return <Navigate to={redirect} />;
|
||||
|
||||
return (
|
||||
<Loading loaded={loaded}>
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
{this.renderError("_general")}
|
||||
{this.renderInput("name", this.labelName, InputType.text)}
|
||||
{this.renderInput("sunriseHostName", this.labelSunriseHostName, InputType.text)}
|
||||
{this.renderInput("sunriseAppId", this.labelSunriseAppId, InputType.text)}
|
||||
{this.renderInput("sunriseCategoryId", this.labelSunriseCategoryId, InputType.text)}
|
||||
{this.renderSsoProviderPicker("ssoProviderId", this.labelSsoProvider)}
|
||||
{this.renderInput("sigmaId", this.labelSigmaId, InputType.number)}
|
||||
|
||||
{isEditMode && this.renderButton(this.labelApply)}
|
||||
{this.renderButton(this.labelSave)}
|
||||
</form>
|
||||
</Loading>
|
||||
if (isEditMode) {
|
||||
var generalIdRef = MakeGeneralIdRef(BigInt(domainId!));
|
||||
const response = await domainsService.putDomain(
|
||||
generalIdRef,
|
||||
nameStr,
|
||||
sunriseHostNameStr,
|
||||
sunriseAppIdStr,
|
||||
sunriseCategoryIdStr,
|
||||
ssoProviderId as any,
|
||||
sigmaIdValue,
|
||||
);
|
||||
if (response) {
|
||||
toast.info("Domain edited");
|
||||
}
|
||||
} else {
|
||||
const response = await domainsService.postDomain(
|
||||
nameStr,
|
||||
sunriseHostNameStr,
|
||||
sunriseAppIdStr,
|
||||
sunriseCategoryIdStr,
|
||||
ssoProviderId as any,
|
||||
sigmaIdValue,
|
||||
);
|
||||
if (response) {
|
||||
toast.info("New Domain added");
|
||||
}
|
||||
}
|
||||
|
||||
if (buttonName === "save") form.setState({ redirect: "/domains" });
|
||||
} catch (ex: any) {
|
||||
form.handleGeneralError(ex);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const GeneralTab = withRouter(LocGeneralTab);
|
||||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||
form.handleSubmit(e, doSubmit);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const loadData = async () => {
|
||||
try {
|
||||
if (domainId !== undefined) {
|
||||
const loadedData = await domainsService.getDomain(BigInt(domainId));
|
||||
if (loadedData) {
|
||||
const newData = { ...form.state.data };
|
||||
|
||||
newData.name = loadedData.name;
|
||||
newData.ssoProviderId = loadedData.ssoProviderId;
|
||||
newData.sunriseHostName = loadedData.sunriseHostName;
|
||||
newData.sunriseAppId = loadedData.sunriseAppId;
|
||||
newData.sunriseCategoryId = loadedData.sunriseCategoryId;
|
||||
newData.sigmaId = loadedData.sigmaId;
|
||||
|
||||
form.setState({ loaded: true, data: newData });
|
||||
} else {
|
||||
form.setState({ loaded: false });
|
||||
}
|
||||
}
|
||||
} catch (ex: any) {
|
||||
form.handleGeneralError(ex);
|
||||
}
|
||||
|
||||
if (!isEditMode) form.setState({ loaded: true });
|
||||
};
|
||||
|
||||
loadData();
|
||||
}, [domainId, isEditMode]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
const { loaded, redirect } = form.state;
|
||||
if (redirect) return <Navigate to={redirect} />;
|
||||
|
||||
return (
|
||||
<Loading loaded={loaded}>
|
||||
<form onSubmit={handleSubmit}>
|
||||
{renderError("_general", form.state.errors)}
|
||||
{renderInput(
|
||||
"name",
|
||||
labelName,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.text,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
{renderInput(
|
||||
"sunriseHostName",
|
||||
labelSunriseHostName,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.text,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
{renderInput(
|
||||
"sunriseAppId",
|
||||
labelSunriseAppId,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.text,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
{renderInput(
|
||||
"sunriseCategoryId",
|
||||
labelSunriseCategoryId,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.text,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
{renderSsoProviderPicker(
|
||||
"ssoProviderId",
|
||||
labelSsoProvider,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
form.handleSsoProviderPickerChange,
|
||||
)}
|
||||
{renderInput(
|
||||
"sigmaId",
|
||||
labelSigmaId,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.number,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
|
||||
{isEditMode && renderButton(labelApply, form.state.errors, "apply")}
|
||||
{renderButton(labelSave, form.state.errors, "save")}
|
||||
</form>
|
||||
</Loading>
|
||||
);
|
||||
};
|
||||
export default GeneralTab;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import React, { useEffect, useState, useCallback } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import mailTemplatesService from "../serrvices/mailTemplatesService";
|
||||
import HOCEmailTemplateEditor from "./EmailTemplateEditor";
|
||||
@ -10,7 +10,7 @@ interface MailType {
|
||||
}
|
||||
|
||||
const MailTemplatesTab: React.FC = () => {
|
||||
const [loaded, setLoaded] = useState(false);
|
||||
const [loaded, setLoaded] = useState(true);
|
||||
const [currentMailType, setCurrentMailType] = useState("");
|
||||
const [types, setTypes] = useState<MailType[]>([]);
|
||||
|
||||
@ -22,21 +22,23 @@ const MailTemplatesTab: React.FC = () => {
|
||||
setTypes(nextTypes);
|
||||
|
||||
if (nextTypes.length > 0) {
|
||||
setLoaded(true);
|
||||
setCurrentMailType(nextTypes[0].mailType);
|
||||
}
|
||||
setLoaded(true);
|
||||
}
|
||||
};
|
||||
|
||||
void loadTypes();
|
||||
}, []);
|
||||
|
||||
const selectTemplate = (emailType: string) => {
|
||||
if (currentMailType !== emailType) {
|
||||
setLoaded(true);
|
||||
setCurrentMailType(emailType);
|
||||
}
|
||||
};
|
||||
const selectTemplate = useCallback(
|
||||
(emailType: string) => {
|
||||
if (currentMailType !== emailType) {
|
||||
setCurrentMailType(emailType);
|
||||
}
|
||||
},
|
||||
[currentMailType],
|
||||
);
|
||||
|
||||
const onClick = (e: React.MouseEvent<HTMLElement>) => {
|
||||
const value = (e.target as HTMLElement).getAttribute("value");
|
||||
@ -54,7 +56,12 @@ const MailTemplatesTab: React.FC = () => {
|
||||
<ul className="mail-types">
|
||||
{types.map((x) => {
|
||||
return (
|
||||
<li key={x.mailType} value={x.mailType} onClick={onClick}>
|
||||
<li
|
||||
key={x.mailType}
|
||||
value={x.mailType}
|
||||
onClick={onClick}
|
||||
className={currentMailType === x.mailType ? "selected" : ""}
|
||||
>
|
||||
{x.description}
|
||||
</li>
|
||||
);
|
||||
|
||||
@ -1,129 +1,134 @@
|
||||
import Joi from "joi";
|
||||
import React from "react";
|
||||
import { Navigate } from "react-router-dom";
|
||||
import React, { useEffect } from "react";
|
||||
import { Navigate, useParams } from "react-router-dom";
|
||||
import { toast } from "react-toastify";
|
||||
import Form, { FormState } from "../../../../components/common/Form";
|
||||
import { useForm } from "../../../../components/common/useForm";
|
||||
import { InputType } from "../../../../components/common/Input";
|
||||
import { MakeGeneralIdRef } from "../../../../utils/GeneralIdRef";
|
||||
import withRouter, { RouterProps } from "../../../../utils/withRouter";
|
||||
import roleService from "../serrvices/rolesService";
|
||||
import Loading from "../../../../components/common/Loading";
|
||||
import {
|
||||
renderError,
|
||||
renderButton,
|
||||
renderInput,
|
||||
} from "../../../../components/common/formHelpers";
|
||||
|
||||
interface RolesDetailsProps extends RouterProps {
|
||||
isEditMode : boolean;
|
||||
interface RolesDetailsProps {
|
||||
isEditMode: boolean;
|
||||
}
|
||||
|
||||
interface RolesDetailsState extends FormState {
|
||||
const RolesDetails: React.FC<RolesDetailsProps> = ({ isEditMode }) => {
|
||||
const { domainId, roleId } = useParams<{
|
||||
domainId: string;
|
||||
roleId: string;
|
||||
}>();
|
||||
|
||||
const labelName = "Name";
|
||||
const labelApply = "Save";
|
||||
const labelSave = "Save and close";
|
||||
|
||||
const form = useForm({
|
||||
loaded: false,
|
||||
data: {
|
||||
name: string;
|
||||
};
|
||||
redirect: string;
|
||||
}
|
||||
name: "",
|
||||
},
|
||||
errors: {},
|
||||
redirect: "",
|
||||
});
|
||||
|
||||
class LocRolesDetails extends Form<RolesDetailsProps, any, RolesDetailsState> {
|
||||
state: RolesDetailsState = {
|
||||
loaded: false,
|
||||
data: {
|
||||
name: ""
|
||||
},
|
||||
errors: {},
|
||||
redirect: "",
|
||||
};
|
||||
form.schema = {
|
||||
name: Joi.string().required().max(450).label(labelName),
|
||||
};
|
||||
|
||||
labelName = "Name";
|
||||
const doSubmit = async (buttonName: string) => {
|
||||
try {
|
||||
const { name } = form.state.data;
|
||||
const nameStr = typeof name === "string" ? name : "";
|
||||
|
||||
labelApply = "Save";
|
||||
labelSave = "Save and close";
|
||||
var domainIdGeneralIdRef = MakeGeneralIdRef(BigInt(domainId!));
|
||||
|
||||
|
||||
schema = {
|
||||
name: Joi.string().required().max(450).label(this.labelName),
|
||||
};
|
||||
|
||||
doSubmit = async (buttonName : string) => {
|
||||
try {
|
||||
const { name } = this.state.data;
|
||||
|
||||
const { domainId } = this.props.router.params;
|
||||
var domainIdGeneralIdRef = MakeGeneralIdRef(domainId);
|
||||
|
||||
if (this.isEditMode()) {
|
||||
const { roleId } = this.props.router.params;
|
||||
var generalIdRef = MakeGeneralIdRef(roleId);
|
||||
const response = await roleService.putRole(generalIdRef, name);
|
||||
if (response) {
|
||||
toast.info("Role edited");
|
||||
}
|
||||
} else {
|
||||
const response = await roleService.postRole(domainIdGeneralIdRef, name);
|
||||
if (response) {
|
||||
toast.info("New Role added");
|
||||
}
|
||||
}
|
||||
|
||||
if (buttonName === this.labelSave)
|
||||
this.setState({ redirect: "/domains/edit/" + domainId });
|
||||
if (isEditMode) {
|
||||
var generalIdRef = MakeGeneralIdRef(BigInt(roleId!));
|
||||
const response = await roleService.putRole(generalIdRef, nameStr);
|
||||
if (response) {
|
||||
toast.info("Role edited");
|
||||
}
|
||||
catch(ex: any) {
|
||||
this.handleGeneralError(ex);
|
||||
}
|
||||
};
|
||||
|
||||
isEditMode = () => {
|
||||
const { editMode } = this.props;
|
||||
return editMode;
|
||||
};
|
||||
|
||||
componentDidMount = async () => {
|
||||
const { roleId } = this.props.router.params;
|
||||
|
||||
if (roleId !== undefined) {
|
||||
try {
|
||||
const loadedData = await roleService.getRole(roleId);
|
||||
|
||||
const { data } = this.state;
|
||||
if (loadedData) {
|
||||
data.name = loadedData.name;
|
||||
|
||||
this.setState({ loaded: true, data });
|
||||
}
|
||||
else {
|
||||
this.setState({ loaded: false });
|
||||
}
|
||||
}
|
||||
catch(ex: any) {
|
||||
this.handleGeneralError(ex);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.setState({ loaded : true });
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { loaded, redirect } = this.state;
|
||||
if (redirect !== "") return <Navigate to={redirect} />;
|
||||
|
||||
const isEditMode = this.isEditMode();
|
||||
|
||||
let mode = "Add";
|
||||
if (isEditMode) mode = "Edit";
|
||||
|
||||
return (
|
||||
<Loading loaded={loaded}>
|
||||
<h1>{mode} Role</h1>
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
{this.renderError("_general")}
|
||||
{this.renderInput("name", this.labelName, InputType.text)}
|
||||
|
||||
{isEditMode && this.renderButton(this.labelApply)}
|
||||
{this.renderButton(this.labelSave)}
|
||||
</form>
|
||||
</Loading>
|
||||
} else {
|
||||
const response = await roleService.postRole(
|
||||
domainIdGeneralIdRef,
|
||||
nameStr,
|
||||
);
|
||||
if (response) {
|
||||
toast.info("New Role added");
|
||||
}
|
||||
}
|
||||
|
||||
if (buttonName === labelSave)
|
||||
form.setState({ redirect: "/domains/edit/" + domainId });
|
||||
} catch (ex: any) {
|
||||
form.handleGeneralError(ex);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const RolesDetails = withRouter(LocRolesDetails);
|
||||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||
form.handleSubmit(e, doSubmit);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const loadData = async () => {
|
||||
if (roleId !== undefined) {
|
||||
try {
|
||||
const loadedData = await roleService.getRole(BigInt(roleId));
|
||||
|
||||
if (loadedData) {
|
||||
const newData = { ...form.state.data };
|
||||
newData.name = loadedData.name;
|
||||
|
||||
form.setState({ loaded: true, data: newData });
|
||||
} else {
|
||||
form.setState({ loaded: false });
|
||||
}
|
||||
} catch (ex: any) {
|
||||
form.handleGeneralError(ex);
|
||||
}
|
||||
} else {
|
||||
form.setState({ loaded: true });
|
||||
}
|
||||
};
|
||||
|
||||
loadData();
|
||||
}, [roleId, form]);
|
||||
|
||||
const { loaded, redirect } = form.state;
|
||||
if (redirect) return <Navigate to={redirect} />;
|
||||
|
||||
let mode = "Add";
|
||||
if (isEditMode) mode = "Edit";
|
||||
|
||||
return (
|
||||
<Loading loaded={loaded}>
|
||||
<h1>{mode} Role</h1>
|
||||
<form onSubmit={handleSubmit}>
|
||||
{renderError("_general", form.state.errors)}
|
||||
{renderInput(
|
||||
"name",
|
||||
labelName,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.text,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
|
||||
{isEditMode && renderButton(labelApply, form.state.errors, "apply")}
|
||||
{renderButton(labelSave, form.state.errors, "save")}
|
||||
</form>
|
||||
</Loading>
|
||||
);
|
||||
};
|
||||
export default RolesDetails;
|
||||
|
||||
@ -22,12 +22,14 @@ interface RolesEditorProps {
|
||||
selectedRole?: GetRoleResponse;
|
||||
onSelectRole?: (keyValue: any) => void;
|
||||
onUnselectRole?: () => void;
|
||||
initialRoleId?: string;
|
||||
}
|
||||
|
||||
const RolesEditor: React.FC<RolesEditorProps> = ({
|
||||
selectedRole,
|
||||
onSelectRole,
|
||||
onUnselectRole,
|
||||
initialRoleId,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const [loaded, setLoaded] = useState(false);
|
||||
@ -74,7 +76,19 @@ const RolesEditor: React.FC<RolesEditorProps> = ({
|
||||
};
|
||||
|
||||
void loadInitial();
|
||||
}, [changePage, domainId]);
|
||||
}, [changePage]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
// Auto-select role when initialRoleId is provided
|
||||
useEffect(() => {
|
||||
if (initialRoleId && pagedData.data.length > 0 && onSelectRole) {
|
||||
const roleToSelect = pagedData.data.find(
|
||||
(role) => role.id.toString() === initialRoleId,
|
||||
);
|
||||
if (roleToSelect) {
|
||||
onSelectRole(roleToSelect);
|
||||
}
|
||||
}
|
||||
}, [initialRoleId, pagedData.data, onSelectRole]);
|
||||
|
||||
const onSort = async (nextSortColumn: Column<GetRoleResponse>) => {
|
||||
const { page, pageSize } = pagedData;
|
||||
|
||||
@ -8,7 +8,15 @@ import UserRoleEditor from "./UserRoleEditor";
|
||||
import { GetRoleResponse } from "../serrvices/rolesService";
|
||||
import authentication from "../../../frame/services/authenticationService";
|
||||
|
||||
const SecurityRolesTab: React.FC = () => {
|
||||
interface SecurityRolesTabProps {
|
||||
initialRoleId?: string;
|
||||
initialInnerTab?: string;
|
||||
}
|
||||
|
||||
const SecurityRolesTab: React.FC<SecurityRolesTabProps> = ({
|
||||
initialRoleId,
|
||||
initialInnerTab,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const [selectedRole, setSelectedRole] = useState<GetRoleResponse | undefined>(
|
||||
undefined,
|
||||
@ -49,12 +57,13 @@ const SecurityRolesTab: React.FC = () => {
|
||||
selectedRole={selectedRole}
|
||||
onSelectRole={onSelectRow}
|
||||
onUnselectRole={onUnselectRow}
|
||||
initialRoleId={initialRoleId}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
{selectedRole !== undefined &&
|
||||
(canViewRoleAccess || canViewRoleUsers) && (
|
||||
<HorizontalTabs>{tabs}</HorizontalTabs>
|
||||
<HorizontalTabs initialTab={initialInnerTab}>{tabs}</HorizontalTabs>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -78,7 +78,7 @@ const UserRoleEditor: React.FC<UserRoleEditorProps> = ({ role }) => {
|
||||
};
|
||||
|
||||
void loadInitial();
|
||||
}, [getRoleUsers, role?.id, sortColumn]);
|
||||
}, [getRoleUsers]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
const changePage = async (page: number, pageSize: number) => {
|
||||
await getRoleUsers(page, pageSize, sortColumn, filters);
|
||||
|
||||
@ -94,8 +94,18 @@ const Forms: React.FC = () => {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
changePage(pagedData.page, pagedData.pageSize);
|
||||
}, [changePage, pagedData.page, pagedData.pageSize]);
|
||||
const loadInitial = async () => {
|
||||
const data = await formsService.getForms(1, 10, "name", true, filters);
|
||||
if (data) {
|
||||
setLoaded(true);
|
||||
setPagedData(data);
|
||||
} else {
|
||||
setLoaded(false);
|
||||
}
|
||||
};
|
||||
|
||||
void loadInitial();
|
||||
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
return (
|
||||
<Loading loaded={loaded}>
|
||||
|
||||
@ -1,141 +1,142 @@
|
||||
import Joi from "joi";
|
||||
import React from "react";
|
||||
import { Navigate } from "react-router-dom";
|
||||
import React, { useEffect } from "react";
|
||||
import { Navigate, useParams } from "react-router-dom";
|
||||
import { toast } from "react-toastify";
|
||||
import Form from "../../../components/common/Form";
|
||||
import { useForm } from "../../../components/common/useForm";
|
||||
import { InputType } from "../../../components/common/Input";
|
||||
import { FormState } from "../../../components/common/Form";
|
||||
import withRouter from "../../../utils/withRouter";
|
||||
import { MakeGeneralIdRef } from "../../../utils/GeneralIdRef";
|
||||
import formsService from "./services/formsService";
|
||||
import Loading from "../../../components/common/Loading";
|
||||
// import Tab from "../../../components/common/Tab";
|
||||
// import HorizontalTabs from "../../../components/common/HorizionalTabs";
|
||||
import {
|
||||
renderError,
|
||||
renderButton,
|
||||
renderInput,
|
||||
renderTemplateEditor,
|
||||
} from "../../../components/common/formHelpers";
|
||||
|
||||
interface FormsDetailsState extends FormState {
|
||||
const FormsDetails: React.FC<{ editMode?: boolean }> = ({
|
||||
editMode = false,
|
||||
}) => {
|
||||
const { formId } = useParams<{ formId: string }>();
|
||||
|
||||
const labelName = "Name";
|
||||
const labelDefinition = "Definition";
|
||||
|
||||
const labelApply = "Save";
|
||||
const labelSave = "Save and close";
|
||||
|
||||
const form = useForm({
|
||||
loaded: false,
|
||||
data: {
|
||||
name: string;
|
||||
definition: string;
|
||||
};
|
||||
redirect: string;
|
||||
}
|
||||
name: "",
|
||||
definition: "",
|
||||
},
|
||||
errors: {},
|
||||
redirect: "",
|
||||
});
|
||||
|
||||
class FormsDetails extends Form<any, any, FormsDetailsState> {
|
||||
state: FormsDetailsState = {
|
||||
loaded: false,
|
||||
data: {
|
||||
name: "",
|
||||
definition: "",
|
||||
},
|
||||
errors: {},
|
||||
redirect: "",
|
||||
};
|
||||
form.schema = {
|
||||
name: Joi.string().required().max(450).label(labelName),
|
||||
definition: Joi.string().required().label(labelDefinition),
|
||||
};
|
||||
|
||||
labelName = "Name";
|
||||
labelDefinition = "Definition";
|
||||
|
||||
labelApply = "Save";
|
||||
labelSave = "Save and close";
|
||||
|
||||
schema = {
|
||||
name: Joi.string().required().max(450).label(this.labelName),
|
||||
definition: Joi.string().required().label(this.labelDefinition),
|
||||
};
|
||||
|
||||
doSubmit = async (buttonName : string) => {
|
||||
useEffect(() => {
|
||||
const loadData = async () => {
|
||||
if (formId !== undefined) {
|
||||
try {
|
||||
const { name, definition } = this.state.data;
|
||||
const loadedData = await formsService.getForm(BigInt(formId));
|
||||
|
||||
if (this.isEditMode()) {
|
||||
const { formId } = this.props.router.params;
|
||||
if (loadedData) {
|
||||
const newData = { ...form.state.data };
|
||||
newData.name = loadedData.name;
|
||||
newData.definition = loadedData.definition;
|
||||
|
||||
var generalIdRef = MakeGeneralIdRef(formId);
|
||||
const response = await formsService.putForm(generalIdRef, name, definition);
|
||||
if (response) {
|
||||
toast.info("Form template edited");
|
||||
}
|
||||
} else {
|
||||
const response = await formsService.postForm(name, definition);
|
||||
if (response) {
|
||||
toast.info("New Form Template added");
|
||||
}
|
||||
}
|
||||
|
||||
if (buttonName === this.labelSave)
|
||||
this.setState({ redirect: "/forms" });
|
||||
}
|
||||
catch(ex: any) {
|
||||
this.handleGeneralError(ex);
|
||||
form.setState({ loaded: true, data: newData });
|
||||
} else {
|
||||
form.setState({ loaded: false });
|
||||
}
|
||||
} catch (ex: any) {
|
||||
form.handleGeneralError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (!editMode) form.setState({ loaded: true });
|
||||
};
|
||||
|
||||
isEditMode = () => {
|
||||
const { editMode } = this.props;
|
||||
return editMode;
|
||||
};
|
||||
loadData();
|
||||
}, [formId, editMode]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
componentDidMount = async () => {
|
||||
const { formId } = this.props.router.params;
|
||||
const doSubmit = async (buttonName: string) => {
|
||||
try {
|
||||
const { name, definition } = form.state.data;
|
||||
const nameStr = typeof name === "string" ? name : "";
|
||||
const definitionStr = typeof definition === "string" ? definition : "";
|
||||
|
||||
if (formId !== undefined) {
|
||||
try {
|
||||
const loadedData = await formsService.getForm(formId);
|
||||
|
||||
const { data } = this.state;
|
||||
if (loadedData) {
|
||||
data.name = loadedData.name;
|
||||
data.definition = loadedData.definition;
|
||||
|
||||
this.setState({ loaded: true, data });
|
||||
}
|
||||
else {
|
||||
this.setState({ loaded: false });
|
||||
}
|
||||
}
|
||||
catch(ex: any) {
|
||||
this.handleGeneralError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.isEditMode())
|
||||
this.setState({ loaded: true } );
|
||||
};
|
||||
|
||||
render() {
|
||||
const { loaded, redirect } = this.state;
|
||||
if (redirect !== "") return <Navigate to={redirect} />;
|
||||
|
||||
let mode = "Add";
|
||||
if (this.isEditMode()) mode = "Edit";
|
||||
|
||||
// let tabs : JSX.Element[] = [];
|
||||
|
||||
// tabs.push( <Tab key={1} label="Form Mode">
|
||||
// {this.renderTemplateEditor("definition", this.labelDefinition, true)}
|
||||
// </Tab> );
|
||||
|
||||
// tabs.push( <Tab key={1} label="Wizard Mode">
|
||||
// <>This is Wizard Mode</>
|
||||
// </Tab> );
|
||||
|
||||
return (
|
||||
<Loading loaded={loaded}>
|
||||
<h1>{mode} Form Template</h1>
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
{this.renderError("_general")}
|
||||
{this.renderInput("name", this.labelName, InputType.text)}
|
||||
{/* <HorizontalTabs>
|
||||
{tabs}
|
||||
</HorizontalTabs> */}
|
||||
{this.renderTemplateEditor("form-editor","definition", this.labelDefinition, true)}
|
||||
{this.isEditMode() && this.renderButton(this.labelApply)}
|
||||
{this.renderButton(this.labelSave)}
|
||||
</form>
|
||||
</Loading>
|
||||
if (editMode) {
|
||||
var generalIdRef = MakeGeneralIdRef(BigInt(formId!));
|
||||
const response = await formsService.putForm(
|
||||
generalIdRef,
|
||||
nameStr,
|
||||
definitionStr,
|
||||
);
|
||||
if (response) {
|
||||
toast.info("Form template edited");
|
||||
}
|
||||
} else {
|
||||
const response = await formsService.postForm(nameStr, definitionStr);
|
||||
if (response) {
|
||||
toast.info("New Form Template added");
|
||||
}
|
||||
}
|
||||
|
||||
if (buttonName === "save") form.setState({ redirect: "/forms" });
|
||||
} catch (ex: any) {
|
||||
form.handleGeneralError(ex);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const HOCFormsDetails = withRouter(FormsDetails);
|
||||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||
form.handleSubmit(e, doSubmit);
|
||||
};
|
||||
|
||||
export default HOCFormsDetails;
|
||||
const { loaded, redirect } = form.state;
|
||||
if (redirect) return <Navigate to={redirect} />;
|
||||
|
||||
let mode = "Add";
|
||||
if (editMode) mode = "Edit";
|
||||
|
||||
return (
|
||||
<Loading loaded={loaded}>
|
||||
<h1>{mode} Form Template</h1>
|
||||
<form onSubmit={handleSubmit}>
|
||||
{renderError("_general", form.state.errors)}
|
||||
{renderInput(
|
||||
"name",
|
||||
labelName,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.text,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
{renderTemplateEditor(
|
||||
"form-editor",
|
||||
"definition",
|
||||
labelDefinition,
|
||||
form.state.data,
|
||||
true,
|
||||
form.handleTemplateEditorChange,
|
||||
)}
|
||||
{editMode && renderButton(labelApply, form.state.errors, "apply")}
|
||||
{renderButton(labelSave, form.state.errors, "save")}
|
||||
</form>
|
||||
</Loading>
|
||||
);
|
||||
};
|
||||
|
||||
export default FormsDetails;
|
||||
|
||||
@ -1,177 +1,269 @@
|
||||
import Joi from "joi";
|
||||
import React from "react";
|
||||
import { Navigate } from "react-router-dom";
|
||||
import React, { useEffect } from "react";
|
||||
import { Navigate, useParams } from "react-router-dom";
|
||||
import { toast } from "react-toastify";
|
||||
import Form from "../../../components/common/Form";
|
||||
import { useForm } from "../../../components/common/useForm";
|
||||
import { InputType } from "../../../components/common/Input";
|
||||
import { FormState } from "../../../components/common/Form";
|
||||
import withRouter from "../../../utils/withRouter";
|
||||
import { MakeGeneralIdRef } from "../../../utils/GeneralIdRef";
|
||||
import glossariesService, { Glossary, SystemGlossaries } from "./services/glossaryService";
|
||||
import { GeneralIdRef, MakeGeneralIdRef } from "../../../utils/GeneralIdRef";
|
||||
import glossariesService, {
|
||||
CustomFieldValue,
|
||||
Glossary,
|
||||
SystemGlossaries,
|
||||
} from "./services/glossaryService";
|
||||
import { CustomField } from "../customfields/services/customFieldsService";
|
||||
import Loading from "../../../components/common/Loading";
|
||||
import {
|
||||
renderError,
|
||||
renderButton,
|
||||
renderInput,
|
||||
renderCustomFields,
|
||||
renderCustomFieldsEditor,
|
||||
} from "../../../components/common/formHelpers";
|
||||
|
||||
interface GlossariesState extends FormState {
|
||||
interface GlossariesDetailsProps {
|
||||
editMode?: boolean;
|
||||
}
|
||||
|
||||
const GlossariesDetails: React.FC<GlossariesDetailsProps> = ({
|
||||
editMode = false,
|
||||
}) => {
|
||||
const { glossaryId } = useParams<{ glossaryId: string }>();
|
||||
|
||||
const labelName = "Name";
|
||||
const labelChildCustomFieldDefinition = "Custom field for child entries";
|
||||
|
||||
const labelApply = "Save";
|
||||
const labelSave = "Save and close";
|
||||
|
||||
const form = useForm({
|
||||
loaded: false,
|
||||
data: {
|
||||
id? : bigint,
|
||||
guid? : string,
|
||||
name: string,
|
||||
parent?: Glossary,
|
||||
childCustomFieldDefinition : CustomField[]
|
||||
};
|
||||
redirect: string;
|
||||
}
|
||||
id: undefined,
|
||||
guid: undefined,
|
||||
name: "",
|
||||
parent: undefined,
|
||||
childCustomFieldDefinition: [],
|
||||
},
|
||||
errors: {},
|
||||
redirect: "",
|
||||
});
|
||||
|
||||
class GlossariesDetails extends Form<any, any, GlossariesState> {
|
||||
state: GlossariesState = {
|
||||
loaded: false,
|
||||
data: {
|
||||
id: undefined,
|
||||
guid: undefined,
|
||||
name: "",
|
||||
parent : undefined,
|
||||
childCustomFieldDefinition : []
|
||||
},
|
||||
errors: {},
|
||||
redirect: "",
|
||||
};
|
||||
form.schema = {
|
||||
id: Joi.optional(),
|
||||
guid: Joi.optional(),
|
||||
name: Joi.string().required().max(450).label(labelName),
|
||||
parent: Joi.optional(),
|
||||
childCustomFieldDefinition: Joi.optional().label(
|
||||
labelChildCustomFieldDefinition,
|
||||
),
|
||||
};
|
||||
|
||||
labelName = "Name";
|
||||
labelParent = "Parent"
|
||||
labelChildCustomFieldDefinition = "Custom field for child entries"
|
||||
useEffect(() => {
|
||||
const loadData = async () => {
|
||||
const newData = { ...form.state.data };
|
||||
|
||||
labelApply = "Save";
|
||||
labelSave = "Save and close";
|
||||
|
||||
schema = {
|
||||
id : Joi.optional(),
|
||||
guid : Joi.optional(),
|
||||
name: Joi.string().required().max(450).label(this.labelName),
|
||||
parent: Joi.optional(),
|
||||
childCustomFieldDefinition : Joi.optional().label(this.labelChildCustomFieldDefinition)
|
||||
};
|
||||
|
||||
doSubmit = async (buttonName : string) => {
|
||||
if (editMode) {
|
||||
const generalIdRef = MakeGeneralIdRef(BigInt(glossaryId!));
|
||||
try {
|
||||
const { id, guid, name, parent, childCustomFieldDefinition } = this.state.data;
|
||||
const loadedData =
|
||||
await glossariesService.getGlossaryItem(generalIdRef);
|
||||
if (loadedData) {
|
||||
newData.name = loadedData.name;
|
||||
newData.parent = loadedData.parent;
|
||||
newData.id = loadedData.id;
|
||||
newData.guid = loadedData.guid;
|
||||
newData.childCustomFieldDefinition =
|
||||
loadedData.childCustomFieldDefinition ?? [];
|
||||
|
||||
const customfieldValues = this.CustomFieldValues();
|
||||
const parentGlossary = newData.parent as Glossary | undefined;
|
||||
|
||||
if (this.isEditMode()) {
|
||||
const generalIdRef = MakeGeneralIdRef(id, guid);
|
||||
|
||||
const response = await glossariesService.putGlossaryItem(generalIdRef, parent, name, childCustomFieldDefinition, customfieldValues);
|
||||
if (response) {
|
||||
toast.info("Glossary Item edited");
|
||||
}
|
||||
} else {
|
||||
const generalIdRef = parent ? MakeGeneralIdRef(parent.id, parent.guid) : SystemGlossaries;
|
||||
const response = await glossariesService.postGlossaryItem(generalIdRef, name, childCustomFieldDefinition, customfieldValues);
|
||||
if (response) {
|
||||
toast.info("New Glossary Item added");
|
||||
}
|
||||
}
|
||||
|
||||
const navigateId = parent ? parent.id : "";
|
||||
if (buttonName === this.labelSave)
|
||||
this.setState({ redirect: "/glossaries/" + navigateId });
|
||||
form.setCustomFieldValues(
|
||||
newData,
|
||||
loadedData.customFieldValues,
|
||||
parentGlossary?.childCustomFieldDefinition ?? [],
|
||||
);
|
||||
}
|
||||
} catch (ex: any) {
|
||||
form.handleGeneralError(ex);
|
||||
}
|
||||
catch(ex: any) {
|
||||
this.handleGeneralError(ex);
|
||||
} else {
|
||||
const generalIdRef = MakeGeneralIdRef(BigInt(glossaryId!));
|
||||
try {
|
||||
const loadedData =
|
||||
await glossariesService.getGlossaryItem(generalIdRef);
|
||||
if (loadedData) {
|
||||
newData.parent = loadedData;
|
||||
}
|
||||
} catch (ex: any) {
|
||||
form.handleGeneralError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
form.setState({
|
||||
loaded: true,
|
||||
data: newData,
|
||||
customFields: (newData.parent as Glossary | undefined)
|
||||
?.childCustomFieldDefinition,
|
||||
});
|
||||
};
|
||||
|
||||
isEditMode = () => {
|
||||
const { editMode } = this.props;
|
||||
return editMode;
|
||||
};
|
||||
loadData();
|
||||
}, [glossaryId, editMode]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
componentDidMount = async () => {
|
||||
const { data } = this.state;
|
||||
const handleAdd = (customfield: CustomField) => {
|
||||
const newData = { ...form.state.data };
|
||||
const childDefs =
|
||||
(newData.childCustomFieldDefinition as CustomField[]) ?? [];
|
||||
childDefs.push(customfield);
|
||||
newData.childCustomFieldDefinition = childDefs;
|
||||
|
||||
if (this.isEditMode()) {
|
||||
const { glossaryId } = this.props.router.params;
|
||||
form.setState({ data: newData });
|
||||
};
|
||||
|
||||
const generalIdRef = MakeGeneralIdRef(glossaryId);
|
||||
try {
|
||||
const loadedData = await glossariesService.getGlossaryItem( generalIdRef)
|
||||
if (loadedData) {
|
||||
data.name = loadedData.name;
|
||||
data.parent = loadedData.parent;
|
||||
data.id = loadedData.id;
|
||||
data.guid = loadedData.guid;
|
||||
data.childCustomFieldDefinition = loadedData.childCustomFieldDefinition ?? [];
|
||||
const handleDelete = (fieldToDelete: CustomField) => {
|
||||
const newData = { ...form.state.data };
|
||||
|
||||
this.setCustomFieldValues(data, loadedData.customFieldValues, (data.parent as Glossary)?.childCustomFieldDefinition);
|
||||
}
|
||||
}
|
||||
catch(ex: any) {
|
||||
this.handleGeneralError(ex);
|
||||
}
|
||||
}
|
||||
else{
|
||||
const { glossaryId } = this.props.router.params;
|
||||
|
||||
const generalIdRef = MakeGeneralIdRef(glossaryId);
|
||||
try{
|
||||
const loadedData = await glossariesService.getGlossaryItem( generalIdRef)
|
||||
if (loadedData) {
|
||||
data.parent = loadedData;
|
||||
}
|
||||
}
|
||||
catch(ex: any) {
|
||||
this.handleGeneralError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({ loaded: true, data, customFields : data.parent?.childCustomFieldDefinition });
|
||||
};
|
||||
|
||||
handleAdd = ( customfield : CustomField) => {
|
||||
let { data } = this.state;
|
||||
|
||||
data.childCustomFieldDefinition.push( customfield);
|
||||
|
||||
this.setState({ data });
|
||||
if (fieldToDelete) {
|
||||
const childDefs =
|
||||
(newData.childCustomFieldDefinition as CustomField[]) ?? [];
|
||||
newData.childCustomFieldDefinition = childDefs.filter(
|
||||
(x) => x !== fieldToDelete,
|
||||
);
|
||||
}
|
||||
|
||||
handleDelete = ( fieldToDelete : CustomField ) => {
|
||||
let { data } = this.state;
|
||||
form.setState({ data: newData });
|
||||
};
|
||||
|
||||
if (fieldToDelete){
|
||||
data.childCustomFieldDefinition = data.childCustomFieldDefinition.filter( x => x !== fieldToDelete);
|
||||
}
|
||||
const doSubmit = async (buttonName: string) => {
|
||||
try {
|
||||
const { id, guid, name, parent, childCustomFieldDefinition } =
|
||||
form.state.data;
|
||||
const nameStr = typeof name === "string" ? name : "";
|
||||
const parentGlossary = parent as Glossary | undefined;
|
||||
const childDefs = (childCustomFieldDefinition as CustomField[]) ?? [];
|
||||
const idValue = typeof id === "bigint" ? id : undefined;
|
||||
const guidValue = typeof guid === "string" ? guid : undefined;
|
||||
|
||||
this.setState({ data });
|
||||
}
|
||||
const customfieldValues = form.CustomFieldValues();
|
||||
|
||||
render() {
|
||||
const { loaded, redirect, data } = this.state;
|
||||
if (redirect !== "") return <Navigate to={redirect} />;
|
||||
if (editMode) {
|
||||
const generalIdRef = MakeGeneralIdRef(idValue, guidValue);
|
||||
|
||||
let mode = "Add";
|
||||
const isEditMode = this.isEditMode();
|
||||
if (isEditMode) mode = "Edit";
|
||||
|
||||
return (
|
||||
<Loading loaded={loaded}>
|
||||
<h1>{mode} Glossary Item</h1>
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
{this.renderError("_general")}
|
||||
{this.renderInput("name", this.labelName, InputType.text)}
|
||||
{this.renderCustomFields(data.parent?.childCustomFieldDefinition)}
|
||||
<hr/>
|
||||
{this.renderCustomFieldsEditor("childCustomFieldDefinition", this.labelChildCustomFieldDefinition, data.childCustomFieldDefinition, this.handleAdd, this.handleDelete)}
|
||||
<br/>
|
||||
{isEditMode && this.renderButton(this.labelApply)}
|
||||
{this.renderButton(this.labelSave)}
|
||||
</form>
|
||||
</Loading>
|
||||
const response = await glossariesService.putGlossaryItem(
|
||||
generalIdRef,
|
||||
parentGlossary
|
||||
? MakeGeneralIdRef(parentGlossary.id, parentGlossary.guid)
|
||||
: undefined,
|
||||
nameStr,
|
||||
childDefs,
|
||||
customfieldValues,
|
||||
);
|
||||
if (response) {
|
||||
toast.info("Glossary Item edited");
|
||||
}
|
||||
} else {
|
||||
const generalIdRef = parentGlossary
|
||||
? MakeGeneralIdRef(parentGlossary.id, parentGlossary.guid)
|
||||
: SystemGlossaries;
|
||||
const response = await glossariesService.postGlossaryItem(
|
||||
generalIdRef,
|
||||
nameStr,
|
||||
childDefs,
|
||||
customfieldValues,
|
||||
);
|
||||
if (response) {
|
||||
toast.info("New Glossary Item added");
|
||||
}
|
||||
}
|
||||
|
||||
const navigateId = parentGlossary ? parentGlossary.id.toString() : "";
|
||||
if (buttonName === "save")
|
||||
form.setState({ redirect: "/glossaries/" + navigateId });
|
||||
} catch (ex: any) {
|
||||
form.handleGeneralError(ex);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const HOCGlossariesDetails = withRouter(GlossariesDetails);
|
||||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||
form.handleSubmit(e, doSubmit);
|
||||
};
|
||||
|
||||
export default HOCGlossariesDetails;
|
||||
const { loaded, redirect, data } = form.state;
|
||||
if (redirect) return <Navigate to={redirect} />;
|
||||
|
||||
let mode = "Add";
|
||||
if (editMode) mode = "Edit";
|
||||
|
||||
const parentGlossary = data.parent as Glossary | undefined;
|
||||
const handleCustomFieldChange = (
|
||||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
||||
) => {
|
||||
if (e.target instanceof HTMLTextAreaElement) {
|
||||
form.handleTextAreaChange(e as React.ChangeEvent<HTMLTextAreaElement>);
|
||||
} else {
|
||||
form.handleCustomFieldChange(e as React.ChangeEvent<HTMLInputElement>);
|
||||
}
|
||||
};
|
||||
const getCustomFieldType = (
|
||||
field: CustomFieldValue,
|
||||
customFields: CustomField[],
|
||||
) => {
|
||||
return form.getCustomFieldType(field as any, customFields);
|
||||
};
|
||||
const handleCustomFieldPickerChange = (
|
||||
name: string,
|
||||
value: GeneralIdRef | CustomFieldValue[],
|
||||
) => {
|
||||
if (Array.isArray(value)) {
|
||||
form.handleGlossaryPickerChange(name, value);
|
||||
} else {
|
||||
form.handlePickerChange(name, value as GeneralIdRef);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Loading loaded={loaded}>
|
||||
<h1>{mode} Glossary Item</h1>
|
||||
<form onSubmit={handleSubmit}>
|
||||
{renderError("_general", form.state.errors)}
|
||||
{renderInput(
|
||||
"name",
|
||||
labelName,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.text,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
{renderCustomFields(
|
||||
parentGlossary?.childCustomFieldDefinition,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
handleCustomFieldChange,
|
||||
handleCustomFieldPickerChange,
|
||||
getCustomFieldType,
|
||||
)}
|
||||
<hr />
|
||||
{renderCustomFieldsEditor(
|
||||
"childCustomFieldDefinition",
|
||||
labelChildCustomFieldDefinition,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
(data.childCustomFieldDefinition as CustomField[]) ?? [],
|
||||
handleAdd,
|
||||
handleDelete,
|
||||
)}
|
||||
<br />
|
||||
{editMode && renderButton(labelApply, form.state.errors, "apply")}
|
||||
{renderButton(labelSave, form.state.errors, "save")}
|
||||
</form>
|
||||
</Loading>
|
||||
);
|
||||
};
|
||||
|
||||
export default GlossariesDetails;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { useEffect, useState } 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";
|
||||
@ -29,21 +29,24 @@ const Organisations: React.FC = () => {
|
||||
new Map<string, string>(),
|
||||
);
|
||||
|
||||
const changePage = async (page: number, pageSize: number) => {
|
||||
const data = await organisationsService.getOrganisations(
|
||||
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 organisationsService.getOrganisations(
|
||||
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<ReadOrganisation>) => {
|
||||
const { page, pageSize } = pagedData;
|
||||
@ -96,9 +99,24 @@ const Organisations: React.FC = () => {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const { page, pageSize } = pagedData;
|
||||
changePage(page, pageSize);
|
||||
});
|
||||
const loadInitial = async () => {
|
||||
const data = await organisationsService.getOrganisations(
|
||||
1,
|
||||
10,
|
||||
"name",
|
||||
true,
|
||||
filters,
|
||||
);
|
||||
if (data) {
|
||||
setLoaded(true);
|
||||
setPagedData(data);
|
||||
} else {
|
||||
setLoaded(false);
|
||||
}
|
||||
};
|
||||
|
||||
void loadInitial();
|
||||
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
return (
|
||||
<Loading loaded={loaded}>
|
||||
|
||||
@ -1,140 +1,175 @@
|
||||
import Joi from "joi";
|
||||
import React from "react";
|
||||
import { Navigate } from "react-router-dom";
|
||||
import React, { useEffect } from "react";
|
||||
import { Navigate, useParams } from "react-router-dom";
|
||||
import { toast } from "react-toastify";
|
||||
import Form from "../../../components/common/Form";
|
||||
import { useForm } from "../../../components/common/useForm";
|
||||
import { InputType } from "../../../components/common/Input";
|
||||
import { FormState } from "../../../components/common/Form";
|
||||
import withRouter from "../../../utils/withRouter";
|
||||
import { MakeGeneralIdRef } from "../../../utils/GeneralIdRef";
|
||||
import Option from "../../../components/common/option";
|
||||
import organisationsService from "./services/organisationsService";
|
||||
import Loading from "../../../components/common/Loading";
|
||||
import {
|
||||
renderError,
|
||||
renderButton,
|
||||
renderInput,
|
||||
renderSelect,
|
||||
} from "../../../components/common/formHelpers";
|
||||
|
||||
interface OrganisationsDetailsState extends FormState {
|
||||
const OrganisationsDetails: React.FC<{ editMode?: boolean }> = ({
|
||||
editMode = false,
|
||||
}) => {
|
||||
const { organisationId } = useParams<{ organisationId: string }>();
|
||||
|
||||
const labelName = "Name";
|
||||
const labelAddress = "Address";
|
||||
const labelStatus = "Status";
|
||||
|
||||
const labelApply = "Save";
|
||||
const labelSave = "Save and close";
|
||||
|
||||
const organisationStatusOptions: Option[] = [
|
||||
{ _id: "Active", name: "Active" },
|
||||
{ _id: "Pending", name: "Pending" },
|
||||
{ _id: "Blocked", name: "Blocked" },
|
||||
];
|
||||
|
||||
const form = useForm({
|
||||
loaded: false,
|
||||
data: {
|
||||
name: string;
|
||||
address: string;
|
||||
status: string;
|
||||
};
|
||||
redirect: string;
|
||||
organisationStatusOptions: Option[];
|
||||
}
|
||||
name: "",
|
||||
address: "",
|
||||
status: "Active",
|
||||
},
|
||||
errors: {},
|
||||
redirect: "",
|
||||
});
|
||||
|
||||
class OrganisationsDetails extends Form<any, any, OrganisationsDetailsState> {
|
||||
state: OrganisationsDetailsState = {
|
||||
loaded: false,
|
||||
data: {
|
||||
name: "",
|
||||
address: "",
|
||||
status: "Active"
|
||||
},
|
||||
errors: {},
|
||||
redirect: "",
|
||||
organisationStatusOptions: [
|
||||
{ _id: "Active", name: "Active" },
|
||||
{ _id: "Pending", name: "Pending" },
|
||||
{ _id: "Blocked", name: "Blocked" },
|
||||
]
|
||||
};
|
||||
form.schema = {
|
||||
name: Joi.string().required().max(450).label(labelName),
|
||||
address: Joi.string().required().max(450).label(labelAddress),
|
||||
status: Joi.string().required().max(450).label(labelStatus),
|
||||
};
|
||||
|
||||
labelName = "Name";
|
||||
labelAddress = "Address";
|
||||
labelStatus = "Status";
|
||||
|
||||
labelApply = "Save";
|
||||
labelSave = "Save and close";
|
||||
|
||||
schema = {
|
||||
name: Joi.string().required().max(450).label(this.labelName),
|
||||
address:Joi.string().required().max(450).label(this.labelAddress),
|
||||
status:Joi.string().required().max(450).label(this.labelAddress)
|
||||
};
|
||||
|
||||
doSubmit = async (buttonName : string) => {
|
||||
useEffect(() => {
|
||||
const loadData = async () => {
|
||||
if (organisationId !== undefined) {
|
||||
try {
|
||||
const { name, address, status } = this.state.data;
|
||||
const loadedData = await organisationsService.getOrganisation(
|
||||
BigInt(organisationId),
|
||||
);
|
||||
|
||||
if (this.isEditMode()) {
|
||||
const { organisationId } = this.props.router.params;
|
||||
if (loadedData) {
|
||||
const newData = { ...form.state.data };
|
||||
newData.name = loadedData.name;
|
||||
newData.address = loadedData.address;
|
||||
newData.status = loadedData.status;
|
||||
|
||||
var generalIdRef = MakeGeneralIdRef(organisationId);
|
||||
const response = await organisationsService.putOrganisation(generalIdRef, name, address, status);
|
||||
if (response) {
|
||||
toast.info("Organisation edited");
|
||||
}
|
||||
} else {
|
||||
const response = await organisationsService.postOrganisation(name, address, status);
|
||||
if (response) {
|
||||
toast.info("New Organisation added");
|
||||
}
|
||||
}
|
||||
|
||||
if (buttonName === this.labelSave)
|
||||
this.setState({ redirect: "/organisations" });
|
||||
}
|
||||
catch(ex: any) {
|
||||
this.handleGeneralError(ex);
|
||||
form.setState({ loaded: true, data: newData });
|
||||
} else {
|
||||
form.setState({ loaded: false });
|
||||
}
|
||||
} catch (ex: any) {
|
||||
form.handleGeneralError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (!editMode) form.setState({ loaded: true });
|
||||
};
|
||||
|
||||
isEditMode = () => {
|
||||
const { editMode } = this.props;
|
||||
return editMode;
|
||||
};
|
||||
loadData();
|
||||
}, [organisationId, editMode]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
componentDidMount = async () => {
|
||||
const { organisationId } = this.props.router.params;
|
||||
const doSubmit = async (buttonName: string) => {
|
||||
try {
|
||||
const { name, address, status } = form.state.data;
|
||||
const nameStr = typeof name === "string" ? name : "";
|
||||
const addressStr = typeof address === "string" ? address : "";
|
||||
const statusStr = typeof status === "string" ? status : "";
|
||||
|
||||
if (organisationId !== undefined) {
|
||||
try
|
||||
{
|
||||
const loadedData = await organisationsService.getOrganisation(organisationId);
|
||||
|
||||
const { data } = this.state;
|
||||
if (loadedData) {
|
||||
data.name = loadedData.name;
|
||||
data.address = loadedData.address;
|
||||
data.status = loadedData.status;
|
||||
|
||||
this.setState({ loaded: true, data });
|
||||
}
|
||||
else {
|
||||
this.setState({ loaded: false });
|
||||
}
|
||||
}
|
||||
catch(ex: any) {
|
||||
this.handleGeneralError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.isEditMode())
|
||||
this.setState({loaded:true});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { loaded, redirect, organisationStatusOptions } = this.state;
|
||||
if (redirect !== "") return <Navigate to={redirect} />;
|
||||
|
||||
let mode = "Add";
|
||||
if (this.isEditMode()) mode = "Edit";
|
||||
|
||||
return (
|
||||
<Loading loaded={loaded}>
|
||||
<h1>{mode} Organisation</h1>
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
{this.renderError("_general")}
|
||||
{this.renderInput("name", this.labelName, InputType.text)}
|
||||
{this.renderInput("address", this.labelAddress, InputType.text)}
|
||||
{this.renderSelect("status", this.labelStatus, organisationStatusOptions)}
|
||||
{this.isEditMode() && this.renderButton(this.labelApply)}
|
||||
{this.renderButton(this.labelSave)}
|
||||
</form>
|
||||
</Loading>
|
||||
if (editMode) {
|
||||
var generalIdRef = MakeGeneralIdRef(BigInt(organisationId!));
|
||||
const response = await organisationsService.putOrganisation(
|
||||
generalIdRef,
|
||||
nameStr,
|
||||
addressStr,
|
||||
statusStr,
|
||||
);
|
||||
if (response) {
|
||||
toast.info("Organisation edited");
|
||||
}
|
||||
} else {
|
||||
const response = await organisationsService.postOrganisation(
|
||||
nameStr,
|
||||
addressStr,
|
||||
statusStr,
|
||||
);
|
||||
if (response) {
|
||||
toast.info("New Organisation added");
|
||||
}
|
||||
}
|
||||
|
||||
if (buttonName === "save") form.setState({ redirect: "/organisations" });
|
||||
} catch (ex: any) {
|
||||
form.handleGeneralError(ex);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const HOCOrganisationsDetails = withRouter(OrganisationsDetails);
|
||||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||
form.handleSubmit(e, doSubmit);
|
||||
};
|
||||
|
||||
export default HOCOrganisationsDetails;
|
||||
const { loaded, redirect } = form.state;
|
||||
if (redirect) return <Navigate to={redirect} />;
|
||||
|
||||
let mode = "Add";
|
||||
if (editMode) mode = "Edit";
|
||||
|
||||
return (
|
||||
<Loading loaded={loaded}>
|
||||
<h1>{mode} Organisation</h1>
|
||||
<form onSubmit={handleSubmit}>
|
||||
{renderError("_general", form.state.errors)}
|
||||
{renderInput(
|
||||
"name",
|
||||
labelName,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.text,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
{renderInput(
|
||||
"address",
|
||||
labelAddress,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.text,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
{renderSelect(
|
||||
"status",
|
||||
labelStatus,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
organisationStatusOptions,
|
||||
form.handleSelectChange,
|
||||
)}
|
||||
{editMode && renderButton(labelApply, form.state.errors, "apply")}
|
||||
{renderButton(labelSave, form.state.errors, "save")}
|
||||
</form>
|
||||
</Loading>
|
||||
);
|
||||
};
|
||||
|
||||
export default OrganisationsDetails;
|
||||
|
||||
@ -1,152 +1,224 @@
|
||||
import Joi from "joi";
|
||||
import React from "react";
|
||||
import { Navigate } from "react-router-dom";
|
||||
import React, { useEffect } from "react";
|
||||
import { Navigate, useParams } from "react-router-dom";
|
||||
import { toast } from "react-toastify";
|
||||
import Form from "../../../components/common/Form";
|
||||
import { useForm } from "../../../components/common/useForm";
|
||||
import { InputType } from "../../../components/common/Input";
|
||||
import { FormState } from "../../../components/common/Form";
|
||||
import {
|
||||
renderInput,
|
||||
renderButton,
|
||||
renderError,
|
||||
renderSelect,
|
||||
renderInputNumber,
|
||||
} from "../../../components/common/formHelpers";
|
||||
import sequenceService from "./services/sequenceService";
|
||||
import Option from "../../../components/common/option";
|
||||
import withRouter from "../../../utils/withRouter";
|
||||
import { MakeGeneralIdRef } from "../../../utils/GeneralIdRef";
|
||||
import Loading from "../../../components/common/Loading";
|
||||
|
||||
interface SequenceDetailsState extends FormState {
|
||||
interface SequenceDetailsProps {
|
||||
editMode?: boolean;
|
||||
}
|
||||
|
||||
const SequenceDetails: React.FC<SequenceDetailsProps> = ({
|
||||
editMode = false,
|
||||
}) => {
|
||||
const { sequenceId } = useParams<{ sequenceId: string }>();
|
||||
|
||||
const labelName = "Name";
|
||||
const labelSeed = "Seed";
|
||||
const labelIncrement = "Increment";
|
||||
const labelPattern = "Pattern";
|
||||
const labelRolloverType = "Rollover Type";
|
||||
|
||||
const labelApply = "Save";
|
||||
const labelSave = "Save and close";
|
||||
|
||||
const form = useForm({
|
||||
loaded: false,
|
||||
data: {
|
||||
name: string;
|
||||
seed: number;
|
||||
increment: number;
|
||||
pattern: string;
|
||||
rolloverType: string;
|
||||
};
|
||||
redirect: string;
|
||||
}
|
||||
name: "",
|
||||
seed: 1,
|
||||
increment: 1,
|
||||
pattern: "[0]",
|
||||
rolloverType: "Continuous",
|
||||
},
|
||||
errors: {},
|
||||
redirect: "",
|
||||
});
|
||||
|
||||
class SequenceDetails extends Form<any, any, SequenceDetailsState> {
|
||||
state: SequenceDetailsState = {
|
||||
loaded : false,
|
||||
data: {
|
||||
name: "",
|
||||
seed: 1,
|
||||
increment: 1,
|
||||
pattern: "[0]",
|
||||
rolloverType: "Continuous",
|
||||
},
|
||||
errors: {},
|
||||
redirect: "",
|
||||
};
|
||||
form.schema = {
|
||||
name: Joi.string().required().max(450).label(labelName),
|
||||
seed: Joi.number().required().label(labelSeed),
|
||||
increment: Joi.number().required().label(labelIncrement),
|
||||
pattern: Joi.string().required().label(labelPattern),
|
||||
rolloverType: Joi.string().required().label(labelRolloverType),
|
||||
};
|
||||
|
||||
labelName = "Name";
|
||||
labelSeed = "Seed";
|
||||
labelIncrement = "Increment";
|
||||
labelPattern = "Pattern";
|
||||
labelRolloverType = "Rollover Type";
|
||||
|
||||
labelApply = "Save";
|
||||
labelSave = "Save and close";
|
||||
|
||||
schema = {
|
||||
name: Joi.string().required().max(450).label(this.labelName),
|
||||
seed: Joi.number().required().label(this.labelSeed),
|
||||
increment: Joi.number().required().label(this.labelIncrement),
|
||||
pattern: Joi.string().required().label(this.labelPattern),
|
||||
rolloverType: Joi.string().required().label(this.labelRolloverType),
|
||||
};
|
||||
|
||||
doSubmit = async (buttonName : string) => {
|
||||
useEffect(() => {
|
||||
const loadData = async () => {
|
||||
if (sequenceId !== undefined) {
|
||||
try {
|
||||
const { name, seed, increment, pattern, rolloverType } = this.state.data;
|
||||
|
||||
if (this.isEditMode()) {
|
||||
const { sequenceId } = this.props.router.params;
|
||||
|
||||
var generalIdRef = MakeGeneralIdRef(sequenceId);
|
||||
const response = await sequenceService.putSequence(generalIdRef, name, seed, increment, pattern, rolloverType);
|
||||
if (response) {
|
||||
toast.info("Sequence edited");
|
||||
}
|
||||
} else {
|
||||
const response = await sequenceService.postSequence(name, seed, increment, pattern, rolloverType);
|
||||
if (response) {
|
||||
toast.info("New sequence added");
|
||||
}
|
||||
}
|
||||
|
||||
if (buttonName === this.labelSave)
|
||||
this.setState({ redirect: "/sequence" });
|
||||
}
|
||||
catch(ex: any) {
|
||||
this.handleGeneralError(ex);
|
||||
const loadedData = await sequenceService.getSequence(
|
||||
BigInt(sequenceId),
|
||||
);
|
||||
if (loadedData) {
|
||||
const newData = { ...form.state.data };
|
||||
newData.increment = loadedData.increment;
|
||||
newData.name = loadedData.name;
|
||||
newData.pattern = loadedData.pattern;
|
||||
newData.rolloverType = loadedData.rolloverType;
|
||||
newData.seed = loadedData.seed;
|
||||
form.setState({ loaded: true, data: newData });
|
||||
} else {
|
||||
form.setState({ loaded: false });
|
||||
}
|
||||
} catch (ex: any) {
|
||||
form.handleGeneralError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (!editMode) {
|
||||
form.setState({ loaded: true });
|
||||
}
|
||||
};
|
||||
|
||||
isEditMode = () => {
|
||||
const { editMode } = this.props;
|
||||
return editMode;
|
||||
};
|
||||
loadData();
|
||||
}, [sequenceId, editMode]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
componentDidMount = async () => {
|
||||
const { sequenceId } = this.props.router.params;
|
||||
const doSubmit = async (buttonName: string) => {
|
||||
try {
|
||||
const { name, seed, increment, pattern, rolloverType } = form.state.data;
|
||||
const nameStr = typeof name === "string" ? name : "";
|
||||
const patternStr = typeof pattern === "string" ? pattern : "";
|
||||
const rolloverTypeStr =
|
||||
typeof rolloverType === "string" ? rolloverType : "";
|
||||
const seedValue = typeof seed === "number" ? seed : Number(seed);
|
||||
const incrementValue =
|
||||
typeof increment === "number" ? increment : Number(increment);
|
||||
|
||||
if (sequenceId !== undefined) {
|
||||
try {
|
||||
const loadedData = await sequenceService.getSequence(sequenceId);
|
||||
if (loadedData) {
|
||||
const { data } = this.state;
|
||||
|
||||
data.increment = loadedData.increment;
|
||||
data.name = loadedData.name;
|
||||
data.pattern = loadedData.pattern;
|
||||
data.rolloverType = loadedData.rolloverType;
|
||||
data.seed = loadedData.seed;
|
||||
|
||||
this.setState({ loaded: true, data });
|
||||
}
|
||||
else {
|
||||
this.setState({ loaded: false });
|
||||
}
|
||||
}
|
||||
catch(ex: any) {
|
||||
this.handleGeneralError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.isEditMode())
|
||||
this.setState({ loaded: true } );
|
||||
};
|
||||
|
||||
render() {
|
||||
const { loaded, redirect } = this.state;
|
||||
if (redirect !== "") return <Navigate to={redirect} />;
|
||||
|
||||
const rolloverOptions: Option[] = [
|
||||
{ _id: "Continuous", name: "Continuous" },
|
||||
{ _id: "Day", name: "Day" },
|
||||
{ _id: "Month", name: "Month" },
|
||||
{ _id: "Year", name: "Year" },
|
||||
];
|
||||
|
||||
let mode = "Add";
|
||||
if (this.isEditMode()) mode = "Edit";
|
||||
|
||||
return (
|
||||
<Loading loaded={loaded}>
|
||||
<h1>{mode} Sequence</h1>
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
{this.renderError("_general")}
|
||||
{this.renderInput("name", this.labelName, InputType.text)}
|
||||
{this.renderInput("seed", this.labelSeed, InputType.text)}
|
||||
{this.renderInput("increment", this.labelIncrement)}
|
||||
{this.renderInput("pattern", this.labelPattern)}
|
||||
{this.renderSelect("rolloverType", this.labelRolloverType, rolloverOptions)}
|
||||
{this.isEditMode() && this.renderButton(this.labelApply)}
|
||||
{this.renderButton(this.labelSave)}
|
||||
</form>
|
||||
</Loading>
|
||||
if (editMode) {
|
||||
const generalIdRef = MakeGeneralIdRef(
|
||||
sequenceId ? BigInt(sequenceId) : undefined,
|
||||
);
|
||||
const response = await sequenceService.putSequence(
|
||||
generalIdRef,
|
||||
nameStr,
|
||||
seedValue,
|
||||
incrementValue,
|
||||
patternStr,
|
||||
rolloverTypeStr,
|
||||
);
|
||||
if (response) {
|
||||
toast.info("Sequence edited");
|
||||
}
|
||||
} else {
|
||||
const response = await sequenceService.postSequence(
|
||||
nameStr,
|
||||
seedValue,
|
||||
incrementValue,
|
||||
patternStr,
|
||||
rolloverTypeStr,
|
||||
);
|
||||
if (response) {
|
||||
toast.info("New sequence added");
|
||||
}
|
||||
}
|
||||
|
||||
if (buttonName === "save") {
|
||||
form.setState({ redirect: "/sequence" });
|
||||
}
|
||||
} catch (ex: any) {
|
||||
form.handleGeneralError(ex);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const HOCSequenceDetails = withRouter(SequenceDetails);
|
||||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||
form.handleSubmit(e, doSubmit);
|
||||
};
|
||||
|
||||
export default HOCSequenceDetails;
|
||||
const { loaded, redirect } = form.state;
|
||||
if (redirect) return <Navigate to={redirect} />;
|
||||
|
||||
const rolloverOptions: Option[] = [
|
||||
{ _id: "Continuous", name: "Continuous" },
|
||||
{ _id: "Day", name: "Day" },
|
||||
{ _id: "Month", name: "Month" },
|
||||
{ _id: "Year", name: "Year" },
|
||||
];
|
||||
|
||||
const mode = editMode ? "Edit" : "Add";
|
||||
|
||||
return (
|
||||
<Loading loaded={loaded}>
|
||||
<h1>{mode} Sequence</h1>
|
||||
<form onSubmit={handleSubmit}>
|
||||
{renderError("_general", form.state.errors)}
|
||||
{renderInput(
|
||||
"name",
|
||||
labelName,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.text,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
{renderInputNumber(
|
||||
"seed",
|
||||
labelSeed,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
false,
|
||||
"",
|
||||
undefined,
|
||||
undefined,
|
||||
1,
|
||||
form.handleChange,
|
||||
)}
|
||||
{renderInputNumber(
|
||||
"increment",
|
||||
labelIncrement,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
false,
|
||||
"",
|
||||
undefined,
|
||||
undefined,
|
||||
1,
|
||||
form.handleChange,
|
||||
)}
|
||||
{renderInput(
|
||||
"pattern",
|
||||
labelPattern,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.text,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
{renderSelect(
|
||||
"rolloverType",
|
||||
labelRolloverType,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
rolloverOptions,
|
||||
form.handleSelectChange,
|
||||
)}
|
||||
{editMode && renderButton(labelApply, form.state.errors, "save")}
|
||||
{renderButton(labelSave, form.state.errors, "save")}
|
||||
</form>
|
||||
</Loading>
|
||||
);
|
||||
};
|
||||
|
||||
export default SequenceDetails;
|
||||
|
||||
@ -93,8 +93,24 @@ const Sequence: React.FC = () => {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
changePage(pagedData.page, pagedData.pageSize);
|
||||
}, [changePage, pagedData.page, pagedData.pageSize]);
|
||||
const loadInitial = async () => {
|
||||
const data = await sequenceService.getSequences(
|
||||
1,
|
||||
10,
|
||||
"name",
|
||||
true,
|
||||
filters,
|
||||
);
|
||||
if (data) {
|
||||
setLoaded(true);
|
||||
setPagedData(data);
|
||||
} else {
|
||||
setLoaded(false);
|
||||
}
|
||||
};
|
||||
|
||||
void loadInitial();
|
||||
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
return (
|
||||
<Loading loaded={loaded}>
|
||||
|
||||
@ -1,143 +1,186 @@
|
||||
import Joi from "joi";
|
||||
import React from "react";
|
||||
import { Navigate } from "react-router-dom";
|
||||
import React, { useEffect } from "react";
|
||||
import { Navigate, useParams } from "react-router-dom";
|
||||
import { toast } from "react-toastify";
|
||||
import Form from "../../../components/common/Form";
|
||||
import { useForm } from "../../../components/common/useForm";
|
||||
import { InputType } from "../../../components/common/Input";
|
||||
import { FormState } from "../../../components/common/Form";
|
||||
import withRouter from "../../../utils/withRouter";
|
||||
import {
|
||||
renderInput,
|
||||
renderButton,
|
||||
renderError,
|
||||
renderSelect,
|
||||
} from "../../../components/common/formHelpers";
|
||||
import { MakeGeneralIdRef } from "../../../utils/GeneralIdRef";
|
||||
import Option from "../../../components/common/option";
|
||||
import siteService from "./services/sitessService";
|
||||
import Loading from "../../../components/common/Loading";
|
||||
|
||||
interface SiteDetailsState extends FormState {
|
||||
interface SiteDetailsProps {
|
||||
editMode?: boolean;
|
||||
}
|
||||
|
||||
const SiteDetails: React.FC<SiteDetailsProps> = ({ editMode = false }) => {
|
||||
const { organisationId, siteId } = useParams<{
|
||||
organisationId: string;
|
||||
siteId?: string;
|
||||
}>();
|
||||
|
||||
const labelName = "Name";
|
||||
const labelAddress = "Address";
|
||||
const labelStatus = "Status";
|
||||
|
||||
const labelApply = "Save";
|
||||
const labelSave = "Save and close";
|
||||
|
||||
const form = useForm({
|
||||
loaded: false,
|
||||
data: {
|
||||
name: string;
|
||||
address: string;
|
||||
status: string;
|
||||
};
|
||||
redirect: string;
|
||||
organisationStatusOptions: Option[];
|
||||
}
|
||||
name: "",
|
||||
address: "",
|
||||
status: "Active",
|
||||
},
|
||||
errors: {},
|
||||
redirect: "",
|
||||
});
|
||||
|
||||
class LocSiteDetails extends Form<any, any, SiteDetailsState> {
|
||||
state: SiteDetailsState = {
|
||||
loaded : false,
|
||||
data: {
|
||||
name: "",
|
||||
address: "",
|
||||
status: "Active"
|
||||
},
|
||||
errors: {},
|
||||
redirect: "",
|
||||
organisationStatusOptions: [
|
||||
{ _id: "Active", name: "Active" },
|
||||
{ _id: "Pending", name: "Pending" },
|
||||
{ _id: "Blocked", name: "Blocked" },
|
||||
]
|
||||
};
|
||||
form.schema = {
|
||||
name: Joi.string().required().max(450).label(labelName),
|
||||
address: Joi.string().required().max(450).label(labelAddress),
|
||||
status: Joi.string().required().max(450).label(labelStatus),
|
||||
};
|
||||
|
||||
labelName = "Name";
|
||||
labelAddress = "Address";
|
||||
labelStatus = "Status";
|
||||
|
||||
labelApply = "Save";
|
||||
labelSave = "Save and close";
|
||||
|
||||
schema = {
|
||||
name: Joi.string().required().max(450).label(this.labelName),
|
||||
address:Joi.string().required().max(450).label(this.labelAddress),
|
||||
status:Joi.string().required().max(450).label(this.labelAddress)
|
||||
};
|
||||
|
||||
doSubmit = async (buttonName : string) => {
|
||||
useEffect(() => {
|
||||
const loadData = async () => {
|
||||
if (siteId !== undefined) {
|
||||
try {
|
||||
const { name, address, status } = this.state.data;
|
||||
|
||||
const { organisationId } = this.props.router.params;
|
||||
var organisationGeneralIdRef = MakeGeneralIdRef(organisationId);
|
||||
|
||||
if (this.isEditMode()) {
|
||||
const { siteId } = this.props.router.params;
|
||||
var siteGeneralIdRef = MakeGeneralIdRef(siteId);
|
||||
|
||||
const resposne = await siteService.putSite(siteGeneralIdRef, name, address, status, organisationGeneralIdRef);
|
||||
if (resposne) {
|
||||
toast.info("Site edited");
|
||||
}
|
||||
} else {
|
||||
const response = await siteService.postSite(name, address, status, organisationGeneralIdRef);
|
||||
if (response) {
|
||||
toast.info("New site added");
|
||||
}
|
||||
}
|
||||
|
||||
if (buttonName === this.labelSave)
|
||||
this.setState({ redirect: "/site/" + organisationId });
|
||||
}
|
||||
catch(ex: any) {
|
||||
this.handleGeneralError(ex);
|
||||
const loadedData = await siteService.getSite(BigInt(siteId));
|
||||
if (loadedData) {
|
||||
const newData = { ...form.state.data };
|
||||
newData.name = loadedData.name;
|
||||
newData.address = loadedData.address;
|
||||
newData.status = loadedData.status;
|
||||
form.setState({ loaded: true, data: newData });
|
||||
} else {
|
||||
form.setState({ loaded: false });
|
||||
}
|
||||
} catch (ex: any) {
|
||||
form.handleGeneralError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (!editMode) {
|
||||
form.setState({ loaded: true });
|
||||
}
|
||||
};
|
||||
|
||||
isEditMode = () => {
|
||||
const { editMode } = this.props;
|
||||
return editMode;
|
||||
};
|
||||
loadData();
|
||||
}, [siteId, editMode]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
componentDidMount = async () => {
|
||||
const { siteId } = this.props.router.params;
|
||||
const doSubmit = async (buttonName: string) => {
|
||||
try {
|
||||
const { name, address, status } = form.state.data;
|
||||
const nameStr = typeof name === "string" ? name : "";
|
||||
const addressStr = typeof address === "string" ? address : "";
|
||||
const statusStr = typeof status === "string" ? status : "";
|
||||
const organisationGeneralIdRef = MakeGeneralIdRef(
|
||||
organisationId ? BigInt(organisationId) : undefined,
|
||||
);
|
||||
|
||||
if (siteId !== undefined) {
|
||||
try
|
||||
{
|
||||
const loadedData = await siteService.getSite(siteId);
|
||||
|
||||
const { data } = this.state;
|
||||
if (loadedData) {
|
||||
data.name = loadedData.name;
|
||||
data.address = loadedData.address;
|
||||
data.status = loadedData.status;
|
||||
|
||||
this.setState({ loaded: true, data });
|
||||
}
|
||||
else {
|
||||
this.setState({ loaded: false });
|
||||
}
|
||||
}
|
||||
catch(ex: any) {
|
||||
this.handleGeneralError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.isEditMode())
|
||||
this.setState({loaded:true});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { loaded, redirect, organisationStatusOptions } = this.state;
|
||||
if (redirect !== "") return <Navigate to={redirect} />;
|
||||
|
||||
let mode = "Add";
|
||||
if (this.isEditMode()) mode = "Edit";
|
||||
|
||||
return (
|
||||
<Loading loaded={loaded}>
|
||||
<h1>{mode} Site</h1>
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
{this.renderError("_general")}
|
||||
{this.renderInput("name", this.labelName, InputType.text)}
|
||||
{this.renderInput("address", this.labelAddress, InputType.text)}
|
||||
{this.renderSelect("status", this.labelStatus, organisationStatusOptions)}
|
||||
{this.isEditMode() && this.renderButton(this.labelApply)}
|
||||
{this.renderButton(this.labelSave)}
|
||||
</form>
|
||||
</Loading>
|
||||
if (editMode) {
|
||||
const siteGeneralIdRef = MakeGeneralIdRef(
|
||||
siteId ? BigInt(siteId) : undefined,
|
||||
);
|
||||
}
|
||||
}
|
||||
const response = await siteService.putSite(
|
||||
siteGeneralIdRef,
|
||||
nameStr,
|
||||
addressStr,
|
||||
statusStr,
|
||||
organisationGeneralIdRef,
|
||||
);
|
||||
if (response) {
|
||||
toast.info("Site edited");
|
||||
}
|
||||
} else {
|
||||
const response = await siteService.postSite(
|
||||
nameStr,
|
||||
addressStr,
|
||||
statusStr,
|
||||
organisationGeneralIdRef,
|
||||
);
|
||||
if (response) {
|
||||
toast.info("New site added");
|
||||
}
|
||||
}
|
||||
|
||||
const SiteDetails = withRouter(LocSiteDetails);
|
||||
if (buttonName === "save") {
|
||||
form.setState({ redirect: "/site/" + organisationId });
|
||||
}
|
||||
} catch (ex: any) {
|
||||
form.handleGeneralError(ex);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||
form.handleSubmit(e, doSubmit);
|
||||
};
|
||||
|
||||
const { loaded, redirect } = form.state;
|
||||
if (redirect) return <Navigate to={redirect} />;
|
||||
|
||||
const organisationStatusOptions: Option[] = [
|
||||
{ _id: "Active", name: "Active" },
|
||||
{ _id: "Pending", name: "Pending" },
|
||||
{ _id: "Blocked", name: "Blocked" },
|
||||
];
|
||||
|
||||
const mode = editMode ? "Edit" : "Add";
|
||||
|
||||
return (
|
||||
<Loading loaded={loaded}>
|
||||
<h1>{mode} Site</h1>
|
||||
<form onSubmit={handleSubmit}>
|
||||
{renderError("_general", form.state.errors)}
|
||||
{renderInput(
|
||||
"name",
|
||||
labelName,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.text,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
{renderInput(
|
||||
"address",
|
||||
labelAddress,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.text,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
{renderSelect(
|
||||
"status",
|
||||
labelStatus,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
organisationStatusOptions,
|
||||
form.handleSelectChange,
|
||||
)}
|
||||
{editMode && renderButton(labelApply, form.state.errors, "save")}
|
||||
{renderButton(labelSave, form.state.errors, "save")}
|
||||
</form>
|
||||
</Loading>
|
||||
);
|
||||
};
|
||||
|
||||
export default SiteDetails;
|
||||
|
||||
@ -71,8 +71,28 @@ const Sites: React.FC = () => {
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
void changePage(initialPagedData.page, initialPagedData.pageSize);
|
||||
}, [changePage, organisationId]);
|
||||
const loadInitial = async () => {
|
||||
const nextFilters = updateFiltersWithOrganisationId(
|
||||
new Map<string, string>(),
|
||||
);
|
||||
const pagedDataResult = await siteService.getSites(
|
||||
initialPagedData.page,
|
||||
initialPagedData.pageSize,
|
||||
"name",
|
||||
true,
|
||||
nextFilters,
|
||||
);
|
||||
if (pagedDataResult) {
|
||||
setLoaded(true);
|
||||
setFilters(nextFilters);
|
||||
setPagedData(pagedDataResult);
|
||||
} else {
|
||||
setLoaded(false);
|
||||
}
|
||||
};
|
||||
|
||||
void loadInitial();
|
||||
}, [updateFiltersWithOrganisationId]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
const onSort = useCallback(
|
||||
async (nextSortColumn: Column<ReadSite>) => {
|
||||
@ -94,7 +114,8 @@ const Sites: React.FC = () => {
|
||||
setLoaded(false);
|
||||
}
|
||||
},
|
||||
[filters, pagedData, updateFiltersWithOrganisationId],
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[filters, updateFiltersWithOrganisationId],
|
||||
);
|
||||
|
||||
const onSearch = useCallback(
|
||||
@ -118,9 +139,9 @@ const Sites: React.FC = () => {
|
||||
setLoaded(false);
|
||||
}
|
||||
},
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[
|
||||
filters,
|
||||
pagedData,
|
||||
sortColumn.key,
|
||||
sortColumn.order,
|
||||
updateFiltersWithOrganisationId,
|
||||
@ -132,7 +153,7 @@ const Sites: React.FC = () => {
|
||||
await siteService.deleteSite(item?.id, item?.guid);
|
||||
await changePage(pagedData.page, pagedData.pageSize);
|
||||
},
|
||||
[changePage, pagedData.page, pagedData.pageSize],
|
||||
[changePage], // eslint-disable-line react-hooks/exhaustive-deps
|
||||
);
|
||||
|
||||
const translatedSortColumn = useMemo(
|
||||
|
||||
@ -68,8 +68,26 @@ const Specifications: React.FC = () => {
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
void changePage(initialPagedData.page, initialPagedData.pageSize);
|
||||
}, [changePage, siteId]);
|
||||
const loadInitial = async () => {
|
||||
const nextFilters = updateFiltersWithSiteId(new Map<string, string>());
|
||||
const pagedDataResult = await specificationService.GetSSpecifications(
|
||||
initialPagedData.page,
|
||||
initialPagedData.pageSize,
|
||||
"name",
|
||||
true,
|
||||
nextFilters,
|
||||
);
|
||||
if (pagedDataResult) {
|
||||
setLoaded(true);
|
||||
setFilters(nextFilters);
|
||||
setPagedData(pagedDataResult);
|
||||
} else {
|
||||
setLoaded(false);
|
||||
}
|
||||
};
|
||||
|
||||
void loadInitial();
|
||||
}, [updateFiltersWithSiteId]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
const onSort = useCallback(
|
||||
async (nextSortColumn: Column<ReadSpecification>) => {
|
||||
@ -91,7 +109,8 @@ const Specifications: React.FC = () => {
|
||||
setLoaded(false);
|
||||
}
|
||||
},
|
||||
[filters, pagedData, updateFiltersWithSiteId],
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[filters, updateFiltersWithSiteId],
|
||||
);
|
||||
|
||||
const onSearch = useCallback(
|
||||
@ -115,13 +134,8 @@ const Specifications: React.FC = () => {
|
||||
setLoaded(false);
|
||||
}
|
||||
},
|
||||
[
|
||||
filters,
|
||||
pagedData,
|
||||
sortColumn.key,
|
||||
sortColumn.order,
|
||||
updateFiltersWithSiteId,
|
||||
],
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[filters, sortColumn.key, sortColumn.order, updateFiltersWithSiteId],
|
||||
);
|
||||
|
||||
const onDelete = useCallback(
|
||||
@ -134,7 +148,8 @@ const Specifications: React.FC = () => {
|
||||
await changePage(pagedData.page, pagedData.pageSize);
|
||||
}
|
||||
},
|
||||
[changePage, pagedData.page, pagedData.pageSize],
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[changePage],
|
||||
);
|
||||
|
||||
const translatedSortColumn = useMemo(
|
||||
|
||||
@ -1,198 +1,292 @@
|
||||
import Joi from "joi";
|
||||
import React from "react";
|
||||
import { Navigate } from "react-router-dom";
|
||||
import React, { useEffect, useRef, useState, useCallback } from "react";
|
||||
import { Navigate, useParams } from "react-router-dom";
|
||||
import { toast } from "react-toastify";
|
||||
import Form, { FormState } from "../../../components/common/Form";
|
||||
import { useForm } from "../../../components/common/useForm";
|
||||
import { InputType } from "../../../components/common/Input";
|
||||
import Loading from "../../../components/common/Loading";
|
||||
import TemplateFiller from "../../../components/common/TemplateFiller";
|
||||
import { GeneralIdRef, MakeGeneralIdRef } from "../../../utils/GeneralIdRef";
|
||||
import withRouter from "../../../utils/withRouter";
|
||||
import { CustomFieldValue, PrintSpecificationsGlossary } from "../glossary/services/glossaryService";
|
||||
import {
|
||||
CustomFieldValue,
|
||||
PrintSpecificationsGlossary,
|
||||
} from "../glossary/services/glossaryService";
|
||||
import specificationService from "./services/specificationService";
|
||||
import {
|
||||
renderInput,
|
||||
renderButton,
|
||||
renderError,
|
||||
renderGlossaryPicker,
|
||||
} from "../../../components/common/formHelpers";
|
||||
|
||||
interface SpecificationsDetailsState extends FormState {
|
||||
formTemplate?: GeneralIdRef;
|
||||
interface SpecificationsDetailsProps {
|
||||
editMode?: boolean;
|
||||
}
|
||||
|
||||
const SpecificationsDetails: React.FC<SpecificationsDetailsProps> = ({
|
||||
editMode = false,
|
||||
}) => {
|
||||
const { organisationId, siteId, specificationId } = useParams<{
|
||||
organisationId: string;
|
||||
siteId: string;
|
||||
specificationId?: string;
|
||||
}>();
|
||||
const TemplateFillerRef = useRef<TemplateFiller>(null);
|
||||
|
||||
const labelName = "Name";
|
||||
const labelPrintSpecification = "Print Specification";
|
||||
const labelSigmaId = "SigmaId";
|
||||
const labelApply = "Save";
|
||||
const labelSave = "Save and close";
|
||||
|
||||
const form = useForm({
|
||||
loaded: false,
|
||||
data: {
|
||||
name: string;
|
||||
printSpecifications?: CustomFieldValue[];
|
||||
formInstanceId?: GeneralIdRef;
|
||||
sigmaId: bigint | null;
|
||||
};
|
||||
redirect: string;
|
||||
hasErrors: boolean;
|
||||
}
|
||||
name: "",
|
||||
sigmaId: null as bigint | null,
|
||||
printSpecifications: [] as CustomFieldValue[],
|
||||
formInstanceId: undefined,
|
||||
},
|
||||
errors: {},
|
||||
redirect: "",
|
||||
});
|
||||
|
||||
class LocSpecificationsDetails extends Form<any, any, SpecificationsDetailsState> {
|
||||
private TemplateFiller: React.RefObject<TemplateFiller>;
|
||||
const [formTemplate, setFormTemplate] = useState<GeneralIdRef | undefined>(
|
||||
undefined,
|
||||
);
|
||||
const [hasErrors, setHasErrors] = useState(false);
|
||||
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
this.TemplateFiller = React.createRef<TemplateFiller>();
|
||||
}
|
||||
form.schema = {
|
||||
name: Joi.string().required().max(450).label(labelName),
|
||||
printSpecifications: Joi.optional(),
|
||||
formInstanceId: Joi.optional(),
|
||||
sigmaId: Joi.number().allow(null).label(labelSigmaId),
|
||||
};
|
||||
|
||||
state: SpecificationsDetailsState = {
|
||||
loaded: false,
|
||||
formTemplate: undefined,
|
||||
data: {
|
||||
name: "",
|
||||
sigmaId: null,
|
||||
},
|
||||
errors: {},
|
||||
redirect: "",
|
||||
hasErrors: true,
|
||||
};
|
||||
const isEditMode = () => editMode;
|
||||
|
||||
labelName = "Name";
|
||||
labelPrintSpecification = "Print Specification";
|
||||
labelStatus = "Status";
|
||||
labelSigmaId = "SigmaId";
|
||||
const loadFormTemplate = useCallback(
|
||||
async (printSpecifications?: GeneralIdRef) => {
|
||||
const { data } = form.state;
|
||||
const printSpecArray =
|
||||
(data.printSpecifications as CustomFieldValue[]) || [];
|
||||
|
||||
labelApply = "Save";
|
||||
labelSave = "Save and close";
|
||||
|
||||
schema = {
|
||||
name: Joi.string().required().max(450).label(this.labelName),
|
||||
printSpecifications: Joi.optional(),
|
||||
formInstanceId: Joi.optional(),
|
||||
sigmaId: Joi.number().allow(null).label(this.labelSigmaId),
|
||||
};
|
||||
|
||||
doSubmit = async (buttonName: string) => {
|
||||
try {
|
||||
const { name, formInstanceId, sigmaId } = this.state.data;
|
||||
|
||||
const { siteId, organisationId, specificationId } = this.props.router.params;
|
||||
const siteIdGeneralIdRef = MakeGeneralIdRef(siteId);
|
||||
const templateFiller = this.TemplateFiller.current!;
|
||||
|
||||
if (this.isEditMode()) {
|
||||
await templateFiller.Save();
|
||||
const specificationIdGeneralIdRef = MakeGeneralIdRef(specificationId);
|
||||
const response = await specificationService.PutSpecification(specificationIdGeneralIdRef, siteIdGeneralIdRef, name, formInstanceId!, sigmaId);
|
||||
if (response) {
|
||||
toast.info("Specifications edited");
|
||||
}
|
||||
} else {
|
||||
const formInstanceId = await templateFiller.Save();
|
||||
if (!formInstanceId) {
|
||||
toast.error("Failed to save form instance");
|
||||
return;
|
||||
}
|
||||
|
||||
const response = await specificationService.PostSpecification(siteIdGeneralIdRef, name, formInstanceId!, sigmaId);
|
||||
if (response) {
|
||||
toast.info("New Specifications added");
|
||||
}
|
||||
}
|
||||
|
||||
if (buttonName === this.labelSave) this.setState({ redirect: "/Specifications/" + organisationId + "/" + siteId });
|
||||
} catch (ex: any) {
|
||||
this.handleGeneralError(ex);
|
||||
if (printSpecArray && printSpecArray.length > 0) {
|
||||
if (
|
||||
((printSpecArray[0] as CustomFieldValue).value as GeneralIdRef).id ===
|
||||
BigInt(0)
|
||||
) {
|
||||
data.printSpecifications = undefined;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
isEditMode = () => {
|
||||
const { editMode } = this.props;
|
||||
return editMode;
|
||||
};
|
||||
|
||||
componentDidMount = async () => {
|
||||
const { specificationId } = this.props.router.params;
|
||||
|
||||
if (specificationId !== undefined) {
|
||||
try {
|
||||
const loadedData = await specificationService.GetSSpecification(BigInt(specificationId));
|
||||
|
||||
const { data } = this.state;
|
||||
if (loadedData) {
|
||||
data.name = loadedData.name;
|
||||
data.formInstanceId = loadedData.formInstanceId;
|
||||
|
||||
this.setState({ loaded: true, data });
|
||||
} else {
|
||||
this.setState({ loaded: false });
|
||||
}
|
||||
} catch (ex: any) {
|
||||
this.handleGeneralError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.isEditMode()) this.setState({ loaded: true });
|
||||
};
|
||||
|
||||
componentDidUpdate(prevProps: Readonly<any>, prevState: Readonly<SpecificationsDetailsState>, snapshot?: any): void {
|
||||
let { printSpecifications } = this.state.data;
|
||||
if (printSpecifications !== prevState.data.printSpecifications) {
|
||||
if (printSpecifications && printSpecifications.length > 0) {
|
||||
this.LoadFormTemplate(printSpecifications[0].value as GeneralIdRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LoadFormTemplate = async (printSpecifications?: GeneralIdRef) => {
|
||||
let { data } = this.state;
|
||||
|
||||
if (data.printSpecifications && data.printSpecifications.length > 0) {
|
||||
if (((data.printSpecifications[0] as CustomFieldValue).value as GeneralIdRef).id === BigInt(0)) data.printSpecifications = undefined;
|
||||
}
|
||||
|
||||
let formTemplate;
|
||||
if (data.printSpecifications === undefined) {
|
||||
formTemplate = undefined;
|
||||
} else {
|
||||
formTemplate = await specificationService.GetTemplateForPrintSpec(data.printSpecifications[0].value as GeneralIdRef);
|
||||
}
|
||||
if (formTemplate) {
|
||||
this.setState({ loaded: true, data, formTemplate });
|
||||
} else {
|
||||
this.setState({ loaded: false });
|
||||
}
|
||||
};
|
||||
|
||||
handleValidationChanged = () => {
|
||||
const templateFiller = this.TemplateFiller.current;
|
||||
|
||||
let templateErrors: boolean = false;
|
||||
|
||||
if (templateFiller) templateErrors = !templateFiller.hasValidationErrors();
|
||||
|
||||
this.setState({ hasErrors: templateErrors });
|
||||
};
|
||||
|
||||
render() {
|
||||
const { loaded, redirect, formTemplate, data, hasErrors } = this.state;
|
||||
if (redirect !== "") return <Navigate to={redirect} />;
|
||||
|
||||
let mode = "Add";
|
||||
const isEditMode = this.isEditMode();
|
||||
if (isEditMode) mode = "Edit";
|
||||
|
||||
return (
|
||||
<Loading loaded={loaded}>
|
||||
<h1>{mode} Specifications</h1>
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
{this.renderError("_general")}
|
||||
{this.renderInput("name", this.labelName, InputType.text)}
|
||||
{this.renderInput("sigmaId", this.labelSigmaId, InputType.number)}
|
||||
{!this.isEditMode() && this.renderGlossaryPicker(true, "printSpecifications", this.labelPrintSpecification, 1, PrintSpecificationsGlossary)}
|
||||
|
||||
<TemplateFiller
|
||||
templateId={formTemplate}
|
||||
formInstanceId={data.formInstanceId}
|
||||
ref={this.TemplateFiller}
|
||||
onValidationChanged={this.handleValidationChanged}
|
||||
/>
|
||||
|
||||
<br />
|
||||
{isEditMode && this.renderButton(this.labelApply, undefined, undefined, undefined, hasErrors)}
|
||||
{this.renderButton(this.labelSave, undefined, undefined, undefined, hasErrors)}
|
||||
</form>
|
||||
</Loading>
|
||||
let template;
|
||||
if (!printSpecArray || printSpecArray.length === 0) {
|
||||
template = undefined;
|
||||
} else {
|
||||
template = await specificationService.GetTemplateForPrintSpec(
|
||||
(printSpecArray[0] as CustomFieldValue).value as GeneralIdRef,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (template) {
|
||||
setFormTemplate(template);
|
||||
form.setState({ loaded: true });
|
||||
} else {
|
||||
form.setState({ loaded: false });
|
||||
}
|
||||
},
|
||||
[form],
|
||||
);
|
||||
|
||||
const SpecificationsDetails = withRouter(LocSpecificationsDetails);
|
||||
const handleValidationChanged = useCallback(() => {
|
||||
const templateFiller = TemplateFillerRef.current;
|
||||
let templateErrors: boolean = false;
|
||||
if (templateFiller) templateErrors = templateFiller.hasValidationErrors();
|
||||
setHasErrors(templateErrors);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const loadData = async () => {
|
||||
if (specificationId !== undefined) {
|
||||
try {
|
||||
const loadedData = await specificationService.GetSSpecification(
|
||||
BigInt(specificationId),
|
||||
);
|
||||
if (loadedData) {
|
||||
const newData = { ...form.state.data };
|
||||
newData.name = loadedData.name;
|
||||
newData.formInstanceId = loadedData.formInstanceId;
|
||||
form.setState({ loaded: true, data: newData });
|
||||
} else {
|
||||
form.setState({ loaded: false });
|
||||
}
|
||||
} catch (ex: any) {
|
||||
form.handleGeneralError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (!editMode) {
|
||||
form.setState({ loaded: true });
|
||||
}
|
||||
};
|
||||
|
||||
loadData();
|
||||
}, [specificationId, editMode]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
useEffect(() => {
|
||||
const { printSpecifications } = form.state.data;
|
||||
const printSpecArray = (printSpecifications as CustomFieldValue[]) || [];
|
||||
if (printSpecArray && printSpecArray.length > 0) {
|
||||
loadFormTemplate(
|
||||
(printSpecArray[0] as CustomFieldValue).value as GeneralIdRef,
|
||||
);
|
||||
}
|
||||
}, [form.state.data.printSpecifications, loadFormTemplate, form]);
|
||||
|
||||
const doSubmit = async (buttonName: string) => {
|
||||
try {
|
||||
const { name, formInstanceId, sigmaId } = form.state.data;
|
||||
const nameStr = typeof name === "string" ? name : "";
|
||||
const sigmaIdValue =
|
||||
sigmaId === null || sigmaId === undefined || sigmaId === ""
|
||||
? null
|
||||
: typeof sigmaId === "bigint"
|
||||
? sigmaId
|
||||
: BigInt(sigmaId as string | number);
|
||||
const siteIdGeneralIdRef = MakeGeneralIdRef(
|
||||
siteId ? BigInt(siteId) : undefined,
|
||||
);
|
||||
const templateFiller = TemplateFillerRef.current!;
|
||||
|
||||
if (isEditMode()) {
|
||||
await templateFiller.Save();
|
||||
const specificationIdGeneralIdRef = MakeGeneralIdRef(
|
||||
specificationId ? BigInt(specificationId) : undefined,
|
||||
);
|
||||
const response = await specificationService.PutSpecification(
|
||||
specificationIdGeneralIdRef,
|
||||
siteIdGeneralIdRef,
|
||||
nameStr,
|
||||
formInstanceId as GeneralIdRef,
|
||||
sigmaIdValue,
|
||||
);
|
||||
if (response) {
|
||||
toast.info("Specifications edited");
|
||||
}
|
||||
} else {
|
||||
const newFormInstanceId = await templateFiller.Save();
|
||||
if (!newFormInstanceId) {
|
||||
toast.error("Failed to save form instance");
|
||||
return;
|
||||
}
|
||||
|
||||
const response = await specificationService.PostSpecification(
|
||||
siteIdGeneralIdRef,
|
||||
nameStr,
|
||||
newFormInstanceId!,
|
||||
sigmaIdValue,
|
||||
);
|
||||
if (response) {
|
||||
toast.info("New Specifications added");
|
||||
}
|
||||
}
|
||||
|
||||
if (buttonName === "save") {
|
||||
form.setState({
|
||||
redirect: "/Specifications/" + organisationId + "/" + siteId,
|
||||
});
|
||||
}
|
||||
} catch (ex: any) {
|
||||
form.handleGeneralError(ex);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||
form.handleSubmit(e, doSubmit);
|
||||
};
|
||||
|
||||
const { loaded, redirect } = form.state;
|
||||
if (redirect && redirect !== "") return <Navigate to={redirect} />;
|
||||
|
||||
const mode = isEditMode() ? "Edit" : "Add";
|
||||
|
||||
return (
|
||||
<Loading loaded={loaded}>
|
||||
<h1>{mode} Specifications</h1>
|
||||
<form onSubmit={handleSubmit}>
|
||||
{renderError("_general", form.state.errors)}
|
||||
{renderInput(
|
||||
"name",
|
||||
labelName,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.text,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
{renderInput(
|
||||
"sigmaId",
|
||||
labelSigmaId,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.number,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
false,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
{!isEditMode() &&
|
||||
renderGlossaryPicker(
|
||||
true,
|
||||
"printSpecifications",
|
||||
labelPrintSpecification,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
1,
|
||||
PrintSpecificationsGlossary,
|
||||
form.handleGlossaryPickerChange,
|
||||
)}
|
||||
|
||||
<TemplateFiller
|
||||
templateId={formTemplate}
|
||||
formInstanceId={form.state.data.formInstanceId}
|
||||
ref={TemplateFillerRef}
|
||||
onValidationChanged={handleValidationChanged}
|
||||
/>
|
||||
|
||||
<br />
|
||||
{isEditMode() &&
|
||||
renderButton(
|
||||
labelApply,
|
||||
form.state.errors,
|
||||
"apply",
|
||||
undefined,
|
||||
undefined,
|
||||
Object.keys(form.state.errors).length === 0 && !hasErrors,
|
||||
undefined,
|
||||
true,
|
||||
)}
|
||||
{renderButton(
|
||||
labelSave,
|
||||
form.state.errors,
|
||||
"save",
|
||||
undefined,
|
||||
undefined,
|
||||
Object.keys(form.state.errors).length === 0 && !hasErrors,
|
||||
undefined,
|
||||
true,
|
||||
)}
|
||||
</form>
|
||||
</Loading>
|
||||
);
|
||||
};
|
||||
|
||||
export default SpecificationsDetails;
|
||||
|
||||
@ -1,161 +1,291 @@
|
||||
import Joi from "joi";
|
||||
import React from "react";
|
||||
import { Navigate } from "react-router-dom";
|
||||
import React, { useEffect } from "react";
|
||||
import { Navigate, useParams, useLocation } from "react-router-dom";
|
||||
import { toast } from "react-toastify";
|
||||
import Form from "../../../components/common/Form";
|
||||
import { useForm } from "../../../components/common/useForm";
|
||||
import { InputType } from "../../../components/common/Input";
|
||||
import { FormState } from "../../../components/common/Form";
|
||||
import withRouter from "../../../utils/withRouter";
|
||||
import {
|
||||
renderInput,
|
||||
renderButton,
|
||||
renderError,
|
||||
} from "../../../components/common/formHelpers";
|
||||
import { MakeGeneralIdRef } from "../../../utils/GeneralIdRef";
|
||||
import Loading from "../../../components/common/Loading";
|
||||
import ssoManagerService from "./services/ssoManagerService";
|
||||
|
||||
interface SsoProviderDetailsState extends FormState {
|
||||
interface SsoProviderDetailsProps {
|
||||
editMode?: boolean;
|
||||
}
|
||||
|
||||
const SsoProviderDetails: React.FC<SsoProviderDetailsProps> = ({
|
||||
editMode = false,
|
||||
}) => {
|
||||
const { ssoProviderId } = useParams<{ ssoProviderId: string }>();
|
||||
const location = useLocation();
|
||||
|
||||
const labelName = "Name";
|
||||
const labelClientId = "Client Id";
|
||||
const labelClientSecret = "Client Secret";
|
||||
const labelValidIssuer = "Valid Issuer";
|
||||
const labelAuthorizationEndpoint = "Authorisation Endpoint";
|
||||
const labelTokenEndpoint = "Token Endpoint";
|
||||
const labelIsPublic = "Is Public";
|
||||
|
||||
const labelApply = "Save";
|
||||
const labelSave = "Save and close";
|
||||
|
||||
const form = useForm({
|
||||
loaded: false,
|
||||
data: {
|
||||
name: string;
|
||||
clientId: string,
|
||||
clientSecret: string,
|
||||
validIssuer: string,
|
||||
authorizationEndpoint: string,
|
||||
tokenEndpoint: string,
|
||||
isPublic: boolean,
|
||||
};
|
||||
redirect: string;
|
||||
}
|
||||
name: "",
|
||||
clientId: "",
|
||||
clientSecret: "",
|
||||
validIssuer: "",
|
||||
authorizationEndpoint: "",
|
||||
tokenEndpoint: "",
|
||||
isPublic: true,
|
||||
},
|
||||
errors: {},
|
||||
redirect: "",
|
||||
});
|
||||
|
||||
class SsoProviderDetails extends Form<any, any, SsoProviderDetailsState> {
|
||||
state: SsoProviderDetailsState = {
|
||||
loaded : false,
|
||||
data: {
|
||||
name: "",
|
||||
clientId: "",
|
||||
clientSecret: "",
|
||||
validIssuer: "",
|
||||
authorizationEndpoint: "",
|
||||
tokenEndpoint: "",
|
||||
isPublic: true,
|
||||
},
|
||||
errors: {},
|
||||
redirect: "",
|
||||
};
|
||||
form.schema = {
|
||||
name: Joi.string().required().max(450).label(labelName),
|
||||
clientId: Joi.string().required().max(450).label(labelClientId),
|
||||
clientSecret: Joi.string().required().max(450).label(labelClientSecret),
|
||||
validIssuer: Joi.string().required().max(450).label(labelValidIssuer),
|
||||
authorizationEndpoint: Joi.string()
|
||||
.required()
|
||||
.max(450)
|
||||
.label(labelAuthorizationEndpoint),
|
||||
tokenEndpoint: Joi.string().required().max(450).label(labelTokenEndpoint),
|
||||
isPublic: Joi.bool().required().label(labelIsPublic),
|
||||
};
|
||||
|
||||
labelName = "Name";
|
||||
labelClientId = "Client Id";
|
||||
labelClientSecret = "Client Secret";
|
||||
labelValidIssuer = "Valid Issuer";
|
||||
labelAuthorizationEndpoint = "Authorisation Endpoint";
|
||||
labelTokenEndpoint = "Token Endpoint";
|
||||
labelIsPublic = "Is Public";
|
||||
|
||||
labelApply = "Save";
|
||||
labelSave = "Save and close";
|
||||
|
||||
schema = {
|
||||
name: Joi.string().required().max(450).label(this.labelName),
|
||||
clientId: Joi.string().required().max(450).label(this.labelClientId),
|
||||
clientSecret: Joi.string().required().max(450).label(this.labelClientSecret),
|
||||
validIssuer: Joi.string().required().max(450).label(this.labelValidIssuer),
|
||||
authorizationEndpoint: Joi.string().required().max(450).label(this.labelAuthorizationEndpoint),
|
||||
tokenEndpoint: Joi.string().required().max(450).label(this.labelTokenEndpoint),
|
||||
isPublic: Joi.bool().required().label(this.labelIsPublic),
|
||||
};
|
||||
|
||||
doSubmit = async (buttonName : string) => {
|
||||
useEffect(() => {
|
||||
const loadData = async () => {
|
||||
if (ssoProviderId !== undefined) {
|
||||
try {
|
||||
const { name, clientId, clientSecret, validIssuer, authorizationEndpoint, tokenEndpoint, isPublic } = this.state.data;
|
||||
|
||||
if (this.isEditMode()) {
|
||||
const { ssoProviderId } = this.props.router.params;
|
||||
|
||||
var generalIdRef = MakeGeneralIdRef(ssoProviderId);
|
||||
const response = await ssoManagerService.putSsoProvider(generalIdRef, name, clientId, clientSecret, validIssuer, authorizationEndpoint, tokenEndpoint, isPublic);
|
||||
if (response) {
|
||||
toast.info("Sso Provider edited");
|
||||
}
|
||||
} else {
|
||||
const response = await ssoManagerService.postSsoProvider(name, clientId, clientSecret, validIssuer, authorizationEndpoint, tokenEndpoint, isPublic);
|
||||
if (response) {
|
||||
toast.info("New Sso Provider added");
|
||||
}
|
||||
}
|
||||
|
||||
if (buttonName === this.labelSave)
|
||||
this.setState({ redirect: "/ssoManager" });
|
||||
}
|
||||
catch(ex: any) {
|
||||
this.handleGeneralError(ex);
|
||||
const loadedData = await ssoManagerService.getSsoProvider(
|
||||
BigInt(ssoProviderId),
|
||||
);
|
||||
if (loadedData) {
|
||||
const newData = { ...form.state.data };
|
||||
newData.name = loadedData.name;
|
||||
newData.clientId = loadedData.clientId;
|
||||
newData.clientSecret = loadedData.clientSecret;
|
||||
newData.validIssuer = loadedData.validIssuer;
|
||||
newData.authorizationEndpoint = loadedData.authorizationEndpoint;
|
||||
newData.tokenEndpoint = loadedData.tokenEndpoint;
|
||||
newData.isPublic = loadedData.isPublic;
|
||||
form.setState({ loaded: true, data: newData });
|
||||
} else {
|
||||
form.setState({ loaded: false });
|
||||
}
|
||||
} catch (ex: any) {
|
||||
form.handleGeneralError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (!editMode) {
|
||||
form.setState({ loaded: true });
|
||||
}
|
||||
};
|
||||
|
||||
isEditMode = () => {
|
||||
const { editMode } = this.props;
|
||||
return editMode;
|
||||
};
|
||||
loadData();
|
||||
}, [ssoProviderId, editMode]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
componentDidMount = async () => {
|
||||
const { ssoProviderId } = this.props.router.params;
|
||||
const doSubmit = async (buttonName: string) => {
|
||||
try {
|
||||
const {
|
||||
name,
|
||||
clientId,
|
||||
clientSecret,
|
||||
validIssuer,
|
||||
authorizationEndpoint,
|
||||
tokenEndpoint,
|
||||
isPublic,
|
||||
} = form.state.data;
|
||||
const nameStr = typeof name === "string" ? name : "";
|
||||
const clientIdStr = typeof clientId === "string" ? clientId : "";
|
||||
const clientSecretStr =
|
||||
typeof clientSecret === "string" ? clientSecret : "";
|
||||
const validIssuerStr = typeof validIssuer === "string" ? validIssuer : "";
|
||||
const authorizationEndpointStr =
|
||||
typeof authorizationEndpoint === "string" ? authorizationEndpoint : "";
|
||||
const tokenEndpointStr =
|
||||
typeof tokenEndpoint === "string" ? tokenEndpoint : "";
|
||||
const isPublicValue = Boolean(isPublic);
|
||||
|
||||
if (ssoProviderId !== undefined) {
|
||||
try {
|
||||
const loadedData = await ssoManagerService.getSsoProvider(ssoProviderId);
|
||||
if (loadedData) {
|
||||
const { data } = this.state;
|
||||
|
||||
data.name = loadedData.name;
|
||||
data.clientId = loadedData.clientId;
|
||||
data.clientSecret = loadedData.clientSecret;
|
||||
data.validIssuer = loadedData.validIssuer;
|
||||
data.authorizationEndpoint = loadedData.authorizationEndpoint;
|
||||
data.tokenEndpoint = loadedData.tokenEndpoint;
|
||||
data.isPublic = loadedData.isPublic
|
||||
|
||||
this.setState({ loaded: true, data });
|
||||
}
|
||||
else {
|
||||
this.setState({ loaded: false });
|
||||
}
|
||||
}
|
||||
catch(ex: any) {
|
||||
this.handleGeneralError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.isEditMode())
|
||||
this.setState({ loaded: true } );
|
||||
};
|
||||
|
||||
render() {
|
||||
const { loaded, redirect } = this.state;
|
||||
if (redirect !== "") return <Navigate to={redirect} />;
|
||||
|
||||
let mode = "Add";
|
||||
if (this.isEditMode()) mode = "Edit";
|
||||
|
||||
let redirectUrl = window.location.href.slice(0,window.location.href.length - this.props.router.location.pathname.length) + "/account/auth/" + this.props.router.params.ssoProviderId;
|
||||
|
||||
return (
|
||||
<Loading loaded={loaded}>
|
||||
<h1>{mode} Sso Provider</h1>
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
{this.renderError("_general")}
|
||||
{this.renderInput("name", this.labelName, InputType.text)}
|
||||
{this.renderInput("clientId", this.labelClientId, InputType.text)}
|
||||
{this.renderInput("clientSecret", this.labelClientSecret, InputType.text)}
|
||||
{this.renderInput("validIssuer", this.labelValidIssuer, InputType.text)}
|
||||
{this.renderInput("authorizationEndpoint", this.labelAuthorizationEndpoint, InputType.text)}
|
||||
{this.renderInput("tokenEndpoint", this.labelTokenEndpoint, InputType.text)}
|
||||
<div className="allignedCheckBox">{this.renderInput("isPublic", this.labelIsPublic, InputType.checkbox)}</div>
|
||||
|
||||
{this.isEditMode() && <div>Redirect URL: {redirectUrl}</div>}
|
||||
|
||||
{this.isEditMode() && this.renderButton(this.labelApply)}
|
||||
{this.renderButton(this.labelSave)}
|
||||
</form>
|
||||
</Loading>
|
||||
if (editMode) {
|
||||
const generalIdRef = MakeGeneralIdRef(
|
||||
ssoProviderId ? BigInt(ssoProviderId) : undefined,
|
||||
);
|
||||
const response = await ssoManagerService.putSsoProvider(
|
||||
generalIdRef,
|
||||
nameStr,
|
||||
clientIdStr,
|
||||
clientSecretStr,
|
||||
validIssuerStr,
|
||||
authorizationEndpointStr,
|
||||
tokenEndpointStr,
|
||||
isPublicValue,
|
||||
);
|
||||
if (response) {
|
||||
toast.info("Sso Provider edited");
|
||||
}
|
||||
} else {
|
||||
const response = await ssoManagerService.postSsoProvider(
|
||||
nameStr,
|
||||
clientIdStr,
|
||||
clientSecretStr,
|
||||
validIssuerStr,
|
||||
authorizationEndpointStr,
|
||||
tokenEndpointStr,
|
||||
isPublicValue,
|
||||
);
|
||||
if (response) {
|
||||
toast.info("New Sso Provider added");
|
||||
}
|
||||
}
|
||||
|
||||
if (buttonName === "save") {
|
||||
form.setState({ redirect: "/ssoManager" });
|
||||
}
|
||||
} catch (ex: any) {
|
||||
form.handleGeneralError(ex);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const HOCSsoProviderDetails = withRouter(SsoProviderDetails);
|
||||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||
form.handleSubmit(e, doSubmit);
|
||||
};
|
||||
|
||||
export default HOCSsoProviderDetails;
|
||||
const { loaded, redirect } = form.state;
|
||||
if (redirect) return <Navigate to={redirect} />;
|
||||
|
||||
const mode = editMode ? "Edit" : "Add";
|
||||
const redirectUrl =
|
||||
window.location.href.slice(
|
||||
0,
|
||||
window.location.href.length - location.pathname.length,
|
||||
) +
|
||||
"/account/auth/" +
|
||||
ssoProviderId;
|
||||
|
||||
return (
|
||||
<Loading loaded={loaded}>
|
||||
<h1>{mode} Sso Provider</h1>
|
||||
<form onSubmit={handleSubmit}>
|
||||
{renderError("_general", form.state.errors)}
|
||||
{renderInput(
|
||||
"name",
|
||||
labelName,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.text,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
{renderInput(
|
||||
"clientId",
|
||||
labelClientId,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.text,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
{renderInput(
|
||||
"clientSecret",
|
||||
labelClientSecret,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.text,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
{renderInput(
|
||||
"validIssuer",
|
||||
labelValidIssuer,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.text,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
{renderInput(
|
||||
"authorizationEndpoint",
|
||||
labelAuthorizationEndpoint,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.text,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
{renderInput(
|
||||
"tokenEndpoint",
|
||||
labelTokenEndpoint,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.text,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
<div className="allignedCheckBox">
|
||||
{renderInput(
|
||||
"isPublic",
|
||||
labelIsPublic,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.checkbox,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
false,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
</div>
|
||||
|
||||
{editMode && <div>Redirect URL: {redirectUrl}</div>}
|
||||
|
||||
{editMode && renderButton(labelApply, form.state.errors, "save")}
|
||||
{renderButton(labelSave, form.state.errors, "save")}
|
||||
</form>
|
||||
</Loading>
|
||||
);
|
||||
};
|
||||
|
||||
export default SsoProviderDetails;
|
||||
|
||||
@ -98,8 +98,24 @@ const SsoManager: React.FC = () => {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
changePage(pagedData.page, pagedData.pageSize);
|
||||
}, [changePage, pagedData.page, pagedData.pageSize]);
|
||||
const loadInitial = async () => {
|
||||
const data = await ssoManagerService.getSsoProviders(
|
||||
1,
|
||||
10,
|
||||
"name",
|
||||
true,
|
||||
filters,
|
||||
);
|
||||
if (data) {
|
||||
setLoaded(true);
|
||||
setPagedData(data);
|
||||
} else {
|
||||
setLoaded(false);
|
||||
}
|
||||
};
|
||||
|
||||
void loadInitial();
|
||||
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
return (
|
||||
<Loading loaded={loaded}>
|
||||
|
||||
@ -1,144 +1,238 @@
|
||||
import Joi from "joi";
|
||||
import React from "react";
|
||||
import { Navigate } from "react-router-dom";
|
||||
import React, { useEffect } from "react";
|
||||
import { Navigate, useParams } from "react-router-dom";
|
||||
import { toast } from "react-toastify";
|
||||
import Form, { FormState } from "../../../../components/common/Form";
|
||||
import { useForm } from "../../../../components/common/useForm";
|
||||
import { InputType } from "../../../../components/common/Input";
|
||||
import { GeneralIdRef, MakeGeneralIdRef } from "../../../../utils/GeneralIdRef";
|
||||
import withRouter, { RouterProps } from "../../../../utils/withRouter";
|
||||
import authentication from "../../../frame/services/authenticationService";
|
||||
import userService from "../services/usersService";
|
||||
import Loading from "../../../../components/common/Loading";
|
||||
import { CustomFieldValue } from "../../glossary/services/glossaryService";
|
||||
import {
|
||||
renderInput,
|
||||
renderButton,
|
||||
renderError,
|
||||
renderDomainPicker,
|
||||
} from "../../../../components/common/formHelpers";
|
||||
|
||||
interface GeneralTabProps extends RouterProps {
|
||||
isEditMode: boolean;
|
||||
interface GeneralTabProps {
|
||||
isEditMode: boolean;
|
||||
}
|
||||
|
||||
interface GeneralTabState extends FormState {
|
||||
const GeneralTab: React.FC<GeneralTabProps> = ({ isEditMode }) => {
|
||||
const { userId } = useParams<{ userId: string }>();
|
||||
|
||||
const labelFirstName = "First name";
|
||||
const labelMiddleNames = "Middle names";
|
||||
const labelLastName = "Last name";
|
||||
const labelEmail = "Mail";
|
||||
const labelDomain = "Domain";
|
||||
|
||||
const labelApply = "Save";
|
||||
const labelSave = "Save and close";
|
||||
|
||||
const form = useForm({
|
||||
loaded: false,
|
||||
data: {
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
middleNames: string;
|
||||
email: string;
|
||||
domain: CustomFieldValue[];
|
||||
};
|
||||
redirect: string;
|
||||
}
|
||||
firstName: "",
|
||||
lastName: "",
|
||||
middleNames: "",
|
||||
email: "",
|
||||
domain: [] as CustomFieldValue[],
|
||||
},
|
||||
errors: {},
|
||||
redirect: "",
|
||||
});
|
||||
|
||||
class LocGeneralTab extends Form<GeneralTabProps, any, GeneralTabState> {
|
||||
state: GeneralTabState = {
|
||||
loaded: false,
|
||||
data: {
|
||||
firstName: "",
|
||||
lastName: "",
|
||||
middleNames: "",
|
||||
email: "",
|
||||
domain: [],
|
||||
},
|
||||
errors: {},
|
||||
redirect: "",
|
||||
};
|
||||
form.schema = {
|
||||
firstName: Joi.string().required().max(450).label(labelFirstName),
|
||||
middleNames: Joi.string().allow("").required().label(labelMiddleNames),
|
||||
lastName: Joi.string().required().label(labelLastName),
|
||||
email: Joi.string()
|
||||
.required()
|
||||
.email({ tlds: { allow: false } })
|
||||
.label(labelEmail),
|
||||
domain: Joi.optional(),
|
||||
};
|
||||
|
||||
labelFirstName = "First name";
|
||||
labelMiddleNames = "Middle names";
|
||||
labelLastName = "Last name";
|
||||
labelEmail = "Mail";
|
||||
labelDomain = "Domain";
|
||||
useEffect(() => {
|
||||
const loadData = async () => {
|
||||
const newData = { ...form.state.data };
|
||||
|
||||
labelApply = "Save";
|
||||
labelSave = "Save and close";
|
||||
|
||||
schema = {
|
||||
firstName: Joi.string().required().max(450).label(this.labelFirstName),
|
||||
middleNames: Joi.string().allow("").required().label(this.labelMiddleNames),
|
||||
lastName: Joi.string().required().label(this.labelLastName),
|
||||
email: Joi.string()
|
||||
.required()
|
||||
.email({ tlds: { allow: false } })
|
||||
.label(this.labelEmail),
|
||||
domain: Joi.optional(),
|
||||
};
|
||||
|
||||
doSubmit = async (buttonName: string) => {
|
||||
if (userId !== undefined) {
|
||||
try {
|
||||
const { isEditMode } = this.props;
|
||||
|
||||
const { firstName, middleNames, lastName, email, domain } = this.state.data;
|
||||
|
||||
if (isEditMode) {
|
||||
const { userId } = this.props.router.params;
|
||||
|
||||
var generalIdRef = MakeGeneralIdRef(userId);
|
||||
const response = await userService.putUser(generalIdRef, firstName, middleNames, lastName, email, domain[0]?.value as GeneralIdRef);
|
||||
if (response) {
|
||||
toast.info("User edited");
|
||||
}
|
||||
} else {
|
||||
const response = await userService.postUser(firstName, middleNames, lastName, email, domain[0]?.value as GeneralIdRef);
|
||||
if (response) {
|
||||
toast.info("New User added");
|
||||
}
|
||||
}
|
||||
|
||||
if (buttonName === this.labelSave) this.setState({ redirect: "/users" });
|
||||
const loadedData = await userService.getUser(BigInt(userId));
|
||||
if (loadedData) {
|
||||
newData.firstName = loadedData.firstName;
|
||||
newData.lastName = loadedData.lastName;
|
||||
newData.middleNames = loadedData.middleNames;
|
||||
newData.email = loadedData.email;
|
||||
newData.domain = [{ value: loadedData.domain } as CustomFieldValue];
|
||||
}
|
||||
} catch (ex: any) {
|
||||
this.handleGeneralError(ex);
|
||||
form.handleGeneralError(ex);
|
||||
}
|
||||
} else {
|
||||
const user = authentication.getCurrentUser();
|
||||
newData.domain = [
|
||||
{ value: MakeGeneralIdRef(user?.domainid) } as CustomFieldValue,
|
||||
];
|
||||
}
|
||||
|
||||
form.setState({ loaded: true, data: newData });
|
||||
};
|
||||
|
||||
componentDidMount = async () => {
|
||||
const { userId } = this.props.router.params;
|
||||
loadData();
|
||||
}, [userId]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
const { data } = this.state;
|
||||
const doSubmit = async (buttonName: string) => {
|
||||
try {
|
||||
const { firstName, middleNames, lastName, email, domain } =
|
||||
form.state.data;
|
||||
const firstNameStr = typeof firstName === "string" ? firstName : "";
|
||||
const middleNamesStr = typeof middleNames === "string" ? middleNames : "";
|
||||
const lastNameStr = typeof lastName === "string" ? lastName : "";
|
||||
const emailStr = typeof email === "string" ? email : "";
|
||||
const domainValues = (domain as CustomFieldValue[]) ?? [];
|
||||
const domainValue = domainValues[0]?.value as GeneralIdRef | undefined;
|
||||
|
||||
if (userId !== undefined) {
|
||||
try {
|
||||
const loadedData = await userService.getUser(userId);
|
||||
if (loadedData) {
|
||||
data.firstName = loadedData.firstName;
|
||||
data.lastName = loadedData.lastName;
|
||||
data.middleNames = loadedData.middleNames;
|
||||
data.email = loadedData.email;
|
||||
data.domain = [{ value: loadedData.domain }];
|
||||
}
|
||||
} catch (ex: any) {
|
||||
this.handleGeneralError(ex);
|
||||
}
|
||||
} else {
|
||||
const user = authentication.getCurrentUser();
|
||||
|
||||
data.domain = [{ value: MakeGeneralIdRef(user?.domainid) }];
|
||||
}
|
||||
|
||||
this.setState({ loaded: true, data });
|
||||
};
|
||||
|
||||
render() {
|
||||
const { loaded, redirect } = this.state;
|
||||
if (redirect !== "") return <Navigate to={redirect} />;
|
||||
|
||||
const { isEditMode } = this.props;
|
||||
return (
|
||||
<Loading loaded={loaded}>
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
{this.renderError("_general")}
|
||||
{isEditMode && this.renderInput("email", this.labelEmail, InputType.text, true)}
|
||||
{!isEditMode && this.renderInput("email", this.labelEmail)}
|
||||
{this.renderInput("firstName", this.labelFirstName)}
|
||||
{this.renderInput("middleNames", this.labelMiddleNames)}
|
||||
{this.renderInput("lastName", this.labelLastName)}
|
||||
|
||||
{this.renderDomainPicker(true, "domain", this.labelDomain, 1, 1)}
|
||||
|
||||
{isEditMode && this.renderButton(this.labelApply)}
|
||||
{this.renderButton(this.labelSave)}
|
||||
</form>
|
||||
</Loading>
|
||||
if (isEditMode) {
|
||||
const generalIdRef = MakeGeneralIdRef(
|
||||
userId ? BigInt(userId) : undefined,
|
||||
);
|
||||
}
|
||||
}
|
||||
const response = await userService.putUser(
|
||||
generalIdRef,
|
||||
firstNameStr,
|
||||
middleNamesStr,
|
||||
lastNameStr,
|
||||
emailStr,
|
||||
domainValue,
|
||||
);
|
||||
if (response) {
|
||||
toast.info("User edited");
|
||||
}
|
||||
} else {
|
||||
const response = await userService.postUser(
|
||||
firstNameStr,
|
||||
middleNamesStr,
|
||||
lastNameStr,
|
||||
emailStr,
|
||||
domainValue,
|
||||
);
|
||||
if (response) {
|
||||
toast.info("New User added");
|
||||
}
|
||||
}
|
||||
|
||||
const GeneralTab = withRouter(LocGeneralTab);
|
||||
if (buttonName === "save") {
|
||||
form.setState({ redirect: "/users" });
|
||||
}
|
||||
} catch (ex: any) {
|
||||
form.handleGeneralError(ex);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||
form.handleSubmit(e, doSubmit);
|
||||
};
|
||||
|
||||
const { loaded, redirect } = form.state;
|
||||
if (redirect) return <Navigate to={redirect} />;
|
||||
|
||||
return (
|
||||
<Loading loaded={loaded}>
|
||||
<form onSubmit={handleSubmit}>
|
||||
{renderError("_general", form.state.errors)}
|
||||
{isEditMode &&
|
||||
renderInput(
|
||||
"email",
|
||||
labelEmail,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.text,
|
||||
true,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
{!isEditMode &&
|
||||
renderInput(
|
||||
"email",
|
||||
labelEmail,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.text,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
{renderInput(
|
||||
"firstName",
|
||||
labelFirstName,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.text,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
{renderInput(
|
||||
"middleNames",
|
||||
labelMiddleNames,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.text,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
false,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
{renderInput(
|
||||
"lastName",
|
||||
labelLastName,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
InputType.text,
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
undefined,
|
||||
form.handleChange,
|
||||
)}
|
||||
|
||||
{renderDomainPicker(
|
||||
true,
|
||||
"domain",
|
||||
labelDomain,
|
||||
form.state.data,
|
||||
form.state.errors,
|
||||
1,
|
||||
undefined,
|
||||
form.handleDomainPickerChange,
|
||||
)}
|
||||
|
||||
{isEditMode && renderButton(labelApply, form.state.errors, "save")}
|
||||
{renderButton(labelSave, form.state.errors, "save")}
|
||||
</form>
|
||||
</Loading>
|
||||
);
|
||||
};
|
||||
|
||||
export default GeneralTab;
|
||||
|
||||
@ -102,8 +102,24 @@ const Users: React.FC = () => {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
changePage(pagedData.page, pagedData.pageSize);
|
||||
}, [changePage, pagedData.page, pagedData.pageSize]);
|
||||
const loadInitial = async () => {
|
||||
const data = await userService.getUsers(
|
||||
1,
|
||||
10,
|
||||
"displayName",
|
||||
true,
|
||||
filters,
|
||||
);
|
||||
if (data) {
|
||||
setLoaded(true);
|
||||
setPagedData(data);
|
||||
} else {
|
||||
setLoaded(false);
|
||||
}
|
||||
};
|
||||
|
||||
void loadInitial();
|
||||
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
return (
|
||||
<Loading loaded={loaded}>
|
||||
|
||||
@ -14,7 +14,8 @@
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "preserve"
|
||||
"jsx": "preserve",
|
||||
"allowImportingTsExtensions": true
|
||||
},
|
||||
"include": ["src", "src/types", "i18next-parser.config.js"]
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user