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 {
|
.two-column-grid-1-1 {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 1fr;
|
grid-template-columns: 1fr 1fr;
|
||||||
grid-gap: $gridGap;
|
grid-gap: $gridGap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.two-column-grid-1-3 {
|
.two-column-grid-1-3 {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 3fr;
|
grid-template-columns: 1fr 3fr;
|
||||||
grid-gap: $gridGap;
|
grid-gap: $gridGap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mail-types {
|
.mail-types {
|
||||||
padding-left: 0rem;
|
padding-left: 0rem;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
width: $mailtemplateNameListWidth;
|
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 {
|
interface HorizontalTabsProps {
|
||||||
children: JSX.Element[];
|
children: JSX.Element[];
|
||||||
|
initialTab?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const HorizontalTabs: React.FC<HorizontalTabsProps> = ({ children }) => {
|
const HorizontalTabs: React.FC<HorizontalTabsProps> = ({
|
||||||
|
children,
|
||||||
|
initialTab,
|
||||||
|
}) => {
|
||||||
const [activeTab, setActiveTab] = useState<string>("");
|
const [activeTab, setActiveTab] = useState<string>("");
|
||||||
|
|
||||||
// Set initial tab on mount
|
// Set initial tab on mount
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (children.length > 0) {
|
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) => {
|
const onClickTabItem = useCallback((tab: string) => {
|
||||||
setActiveTab((prev) => (prev !== tab ? tab : prev));
|
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 Joi from "joi";
|
||||||
import React from "react";
|
import React, { useEffect } from "react";
|
||||||
import { Navigate } from "react-router-dom";
|
import { Navigate, useParams } from "react-router-dom";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import Form from "../../../components/common/Form";
|
|
||||||
import { InputType } from "../../../components/common/Input";
|
import { InputType } from "../../../components/common/Input";
|
||||||
import { FormState } from "../../../components/common/Form";
|
import { useForm } from "../../../components/common/useForm";
|
||||||
import withRouter from "../../../utils/withRouter";
|
import {
|
||||||
|
renderInput,
|
||||||
|
renderButton,
|
||||||
|
renderError,
|
||||||
|
renderSelect,
|
||||||
|
renderInputNumber,
|
||||||
|
renderInputTextarea,
|
||||||
|
renderGlossaryPicker,
|
||||||
|
renderSequencePicker,
|
||||||
|
} from "../../../components/common/formHelpers";
|
||||||
import { MakeGeneralIdRef } from "../../../utils/GeneralIdRef";
|
import { MakeGeneralIdRef } from "../../../utils/GeneralIdRef";
|
||||||
import customFieldsService, {
|
import customFieldsService, {
|
||||||
numberParams,
|
numberParams,
|
||||||
@ -19,25 +27,31 @@ import {
|
|||||||
} from "../glossary/services/glossaryService";
|
} from "../glossary/services/glossaryService";
|
||||||
import Loading from "../../../components/common/Loading";
|
import Loading from "../../../components/common/Loading";
|
||||||
|
|
||||||
interface CustomFieldDetailsState extends FormState {
|
interface CustomFieldDetailsProps {
|
||||||
data: {
|
editMode?: boolean;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class CustomFieldDetails extends Form<any, any, CustomFieldDetailsState> {
|
const CustomFieldDetails: React.FC<CustomFieldDetailsProps> = ({
|
||||||
state: CustomFieldDetailsState = {
|
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,
|
loaded: false,
|
||||||
data: {
|
data: {
|
||||||
name: "",
|
name: "",
|
||||||
@ -54,29 +68,14 @@ class CustomFieldDetails extends Form<any, any, CustomFieldDetailsState> {
|
|||||||
},
|
},
|
||||||
errors: {},
|
errors: {},
|
||||||
redirect: "",
|
redirect: "",
|
||||||
};
|
});
|
||||||
|
|
||||||
labelName = "Name";
|
form.schema = {
|
||||||
labelFieldType = "Field Type";
|
name: Joi.string().required().max(450).label(labelName),
|
||||||
labelMultiLine = "Multi-line";
|
fieldType: Joi.string().required().label(labelFieldType),
|
||||||
labelDefaultValue = "Default Value";
|
multiLine: Joi.boolean().label(labelMultiLine),
|
||||||
labelMinValue = "Minimum Value";
|
minEntries: Joi.number().min(0).label(labelMinEntries),
|
||||||
labelMaxValue = "Maximum Value";
|
maxEntries: Joi.number().empty("").label(labelMaxEntries),
|
||||||
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),
|
|
||||||
refElementId: Joi.when("fieldType", {
|
refElementId: Joi.when("fieldType", {
|
||||||
is: Joi.string().valid("Sequence"),
|
is: Joi.string().valid("Sequence"),
|
||||||
then: Joi.object({
|
then: Joi.object({
|
||||||
@ -98,12 +97,12 @@ class CustomFieldDetails extends Form<any, any, CustomFieldDetailsState> {
|
|||||||
)
|
)
|
||||||
.required(),
|
.required(),
|
||||||
}),
|
}),
|
||||||
minValue: Joi.number().allow("").label(this.labelMinValue),
|
minValue: Joi.number().allow("").label(labelMinValue),
|
||||||
maxValue: Joi.number().allow("").label(this.labelMaxValue),
|
maxValue: Joi.number().allow("").label(labelMaxValue),
|
||||||
step: Joi.number().optional().allow("").min(0).label(this.labelStep),
|
step: Joi.number().optional().allow("").min(0).label(labelStep),
|
||||||
required: Joi.boolean().label(this.labelRequired),
|
required: Joi.boolean().label(labelRequired),
|
||||||
|
|
||||||
//defaultValue: Joi.string().allow("").label(this.labelDefaultValue)
|
//defaultValue: Joi.string().allow("").label(labelDefaultValue)
|
||||||
|
|
||||||
defaultValue: Joi.when("fieldType", {
|
defaultValue: Joi.when("fieldType", {
|
||||||
is: Joi.string().valid("Number"),
|
is: Joi.string().valid("Number"),
|
||||||
@ -114,7 +113,7 @@ class CustomFieldDetails extends Form<any, any, CustomFieldDetailsState> {
|
|||||||
.min(Joi.ref("minValue"))
|
.min(Joi.ref("minValue"))
|
||||||
.message(
|
.message(
|
||||||
'"Default Value" must be greater than or equal to "' +
|
'"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"))
|
.max(Joi.ref("maxValue"))
|
||||||
.message(
|
.message(
|
||||||
'"Default Value" must be less than or equal to "' +
|
'"Default Value" must be less than or equal to "' +
|
||||||
this.labelMaxValue +
|
labelMaxValue +
|
||||||
'"',
|
'"',
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
.allow(""),
|
.allow(""),
|
||||||
otherwise: Joi.string().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 {
|
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 } =
|
let { refElementId, defaultValue, minEntries, maxEntries, required } =
|
||||||
this.state.data;
|
form.state.data;
|
||||||
let numberParams: numberParams | undefined = undefined;
|
let numberParams: numberParams | undefined = undefined;
|
||||||
let textParams: textParams | undefined = undefined;
|
let textParams: textParams | undefined = undefined;
|
||||||
let params;
|
let params;
|
||||||
let refElementIdValue: GeneralIdRef | undefined;
|
let refElementIdValue: GeneralIdRef | undefined;
|
||||||
|
|
||||||
switch (fieldType) {
|
switch (fieldTypeStr) {
|
||||||
case "Sequence":
|
case "Sequence":
|
||||||
minEntries = 1;
|
minEntries = 1;
|
||||||
maxEntries = 1;
|
maxEntries = 1;
|
||||||
@ -171,15 +243,31 @@ class CustomFieldDetails extends Form<any, any, CustomFieldDetailsState> {
|
|||||||
case "Text":
|
case "Text":
|
||||||
minEntries = 1;
|
minEntries = 1;
|
||||||
maxEntries = 1;
|
maxEntries = 1;
|
||||||
let { multiLine } = this.state.data;
|
let { multiLine } = form.state.data;
|
||||||
textParams = { multiLine };
|
textParams = { multiLine: Boolean(multiLine) };
|
||||||
params = textParams;
|
params = textParams;
|
||||||
refElementIdValue = undefined;
|
refElementIdValue = undefined;
|
||||||
break;
|
break;
|
||||||
case "Number":
|
case "Number":
|
||||||
refElementIdValue = undefined;
|
refElementIdValue = undefined;
|
||||||
let { minValue, maxValue, step } = this.state.data;
|
let { minValue, maxValue, step } = form.state.data;
|
||||||
numberParams = { minValue, maxValue, step };
|
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;
|
params = numberParams;
|
||||||
minEntries = required ? 1 : 0;
|
minEntries = required ? 1 : 0;
|
||||||
maxEntries = 1;
|
maxEntries = 1;
|
||||||
@ -188,19 +276,30 @@ class CustomFieldDetails extends Form<any, any, CustomFieldDetailsState> {
|
|||||||
refElementIdValue = undefined;
|
refElementIdValue = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const minEntriesValue =
|
||||||
|
typeof minEntries === "number"
|
||||||
|
? minEntries
|
||||||
|
: minEntries === undefined || minEntries === null || minEntries === ""
|
||||||
|
? 0
|
||||||
|
: Number(minEntries);
|
||||||
const cleanMaxEntries: Number | undefined =
|
const cleanMaxEntries: Number | undefined =
|
||||||
maxEntries === "" ? undefined : Number(maxEntries);
|
maxEntries === "" ? undefined : Number(maxEntries);
|
||||||
|
|
||||||
if (this.isEditMode()) {
|
const defaultValueStr =
|
||||||
const { customFieldId } = this.props.router.params;
|
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(
|
const response = await customFieldsService.putField(
|
||||||
generalIdRef,
|
generalIdRef,
|
||||||
name,
|
nameStr,
|
||||||
fieldType,
|
fieldTypeStr,
|
||||||
defaultValue,
|
defaultValueStr,
|
||||||
minEntries,
|
minEntriesValue,
|
||||||
cleanMaxEntries,
|
cleanMaxEntries,
|
||||||
refElementIdValue,
|
refElementIdValue,
|
||||||
params,
|
params,
|
||||||
@ -210,10 +309,10 @@ class CustomFieldDetails extends Form<any, any, CustomFieldDetailsState> {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const response = await customFieldsService.postField(
|
const response = await customFieldsService.postField(
|
||||||
name,
|
nameStr,
|
||||||
fieldType,
|
fieldTypeStr,
|
||||||
defaultValue,
|
defaultValueStr,
|
||||||
minEntries,
|
minEntriesValue,
|
||||||
cleanMaxEntries,
|
cleanMaxEntries,
|
||||||
refElementIdValue,
|
refElementIdValue,
|
||||||
params,
|
params,
|
||||||
@ -223,262 +322,324 @@ class CustomFieldDetails extends Form<any, any, CustomFieldDetailsState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buttonName === this.labelSave)
|
if (buttonName === "save") form.setState({ redirect: "/customfields" });
|
||||||
this.setState({ redirect: "/customfields" });
|
|
||||||
} catch (ex: any) {
|
} catch (ex: any) {
|
||||||
this.handleGeneralError(ex);
|
form.handleGeneralError(ex);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
isEditMode = () => {
|
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||||
const { editMode } = this.props;
|
form.handleSubmit(e, doSubmit);
|
||||||
return editMode;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount = async () => {
|
if (form.state.redirect) return <Navigate to={form.state.redirect} />;
|
||||||
const { customFieldId } = this.props.router.params;
|
|
||||||
|
|
||||||
if (customFieldId !== undefined) {
|
const { fieldType } = form.state.data;
|
||||||
try {
|
const fieldTypeValue = typeof fieldType === "string" ? fieldType : "";
|
||||||
const loadedData = await customFieldsService.getField(customFieldId);
|
|
||||||
|
|
||||||
const { data } = this.state;
|
let mode = "Add";
|
||||||
if (loadedData) {
|
if (isEditMode()) mode = "Edit";
|
||||||
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,
|
|
||||||
};
|
|
||||||
|
|
||||||
data.refElementId = [convertedRefElementId];
|
const fieldTypeOptions: Option[] = [
|
||||||
data.required = loadedData.minEntries > 0;
|
{ _id: "Text", name: "Text" },
|
||||||
break;
|
{ _id: "Number", name: "Number" },
|
||||||
case "Sequence":
|
{ _id: "Sequence", name: "Sequence" },
|
||||||
data.refElementId = loadedData.refElementId;
|
{ _id: "FormTemplate", name: "Form Template" },
|
||||||
break;
|
{ _id: "Glossary", name: "Glossary" },
|
||||||
case "Domain":
|
{ _id: "Domain", name: "Domain" },
|
||||||
data.required = loadedData.minEntries > 0;
|
];
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (loadedData.parameters !== undefined) {
|
switch (fieldTypeValue) {
|
||||||
switch (data.fieldType) {
|
case "Sequence":
|
||||||
case "Number":
|
labelRefElementId = "Sequence";
|
||||||
data.required = loadedData.minEntries > 0;
|
break;
|
||||||
const parameters: numberParams = JSON.parse(
|
case "FormTemplate":
|
||||||
loadedData.parameters,
|
labelRefElementId = "Form";
|
||||||
);
|
break;
|
||||||
data.minValue = parameters.minValue ?? undefined;
|
case "Glossary":
|
||||||
data.maxValue = parameters.maxValue ?? undefined;
|
labelRefElementId = "Glossary";
|
||||||
data.step = parameters.step ?? undefined;
|
break;
|
||||||
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>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
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 React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { useSearchParams } from "react-router-dom";
|
||||||
import HorizontalTabs from "../../../components/common/HorizionalTabs";
|
import HorizontalTabs from "../../../components/common/HorizionalTabs";
|
||||||
import Tab from "../../../components/common/Tab";
|
import Tab from "../../../components/common/Tab";
|
||||||
import authentication from "../../frame/services/authenticationService";
|
import authentication from "../../frame/services/authenticationService";
|
||||||
@ -13,11 +14,15 @@ interface DomainsDetailsProps {
|
|||||||
|
|
||||||
const DomainsDetails: React.FC<DomainsDetailsProps> = ({ editMode }) => {
|
const DomainsDetails: React.FC<DomainsDetailsProps> = ({ editMode }) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const [searchParams] = useSearchParams();
|
||||||
|
|
||||||
const canViewMailTemplates = authentication.hasAccess("ViewDomain");
|
const canViewMailTemplates = authentication.hasAccess("ViewDomain");
|
||||||
const canViewSecurityRoles = authentication.hasAccess("ViewRole");
|
const canViewSecurityRoles = authentication.hasAccess("ViewRole");
|
||||||
|
|
||||||
const heading = editMode ? t("EditDomain") : t("AddDomain");
|
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[] = [];
|
const tabs: JSX.Element[] = [];
|
||||||
|
|
||||||
@ -38,7 +43,7 @@ const DomainsDetails: React.FC<DomainsDetailsProps> = ({ editMode }) => {
|
|||||||
if (canViewSecurityRoles) {
|
if (canViewSecurityRoles) {
|
||||||
tabs.push(
|
tabs.push(
|
||||||
<Tab key={3} label={t("SecurityRoles")}>
|
<Tab key={3} label={t("SecurityRoles")}>
|
||||||
<SecurityRolesTab />
|
<SecurityRolesTab initialRoleId={roleId} initialInnerTab={innerTab} />
|
||||||
</Tab>,
|
</Tab>,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -47,7 +52,7 @@ const DomainsDetails: React.FC<DomainsDetailsProps> = ({ editMode }) => {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h1>{heading}</h1>
|
<h1>{heading}</h1>
|
||||||
<HorizontalTabs>{tabs}</HorizontalTabs>
|
<HorizontalTabs initialTab={initialTab}>{tabs}</HorizontalTabs>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,82 +1,89 @@
|
|||||||
import Joi from "joi";
|
import Joi from "joi";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Navigate } from "react-router-dom";
|
import { Navigate, useParams } from "react-router-dom";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import Form, { FormState } from "../../../../components/common/Form";
|
import { useForm } from "../../../../components/common/useForm";
|
||||||
import { GeneralIdRef, MakeGeneralIdRef } from "../../../../utils/GeneralIdRef";
|
import { MakeGeneralIdRef } from "../../../../utils/GeneralIdRef";
|
||||||
import withRouter, { RouterProps } from "../../../../utils/withRouter";
|
|
||||||
import roleService from "../serrvices/rolesService";
|
import roleService from "../serrvices/rolesService";
|
||||||
import Loading from "../../../../components/common/Loading";
|
import Loading from "../../../../components/common/Loading";
|
||||||
|
import {
|
||||||
|
renderError,
|
||||||
|
renderButton,
|
||||||
|
renderUserPicker,
|
||||||
|
} from "../../../../components/common/formHelpers";
|
||||||
|
|
||||||
interface LocAddUserToRoleProps extends RouterProps {
|
interface LocAddUserToRoleProps {
|
||||||
isEditMode : boolean;
|
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: {
|
data: {
|
||||||
userId?: GeneralIdRef;
|
userId: undefined,
|
||||||
};
|
},
|
||||||
redirect: string;
|
errors: {},
|
||||||
}
|
redirect: "",
|
||||||
|
});
|
||||||
|
|
||||||
class LocAddUserToRole extends Form<LocAddUserToRoleProps, any, LocAddUserToRoleState> {
|
form.schema = {
|
||||||
state: LocAddUserToRoleState = {
|
userId: Joi.any().required().label(labelUserId),
|
||||||
loaded: true,
|
};
|
||||||
data: {
|
|
||||||
//userId: null;
|
|
||||||
},
|
|
||||||
errors: {},
|
|
||||||
redirect: "",
|
|
||||||
};
|
|
||||||
|
|
||||||
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";
|
if (buttonName === labelSave)
|
||||||
labelSave = "Save and close";
|
form.setState({
|
||||||
|
redirect: `/domains/edit/${domainId}?tab=SecurityRoles&roleId=${roleId}&innerTab=Users`,
|
||||||
|
});
|
||||||
schema = {
|
}
|
||||||
userId: Joi.any().required().label(this.labelUserId),
|
} catch (ex: any) {
|
||||||
};
|
form.handleGeneralError(ex);
|
||||||
|
|
||||||
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>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
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;
|
export default AddUserToRole;
|
||||||
|
|||||||
@ -1,130 +1,172 @@
|
|||||||
import Joi from "joi";
|
import Joi from "joi";
|
||||||
import React from "react";
|
import React, { useEffect } from "react";
|
||||||
import { Navigate } from "react-router-dom";
|
import { Navigate } from "react-router-dom";
|
||||||
import { toast } from "react-toastify";
|
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 { InputType } from "../../../../components/common/Input";
|
||||||
import { MakeGeneralIdRef } from "../../../../utils/GeneralIdRef";
|
import { MakeGeneralIdRef } from "../../../../utils/GeneralIdRef";
|
||||||
import withRouter from "../../../../utils/withRouter";
|
|
||||||
import mailTemplatesService from "../serrvices/mailTemplatesService";
|
import mailTemplatesService from "../serrvices/mailTemplatesService";
|
||||||
import Loading from "../../../../components/common/Loading";
|
import {
|
||||||
|
renderError,
|
||||||
|
renderButton,
|
||||||
|
renderInput,
|
||||||
|
renderTemplateEditor,
|
||||||
|
} from "../../../../components/common/formHelpers";
|
||||||
|
|
||||||
interface EmailTemplateEditorProps{
|
interface EmailTemplateEditorProps {
|
||||||
domainId : number,
|
domainId?: string;
|
||||||
currentMailType : 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: {
|
data: {
|
||||||
currentMailType? : string
|
currentMailType: undefined,
|
||||||
isOverridden : boolean
|
isOverridden: false,
|
||||||
subject: string;
|
subject: "",
|
||||||
definition: string;
|
definition: "",
|
||||||
};
|
},
|
||||||
redirect: string;
|
errors: {},
|
||||||
}
|
redirect: "",
|
||||||
|
});
|
||||||
|
|
||||||
class EmailTemplateEditor extends Form<EmailTemplateEditorProps, any, EmailTemplateEditorState> {
|
form.schema = {
|
||||||
state: EmailTemplateEditorState = {
|
currentMailType: Joi.optional(),
|
||||||
loaded : false,
|
isOverridden: Joi.optional(),
|
||||||
data: {
|
subject: Joi.string().required().max(450).label(labelName),
|
||||||
currentMailType : undefined,
|
definition: Joi.string().required().label(labelDefinition),
|
||||||
isOverridden : false,
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const loadTemplate = async () => {
|
||||||
|
try {
|
||||||
|
if (!domainId) return;
|
||||||
|
|
||||||
|
// Reset form state while loading
|
||||||
|
form.setState({
|
||||||
|
loaded: false,
|
||||||
|
data: {
|
||||||
|
currentMailType: undefined,
|
||||||
|
isOverridden: false,
|
||||||
subject: "",
|
subject: "",
|
||||||
definition: "",
|
definition: "",
|
||||||
},
|
},
|
||||||
errors: {},
|
});
|
||||||
redirect: "",
|
|
||||||
};
|
|
||||||
|
|
||||||
labelName = "Subject";
|
const domainIdValue = BigInt(domainId);
|
||||||
labelDefinition = "Definition";
|
var mailTemplate = await mailTemplatesService.getTemplate(
|
||||||
|
MakeGeneralIdRef(domainIdValue),
|
||||||
labelApply = "Save";
|
currentMailType,
|
||||||
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>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
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 Joi from "joi";
|
||||||
import React from "react";
|
import React, { useEffect } from "react";
|
||||||
import { Navigate } from "react-router-dom";
|
import { Navigate, useParams } from "react-router-dom";
|
||||||
import { toast } from "react-toastify";
|
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 { InputType } from "../../../../components/common/Input";
|
||||||
import { GeneralIdRef, MakeGeneralIdRef } from "../../../../utils/GeneralIdRef";
|
import { MakeGeneralIdRef } from "../../../../utils/GeneralIdRef";
|
||||||
import withRouter, { RouterProps } from "../../../../utils/withRouter";
|
|
||||||
import domainsService from "../serrvices/domainsService";
|
import domainsService from "../serrvices/domainsService";
|
||||||
import Loading from "../../../../components/common/Loading";
|
import Loading from "../../../../components/common/Loading";
|
||||||
|
import {
|
||||||
|
renderError,
|
||||||
|
renderButton,
|
||||||
|
renderInput,
|
||||||
|
renderSsoProviderPicker,
|
||||||
|
} from "../../../../components/common/formHelpers";
|
||||||
|
|
||||||
interface GeneralTabProps extends RouterProps {
|
interface GeneralTabProps {
|
||||||
isEditMode: boolean;
|
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: {
|
data: {
|
||||||
name: string;
|
name: "",
|
||||||
ssoProviderId: GeneralIdRef | null;
|
ssoProviderId: null,
|
||||||
sunriseHostName: string;
|
sunriseHostName: "",
|
||||||
sunriseAppId: string;
|
sunriseAppId: "",
|
||||||
sunriseCategoryId: string;
|
sunriseCategoryId: "",
|
||||||
sigmaId: bigint | null;
|
sigmaId: null,
|
||||||
};
|
},
|
||||||
redirect: string;
|
errors: {},
|
||||||
}
|
redirect: "",
|
||||||
|
});
|
||||||
|
|
||||||
class LocGeneralTab extends Form<GeneralTabProps, any, GeneralTabState> {
|
form.schema = {
|
||||||
state: GeneralTabState = {
|
name: Joi.string().required().max(450).label(labelName),
|
||||||
loaded: false,
|
ssoProviderId: Joi.object().allow(null).optional().label(labelSsoProvider),
|
||||||
data: {
|
sunriseHostName: Joi.string()
|
||||||
name: "",
|
.required()
|
||||||
ssoProviderId: null,
|
.allow("")
|
||||||
sunriseHostName: "",
|
.max(16)
|
||||||
sunriseAppId: "",
|
.label(labelSunriseHostName),
|
||||||
sunriseCategoryId: "",
|
sunriseAppId: Joi.string().required().allow("").label(labelSunriseAppId),
|
||||||
sigmaId: null,
|
sunriseCategoryId: Joi.string()
|
||||||
},
|
.required()
|
||||||
errors: {},
|
.allow("")
|
||||||
redirect: "",
|
.label(labelSunriseCategoryId),
|
||||||
};
|
sigmaId: Joi.number().allow(null).optional().label(labelSigmaId),
|
||||||
|
};
|
||||||
|
|
||||||
labelName = "Name";
|
const doSubmit = async (buttonName: string) => {
|
||||||
labelSsoProvider = "Sso Provider";
|
try {
|
||||||
labelSunriseHostName = "e-flow hostname";
|
const {
|
||||||
labelSunriseAppId = "e-flow AppId";
|
name,
|
||||||
labelSunriseCategoryId = "e-flow CategoryId";
|
ssoProviderId,
|
||||||
labelSigmaId = "Sigma Id";
|
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";
|
if (isEditMode) {
|
||||||
labelSave = "Save and close";
|
var generalIdRef = MakeGeneralIdRef(BigInt(domainId!));
|
||||||
|
const response = await domainsService.putDomain(
|
||||||
schema = {
|
generalIdRef,
|
||||||
name: Joi.string().required().max(450).label(this.labelName),
|
nameStr,
|
||||||
ssoProviderId: Joi.object().allow(null).optional().label(this.labelSsoProvider),
|
sunriseHostNameStr,
|
||||||
sunriseHostName: Joi.string().required().allow("").max(16).label(this.labelSunriseHostName),
|
sunriseAppIdStr,
|
||||||
sunriseAppId: Joi.string().required().allow("").label(this.labelSunriseAppId),
|
sunriseCategoryIdStr,
|
||||||
sunriseCategoryId: Joi.string().required().allow("").label(this.labelSunriseCategoryId),
|
ssoProviderId as any,
|
||||||
sigmaId: Joi.number().allow(null).optional().label(this.labelSigmaId),
|
sigmaIdValue,
|
||||||
};
|
|
||||||
|
|
||||||
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 (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;
|
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 { useParams } from "react-router-dom";
|
||||||
import mailTemplatesService from "../serrvices/mailTemplatesService";
|
import mailTemplatesService from "../serrvices/mailTemplatesService";
|
||||||
import HOCEmailTemplateEditor from "./EmailTemplateEditor";
|
import HOCEmailTemplateEditor from "./EmailTemplateEditor";
|
||||||
@ -10,7 +10,7 @@ interface MailType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const MailTemplatesTab: React.FC = () => {
|
const MailTemplatesTab: React.FC = () => {
|
||||||
const [loaded, setLoaded] = useState(false);
|
const [loaded, setLoaded] = useState(true);
|
||||||
const [currentMailType, setCurrentMailType] = useState("");
|
const [currentMailType, setCurrentMailType] = useState("");
|
||||||
const [types, setTypes] = useState<MailType[]>([]);
|
const [types, setTypes] = useState<MailType[]>([]);
|
||||||
|
|
||||||
@ -22,21 +22,23 @@ const MailTemplatesTab: React.FC = () => {
|
|||||||
setTypes(nextTypes);
|
setTypes(nextTypes);
|
||||||
|
|
||||||
if (nextTypes.length > 0) {
|
if (nextTypes.length > 0) {
|
||||||
setLoaded(true);
|
|
||||||
setCurrentMailType(nextTypes[0].mailType);
|
setCurrentMailType(nextTypes[0].mailType);
|
||||||
}
|
}
|
||||||
|
setLoaded(true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void loadTypes();
|
void loadTypes();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const selectTemplate = (emailType: string) => {
|
const selectTemplate = useCallback(
|
||||||
if (currentMailType !== emailType) {
|
(emailType: string) => {
|
||||||
setLoaded(true);
|
if (currentMailType !== emailType) {
|
||||||
setCurrentMailType(emailType);
|
setCurrentMailType(emailType);
|
||||||
}
|
}
|
||||||
};
|
},
|
||||||
|
[currentMailType],
|
||||||
|
);
|
||||||
|
|
||||||
const onClick = (e: React.MouseEvent<HTMLElement>) => {
|
const onClick = (e: React.MouseEvent<HTMLElement>) => {
|
||||||
const value = (e.target as HTMLElement).getAttribute("value");
|
const value = (e.target as HTMLElement).getAttribute("value");
|
||||||
@ -54,7 +56,12 @@ const MailTemplatesTab: React.FC = () => {
|
|||||||
<ul className="mail-types">
|
<ul className="mail-types">
|
||||||
{types.map((x) => {
|
{types.map((x) => {
|
||||||
return (
|
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}
|
{x.description}
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,129 +1,134 @@
|
|||||||
import Joi from "joi";
|
import Joi from "joi";
|
||||||
import React from "react";
|
import React, { useEffect } from "react";
|
||||||
import { Navigate } from "react-router-dom";
|
import { Navigate, useParams } from "react-router-dom";
|
||||||
import { toast } from "react-toastify";
|
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 { InputType } from "../../../../components/common/Input";
|
||||||
import { MakeGeneralIdRef } from "../../../../utils/GeneralIdRef";
|
import { MakeGeneralIdRef } from "../../../../utils/GeneralIdRef";
|
||||||
import withRouter, { RouterProps } from "../../../../utils/withRouter";
|
|
||||||
import roleService from "../serrvices/rolesService";
|
import roleService from "../serrvices/rolesService";
|
||||||
import Loading from "../../../../components/common/Loading";
|
import Loading from "../../../../components/common/Loading";
|
||||||
|
import {
|
||||||
|
renderError,
|
||||||
|
renderButton,
|
||||||
|
renderInput,
|
||||||
|
} from "../../../../components/common/formHelpers";
|
||||||
|
|
||||||
interface RolesDetailsProps extends RouterProps {
|
interface RolesDetailsProps {
|
||||||
isEditMode : boolean;
|
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: {
|
data: {
|
||||||
name: string;
|
name: "",
|
||||||
};
|
},
|
||||||
redirect: string;
|
errors: {},
|
||||||
}
|
redirect: "",
|
||||||
|
});
|
||||||
|
|
||||||
class LocRolesDetails extends Form<RolesDetailsProps, any, RolesDetailsState> {
|
form.schema = {
|
||||||
state: RolesDetailsState = {
|
name: Joi.string().required().max(450).label(labelName),
|
||||||
loaded: false,
|
};
|
||||||
data: {
|
|
||||||
name: ""
|
|
||||||
},
|
|
||||||
errors: {},
|
|
||||||
redirect: "",
|
|
||||||
};
|
|
||||||
|
|
||||||
labelName = "Name";
|
const doSubmit = async (buttonName: string) => {
|
||||||
|
try {
|
||||||
|
const { name } = form.state.data;
|
||||||
|
const nameStr = typeof name === "string" ? name : "";
|
||||||
|
|
||||||
labelApply = "Save";
|
var domainIdGeneralIdRef = MakeGeneralIdRef(BigInt(domainId!));
|
||||||
labelSave = "Save and close";
|
|
||||||
|
|
||||||
|
|
||||||
schema = {
|
if (isEditMode) {
|
||||||
name: Joi.string().required().max(450).label(this.labelName),
|
var generalIdRef = MakeGeneralIdRef(BigInt(roleId!));
|
||||||
};
|
const response = await roleService.putRole(generalIdRef, nameStr);
|
||||||
|
if (response) {
|
||||||
doSubmit = async (buttonName : string) => {
|
toast.info("Role edited");
|
||||||
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 });
|
|
||||||
}
|
}
|
||||||
catch(ex: any) {
|
} else {
|
||||||
this.handleGeneralError(ex);
|
const response = await roleService.postRole(
|
||||||
}
|
domainIdGeneralIdRef,
|
||||||
};
|
nameStr,
|
||||||
|
|
||||||
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>
|
|
||||||
);
|
);
|
||||||
|
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;
|
export default RolesDetails;
|
||||||
|
|||||||
@ -22,12 +22,14 @@ interface RolesEditorProps {
|
|||||||
selectedRole?: GetRoleResponse;
|
selectedRole?: GetRoleResponse;
|
||||||
onSelectRole?: (keyValue: any) => void;
|
onSelectRole?: (keyValue: any) => void;
|
||||||
onUnselectRole?: () => void;
|
onUnselectRole?: () => void;
|
||||||
|
initialRoleId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const RolesEditor: React.FC<RolesEditorProps> = ({
|
const RolesEditor: React.FC<RolesEditorProps> = ({
|
||||||
selectedRole,
|
selectedRole,
|
||||||
onSelectRole,
|
onSelectRole,
|
||||||
onUnselectRole,
|
onUnselectRole,
|
||||||
|
initialRoleId,
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [loaded, setLoaded] = useState(false);
|
const [loaded, setLoaded] = useState(false);
|
||||||
@ -74,7 +76,19 @@ const RolesEditor: React.FC<RolesEditorProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
void loadInitial();
|
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 onSort = async (nextSortColumn: Column<GetRoleResponse>) => {
|
||||||
const { page, pageSize } = pagedData;
|
const { page, pageSize } = pagedData;
|
||||||
|
|||||||
@ -8,7 +8,15 @@ import UserRoleEditor from "./UserRoleEditor";
|
|||||||
import { GetRoleResponse } from "../serrvices/rolesService";
|
import { GetRoleResponse } from "../serrvices/rolesService";
|
||||||
import authentication from "../../../frame/services/authenticationService";
|
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 { t } = useTranslation();
|
||||||
const [selectedRole, setSelectedRole] = useState<GetRoleResponse | undefined>(
|
const [selectedRole, setSelectedRole] = useState<GetRoleResponse | undefined>(
|
||||||
undefined,
|
undefined,
|
||||||
@ -49,12 +57,13 @@ const SecurityRolesTab: React.FC = () => {
|
|||||||
selectedRole={selectedRole}
|
selectedRole={selectedRole}
|
||||||
onSelectRole={onSelectRow}
|
onSelectRole={onSelectRow}
|
||||||
onUnselectRole={onUnselectRow}
|
onUnselectRole={onUnselectRow}
|
||||||
|
initialRoleId={initialRoleId}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{selectedRole !== undefined &&
|
{selectedRole !== undefined &&
|
||||||
(canViewRoleAccess || canViewRoleUsers) && (
|
(canViewRoleAccess || canViewRoleUsers) && (
|
||||||
<HorizontalTabs>{tabs}</HorizontalTabs>
|
<HorizontalTabs initialTab={initialInnerTab}>{tabs}</HorizontalTabs>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -78,7 +78,7 @@ const UserRoleEditor: React.FC<UserRoleEditorProps> = ({ role }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void loadInitial();
|
void loadInitial();
|
||||||
}, [getRoleUsers, role?.id, sortColumn]);
|
}, [getRoleUsers]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||||
|
|
||||||
const changePage = async (page: number, pageSize: number) => {
|
const changePage = async (page: number, pageSize: number) => {
|
||||||
await getRoleUsers(page, pageSize, sortColumn, filters);
|
await getRoleUsers(page, pageSize, sortColumn, filters);
|
||||||
|
|||||||
@ -94,8 +94,18 @@ const Forms: React.FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
changePage(pagedData.page, pagedData.pageSize);
|
const loadInitial = async () => {
|
||||||
}, [changePage, pagedData.page, pagedData.pageSize]);
|
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 (
|
return (
|
||||||
<Loading loaded={loaded}>
|
<Loading loaded={loaded}>
|
||||||
|
|||||||
@ -1,141 +1,142 @@
|
|||||||
import Joi from "joi";
|
import Joi from "joi";
|
||||||
import React from "react";
|
import React, { useEffect } from "react";
|
||||||
import { Navigate } from "react-router-dom";
|
import { Navigate, useParams } from "react-router-dom";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import Form from "../../../components/common/Form";
|
import { useForm } from "../../../components/common/useForm";
|
||||||
import { InputType } from "../../../components/common/Input";
|
import { InputType } from "../../../components/common/Input";
|
||||||
import { FormState } from "../../../components/common/Form";
|
|
||||||
import withRouter from "../../../utils/withRouter";
|
|
||||||
import { MakeGeneralIdRef } from "../../../utils/GeneralIdRef";
|
import { MakeGeneralIdRef } from "../../../utils/GeneralIdRef";
|
||||||
import formsService from "./services/formsService";
|
import formsService from "./services/formsService";
|
||||||
import Loading from "../../../components/common/Loading";
|
import Loading from "../../../components/common/Loading";
|
||||||
// import Tab from "../../../components/common/Tab";
|
import {
|
||||||
// import HorizontalTabs from "../../../components/common/HorizionalTabs";
|
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: {
|
data: {
|
||||||
name: string;
|
name: "",
|
||||||
definition: string;
|
definition: "",
|
||||||
};
|
},
|
||||||
redirect: string;
|
errors: {},
|
||||||
}
|
redirect: "",
|
||||||
|
});
|
||||||
|
|
||||||
class FormsDetails extends Form<any, any, FormsDetailsState> {
|
form.schema = {
|
||||||
state: FormsDetailsState = {
|
name: Joi.string().required().max(450).label(labelName),
|
||||||
loaded: false,
|
definition: Joi.string().required().label(labelDefinition),
|
||||||
data: {
|
};
|
||||||
name: "",
|
|
||||||
definition: "",
|
|
||||||
},
|
|
||||||
errors: {},
|
|
||||||
redirect: "",
|
|
||||||
};
|
|
||||||
|
|
||||||
labelName = "Name";
|
useEffect(() => {
|
||||||
labelDefinition = "Definition";
|
const loadData = async () => {
|
||||||
|
if (formId !== undefined) {
|
||||||
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) => {
|
|
||||||
try {
|
try {
|
||||||
const { name, definition } = this.state.data;
|
const loadedData = await formsService.getForm(BigInt(formId));
|
||||||
|
|
||||||
if (this.isEditMode()) {
|
if (loadedData) {
|
||||||
const { formId } = this.props.router.params;
|
const newData = { ...form.state.data };
|
||||||
|
newData.name = loadedData.name;
|
||||||
|
newData.definition = loadedData.definition;
|
||||||
|
|
||||||
var generalIdRef = MakeGeneralIdRef(formId);
|
form.setState({ loaded: true, data: newData });
|
||||||
const response = await formsService.putForm(generalIdRef, name, definition);
|
} else {
|
||||||
if (response) {
|
form.setState({ loaded: false });
|
||||||
toast.info("Form template edited");
|
}
|
||||||
}
|
} catch (ex: any) {
|
||||||
} else {
|
form.handleGeneralError(ex);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!editMode) form.setState({ loaded: true });
|
||||||
};
|
};
|
||||||
|
|
||||||
isEditMode = () => {
|
loadData();
|
||||||
const { editMode } = this.props;
|
}, [formId, editMode]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||||
return editMode;
|
|
||||||
};
|
|
||||||
|
|
||||||
componentDidMount = async () => {
|
const doSubmit = async (buttonName: string) => {
|
||||||
const { formId } = this.props.router.params;
|
try {
|
||||||
|
const { name, definition } = form.state.data;
|
||||||
|
const nameStr = typeof name === "string" ? name : "";
|
||||||
|
const definitionStr = typeof definition === "string" ? definition : "";
|
||||||
|
|
||||||
if (formId !== undefined) {
|
if (editMode) {
|
||||||
try {
|
var generalIdRef = MakeGeneralIdRef(BigInt(formId!));
|
||||||
const loadedData = await formsService.getForm(formId);
|
const response = await formsService.putForm(
|
||||||
|
generalIdRef,
|
||||||
const { data } = this.state;
|
nameStr,
|
||||||
if (loadedData) {
|
definitionStr,
|
||||||
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 (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 Joi from "joi";
|
||||||
import React from "react";
|
import React, { useEffect } from "react";
|
||||||
import { Navigate } from "react-router-dom";
|
import { Navigate, useParams } from "react-router-dom";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import Form from "../../../components/common/Form";
|
import { useForm } from "../../../components/common/useForm";
|
||||||
import { InputType } from "../../../components/common/Input";
|
import { InputType } from "../../../components/common/Input";
|
||||||
import { FormState } from "../../../components/common/Form";
|
import { GeneralIdRef, MakeGeneralIdRef } from "../../../utils/GeneralIdRef";
|
||||||
import withRouter from "../../../utils/withRouter";
|
import glossariesService, {
|
||||||
import { MakeGeneralIdRef } from "../../../utils/GeneralIdRef";
|
CustomFieldValue,
|
||||||
import glossariesService, { Glossary, SystemGlossaries } from "./services/glossaryService";
|
Glossary,
|
||||||
|
SystemGlossaries,
|
||||||
|
} from "./services/glossaryService";
|
||||||
import { CustomField } from "../customfields/services/customFieldsService";
|
import { CustomField } from "../customfields/services/customFieldsService";
|
||||||
import Loading from "../../../components/common/Loading";
|
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: {
|
data: {
|
||||||
id? : bigint,
|
id: undefined,
|
||||||
guid? : string,
|
guid: undefined,
|
||||||
name: string,
|
name: "",
|
||||||
parent?: Glossary,
|
parent: undefined,
|
||||||
childCustomFieldDefinition : CustomField[]
|
childCustomFieldDefinition: [],
|
||||||
};
|
},
|
||||||
redirect: string;
|
errors: {},
|
||||||
}
|
redirect: "",
|
||||||
|
});
|
||||||
|
|
||||||
class GlossariesDetails extends Form<any, any, GlossariesState> {
|
form.schema = {
|
||||||
state: GlossariesState = {
|
id: Joi.optional(),
|
||||||
loaded: false,
|
guid: Joi.optional(),
|
||||||
data: {
|
name: Joi.string().required().max(450).label(labelName),
|
||||||
id: undefined,
|
parent: Joi.optional(),
|
||||||
guid: undefined,
|
childCustomFieldDefinition: Joi.optional().label(
|
||||||
name: "",
|
labelChildCustomFieldDefinition,
|
||||||
parent : undefined,
|
),
|
||||||
childCustomFieldDefinition : []
|
};
|
||||||
},
|
|
||||||
errors: {},
|
|
||||||
redirect: "",
|
|
||||||
};
|
|
||||||
|
|
||||||
labelName = "Name";
|
useEffect(() => {
|
||||||
labelParent = "Parent"
|
const loadData = async () => {
|
||||||
labelChildCustomFieldDefinition = "Custom field for child entries"
|
const newData = { ...form.state.data };
|
||||||
|
|
||||||
labelApply = "Save";
|
if (editMode) {
|
||||||
labelSave = "Save and close";
|
const generalIdRef = MakeGeneralIdRef(BigInt(glossaryId!));
|
||||||
|
|
||||||
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) => {
|
|
||||||
try {
|
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()) {
|
form.setCustomFieldValues(
|
||||||
const generalIdRef = MakeGeneralIdRef(id, guid);
|
newData,
|
||||||
|
loadedData.customFieldValues,
|
||||||
const response = await glossariesService.putGlossaryItem(generalIdRef, parent, name, childCustomFieldDefinition, customfieldValues);
|
parentGlossary?.childCustomFieldDefinition ?? [],
|
||||||
if (response) {
|
);
|
||||||
toast.info("Glossary Item edited");
|
}
|
||||||
}
|
} catch (ex: any) {
|
||||||
} else {
|
form.handleGeneralError(ex);
|
||||||
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 });
|
|
||||||
}
|
}
|
||||||
catch(ex: any) {
|
} else {
|
||||||
this.handleGeneralError(ex);
|
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 = () => {
|
loadData();
|
||||||
const { editMode } = this.props;
|
}, [glossaryId, editMode]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||||
return editMode;
|
|
||||||
};
|
|
||||||
|
|
||||||
componentDidMount = async () => {
|
const handleAdd = (customfield: CustomField) => {
|
||||||
const { data } = this.state;
|
const newData = { ...form.state.data };
|
||||||
|
const childDefs =
|
||||||
|
(newData.childCustomFieldDefinition as CustomField[]) ?? [];
|
||||||
|
childDefs.push(customfield);
|
||||||
|
newData.childCustomFieldDefinition = childDefs;
|
||||||
|
|
||||||
if (this.isEditMode()) {
|
form.setState({ data: newData });
|
||||||
const { glossaryId } = this.props.router.params;
|
};
|
||||||
|
|
||||||
const generalIdRef = MakeGeneralIdRef(glossaryId);
|
const handleDelete = (fieldToDelete: CustomField) => {
|
||||||
try {
|
const newData = { ...form.state.data };
|
||||||
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 ?? [];
|
|
||||||
|
|
||||||
this.setCustomFieldValues(data, loadedData.customFieldValues, (data.parent as Glossary)?.childCustomFieldDefinition);
|
if (fieldToDelete) {
|
||||||
}
|
const childDefs =
|
||||||
}
|
(newData.childCustomFieldDefinition as CustomField[]) ?? [];
|
||||||
catch(ex: any) {
|
newData.childCustomFieldDefinition = childDefs.filter(
|
||||||
this.handleGeneralError(ex);
|
(x) => x !== fieldToDelete,
|
||||||
}
|
);
|
||||||
}
|
|
||||||
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 });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleDelete = ( fieldToDelete : CustomField ) => {
|
form.setState({ data: newData });
|
||||||
let { data } = this.state;
|
};
|
||||||
|
|
||||||
if (fieldToDelete){
|
const doSubmit = async (buttonName: string) => {
|
||||||
data.childCustomFieldDefinition = data.childCustomFieldDefinition.filter( x => x !== fieldToDelete);
|
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() {
|
if (editMode) {
|
||||||
const { loaded, redirect, data } = this.state;
|
const generalIdRef = MakeGeneralIdRef(idValue, guidValue);
|
||||||
if (redirect !== "") return <Navigate to={redirect} />;
|
|
||||||
|
|
||||||
let mode = "Add";
|
const response = await glossariesService.putGlossaryItem(
|
||||||
const isEditMode = this.isEditMode();
|
generalIdRef,
|
||||||
if (isEditMode) mode = "Edit";
|
parentGlossary
|
||||||
|
? MakeGeneralIdRef(parentGlossary.id, parentGlossary.guid)
|
||||||
return (
|
: undefined,
|
||||||
<Loading loaded={loaded}>
|
nameStr,
|
||||||
<h1>{mode} Glossary Item</h1>
|
childDefs,
|
||||||
<form onSubmit={this.handleSubmit}>
|
customfieldValues,
|
||||||
{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>
|
|
||||||
);
|
);
|
||||||
|
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 { useTranslation } from "react-i18next";
|
||||||
import Button, { ButtonType } from "../../../components/common/Button";
|
import Button, { ButtonType } from "../../../components/common/Button";
|
||||||
import Column from "../../../components/common/columns";
|
import Column from "../../../components/common/columns";
|
||||||
@ -29,21 +29,24 @@ const Organisations: React.FC = () => {
|
|||||||
new Map<string, string>(),
|
new Map<string, string>(),
|
||||||
);
|
);
|
||||||
|
|
||||||
const changePage = async (page: number, pageSize: number) => {
|
const changePage = useCallback(
|
||||||
const data = await organisationsService.getOrganisations(
|
async (page: number, pageSize: number) => {
|
||||||
page,
|
const data = await organisationsService.getOrganisations(
|
||||||
pageSize,
|
page,
|
||||||
sortColumn.key,
|
pageSize,
|
||||||
sortColumn.order === "asc",
|
sortColumn.key,
|
||||||
filters,
|
sortColumn.order === "asc",
|
||||||
);
|
filters,
|
||||||
if (data) {
|
);
|
||||||
setLoaded(true);
|
if (data) {
|
||||||
setPagedData(data);
|
setLoaded(true);
|
||||||
} else {
|
setPagedData(data);
|
||||||
setLoaded(false);
|
} else {
|
||||||
}
|
setLoaded(false);
|
||||||
};
|
}
|
||||||
|
},
|
||||||
|
[filters, sortColumn.key, sortColumn.order],
|
||||||
|
);
|
||||||
|
|
||||||
const onSort = async (newSortColumn: Column<ReadOrganisation>) => {
|
const onSort = async (newSortColumn: Column<ReadOrganisation>) => {
|
||||||
const { page, pageSize } = pagedData;
|
const { page, pageSize } = pagedData;
|
||||||
@ -96,9 +99,24 @@ const Organisations: React.FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const { page, pageSize } = pagedData;
|
const loadInitial = async () => {
|
||||||
changePage(page, pageSize);
|
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 (
|
return (
|
||||||
<Loading loaded={loaded}>
|
<Loading loaded={loaded}>
|
||||||
|
|||||||
@ -1,140 +1,175 @@
|
|||||||
import Joi from "joi";
|
import Joi from "joi";
|
||||||
import React from "react";
|
import React, { useEffect } from "react";
|
||||||
import { Navigate } from "react-router-dom";
|
import { Navigate, useParams } from "react-router-dom";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import Form from "../../../components/common/Form";
|
import { useForm } from "../../../components/common/useForm";
|
||||||
import { InputType } from "../../../components/common/Input";
|
import { InputType } from "../../../components/common/Input";
|
||||||
import { FormState } from "../../../components/common/Form";
|
|
||||||
import withRouter from "../../../utils/withRouter";
|
|
||||||
import { MakeGeneralIdRef } from "../../../utils/GeneralIdRef";
|
import { MakeGeneralIdRef } from "../../../utils/GeneralIdRef";
|
||||||
import Option from "../../../components/common/option";
|
import Option from "../../../components/common/option";
|
||||||
import organisationsService from "./services/organisationsService";
|
import organisationsService from "./services/organisationsService";
|
||||||
import Loading from "../../../components/common/Loading";
|
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: {
|
data: {
|
||||||
name: string;
|
name: "",
|
||||||
address: string;
|
address: "",
|
||||||
status: string;
|
status: "Active",
|
||||||
};
|
},
|
||||||
redirect: string;
|
errors: {},
|
||||||
organisationStatusOptions: Option[];
|
redirect: "",
|
||||||
}
|
});
|
||||||
|
|
||||||
class OrganisationsDetails extends Form<any, any, OrganisationsDetailsState> {
|
form.schema = {
|
||||||
state: OrganisationsDetailsState = {
|
name: Joi.string().required().max(450).label(labelName),
|
||||||
loaded: false,
|
address: Joi.string().required().max(450).label(labelAddress),
|
||||||
data: {
|
status: Joi.string().required().max(450).label(labelStatus),
|
||||||
name: "",
|
};
|
||||||
address: "",
|
|
||||||
status: "Active"
|
|
||||||
},
|
|
||||||
errors: {},
|
|
||||||
redirect: "",
|
|
||||||
organisationStatusOptions: [
|
|
||||||
{ _id: "Active", name: "Active" },
|
|
||||||
{ _id: "Pending", name: "Pending" },
|
|
||||||
{ _id: "Blocked", name: "Blocked" },
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
labelName = "Name";
|
useEffect(() => {
|
||||||
labelAddress = "Address";
|
const loadData = async () => {
|
||||||
labelStatus = "Status";
|
if (organisationId !== undefined) {
|
||||||
|
|
||||||
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) => {
|
|
||||||
try {
|
try {
|
||||||
const { name, address, status } = this.state.data;
|
const loadedData = await organisationsService.getOrganisation(
|
||||||
|
BigInt(organisationId),
|
||||||
if (this.isEditMode()) {
|
);
|
||||||
const { organisationId } = this.props.router.params;
|
|
||||||
|
|
||||||
var generalIdRef = MakeGeneralIdRef(organisationId);
|
if (loadedData) {
|
||||||
const response = await organisationsService.putOrganisation(generalIdRef, name, address, status);
|
const newData = { ...form.state.data };
|
||||||
if (response) {
|
newData.name = loadedData.name;
|
||||||
toast.info("Organisation edited");
|
newData.address = loadedData.address;
|
||||||
}
|
newData.status = loadedData.status;
|
||||||
} else {
|
|
||||||
const response = await organisationsService.postOrganisation(name, address, status);
|
|
||||||
if (response) {
|
|
||||||
toast.info("New Organisation added");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buttonName === this.labelSave)
|
form.setState({ loaded: true, data: newData });
|
||||||
this.setState({ redirect: "/organisations" });
|
} else {
|
||||||
}
|
form.setState({ loaded: false });
|
||||||
catch(ex: any) {
|
}
|
||||||
this.handleGeneralError(ex);
|
} catch (ex: any) {
|
||||||
|
form.handleGeneralError(ex);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!editMode) form.setState({ loaded: true });
|
||||||
};
|
};
|
||||||
|
|
||||||
isEditMode = () => {
|
loadData();
|
||||||
const { editMode } = this.props;
|
}, [organisationId, editMode]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||||
return editMode;
|
|
||||||
};
|
|
||||||
|
|
||||||
componentDidMount = async () => {
|
const doSubmit = async (buttonName: string) => {
|
||||||
const { organisationId } = this.props.router.params;
|
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) {
|
if (editMode) {
|
||||||
try
|
var generalIdRef = MakeGeneralIdRef(BigInt(organisationId!));
|
||||||
{
|
const response = await organisationsService.putOrganisation(
|
||||||
const loadedData = await organisationsService.getOrganisation(organisationId);
|
generalIdRef,
|
||||||
|
nameStr,
|
||||||
const { data } = this.state;
|
addressStr,
|
||||||
if (loadedData) {
|
statusStr,
|
||||||
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 (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 Joi from "joi";
|
||||||
import React from "react";
|
import React, { useEffect } from "react";
|
||||||
import { Navigate } from "react-router-dom";
|
import { Navigate, useParams } from "react-router-dom";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import Form from "../../../components/common/Form";
|
import { useForm } from "../../../components/common/useForm";
|
||||||
import { InputType } from "../../../components/common/Input";
|
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 sequenceService from "./services/sequenceService";
|
||||||
import Option from "../../../components/common/option";
|
import Option from "../../../components/common/option";
|
||||||
import withRouter from "../../../utils/withRouter";
|
|
||||||
import { MakeGeneralIdRef } from "../../../utils/GeneralIdRef";
|
import { MakeGeneralIdRef } from "../../../utils/GeneralIdRef";
|
||||||
import Loading from "../../../components/common/Loading";
|
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: {
|
data: {
|
||||||
name: string;
|
name: "",
|
||||||
seed: number;
|
seed: 1,
|
||||||
increment: number;
|
increment: 1,
|
||||||
pattern: string;
|
pattern: "[0]",
|
||||||
rolloverType: string;
|
rolloverType: "Continuous",
|
||||||
};
|
},
|
||||||
redirect: string;
|
errors: {},
|
||||||
}
|
redirect: "",
|
||||||
|
});
|
||||||
|
|
||||||
class SequenceDetails extends Form<any, any, SequenceDetailsState> {
|
form.schema = {
|
||||||
state: SequenceDetailsState = {
|
name: Joi.string().required().max(450).label(labelName),
|
||||||
loaded : false,
|
seed: Joi.number().required().label(labelSeed),
|
||||||
data: {
|
increment: Joi.number().required().label(labelIncrement),
|
||||||
name: "",
|
pattern: Joi.string().required().label(labelPattern),
|
||||||
seed: 1,
|
rolloverType: Joi.string().required().label(labelRolloverType),
|
||||||
increment: 1,
|
};
|
||||||
pattern: "[0]",
|
|
||||||
rolloverType: "Continuous",
|
|
||||||
},
|
|
||||||
errors: {},
|
|
||||||
redirect: "",
|
|
||||||
};
|
|
||||||
|
|
||||||
labelName = "Name";
|
useEffect(() => {
|
||||||
labelSeed = "Seed";
|
const loadData = async () => {
|
||||||
labelIncrement = "Increment";
|
if (sequenceId !== undefined) {
|
||||||
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) => {
|
|
||||||
try {
|
try {
|
||||||
const { name, seed, increment, pattern, rolloverType } = this.state.data;
|
const loadedData = await sequenceService.getSequence(
|
||||||
|
BigInt(sequenceId),
|
||||||
if (this.isEditMode()) {
|
);
|
||||||
const { sequenceId } = this.props.router.params;
|
if (loadedData) {
|
||||||
|
const newData = { ...form.state.data };
|
||||||
var generalIdRef = MakeGeneralIdRef(sequenceId);
|
newData.increment = loadedData.increment;
|
||||||
const response = await sequenceService.putSequence(generalIdRef, name, seed, increment, pattern, rolloverType);
|
newData.name = loadedData.name;
|
||||||
if (response) {
|
newData.pattern = loadedData.pattern;
|
||||||
toast.info("Sequence edited");
|
newData.rolloverType = loadedData.rolloverType;
|
||||||
}
|
newData.seed = loadedData.seed;
|
||||||
} else {
|
form.setState({ loaded: true, data: newData });
|
||||||
const response = await sequenceService.postSequence(name, seed, increment, pattern, rolloverType);
|
} else {
|
||||||
if (response) {
|
form.setState({ loaded: false });
|
||||||
toast.info("New sequence added");
|
}
|
||||||
}
|
} catch (ex: any) {
|
||||||
}
|
form.handleGeneralError(ex);
|
||||||
|
|
||||||
if (buttonName === this.labelSave)
|
|
||||||
this.setState({ redirect: "/sequence" });
|
|
||||||
}
|
|
||||||
catch(ex: any) {
|
|
||||||
this.handleGeneralError(ex);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!editMode) {
|
||||||
|
form.setState({ loaded: true });
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
isEditMode = () => {
|
loadData();
|
||||||
const { editMode } = this.props;
|
}, [sequenceId, editMode]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||||
return editMode;
|
|
||||||
};
|
|
||||||
|
|
||||||
componentDidMount = async () => {
|
const doSubmit = async (buttonName: string) => {
|
||||||
const { sequenceId } = this.props.router.params;
|
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) {
|
if (editMode) {
|
||||||
try {
|
const generalIdRef = MakeGeneralIdRef(
|
||||||
const loadedData = await sequenceService.getSequence(sequenceId);
|
sequenceId ? BigInt(sequenceId) : undefined,
|
||||||
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>
|
|
||||||
);
|
);
|
||||||
|
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(() => {
|
useEffect(() => {
|
||||||
changePage(pagedData.page, pagedData.pageSize);
|
const loadInitial = async () => {
|
||||||
}, [changePage, pagedData.page, pagedData.pageSize]);
|
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 (
|
return (
|
||||||
<Loading loaded={loaded}>
|
<Loading loaded={loaded}>
|
||||||
|
|||||||
@ -1,143 +1,186 @@
|
|||||||
import Joi from "joi";
|
import Joi from "joi";
|
||||||
import React from "react";
|
import React, { useEffect } from "react";
|
||||||
import { Navigate } from "react-router-dom";
|
import { Navigate, useParams } from "react-router-dom";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import Form from "../../../components/common/Form";
|
import { useForm } from "../../../components/common/useForm";
|
||||||
import { InputType } from "../../../components/common/Input";
|
import { InputType } from "../../../components/common/Input";
|
||||||
import { FormState } from "../../../components/common/Form";
|
import {
|
||||||
import withRouter from "../../../utils/withRouter";
|
renderInput,
|
||||||
|
renderButton,
|
||||||
|
renderError,
|
||||||
|
renderSelect,
|
||||||
|
} from "../../../components/common/formHelpers";
|
||||||
import { MakeGeneralIdRef } from "../../../utils/GeneralIdRef";
|
import { MakeGeneralIdRef } from "../../../utils/GeneralIdRef";
|
||||||
import Option from "../../../components/common/option";
|
import Option from "../../../components/common/option";
|
||||||
import siteService from "./services/sitessService";
|
import siteService from "./services/sitessService";
|
||||||
import Loading from "../../../components/common/Loading";
|
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: {
|
data: {
|
||||||
name: string;
|
name: "",
|
||||||
address: string;
|
address: "",
|
||||||
status: string;
|
status: "Active",
|
||||||
};
|
},
|
||||||
redirect: string;
|
errors: {},
|
||||||
organisationStatusOptions: Option[];
|
redirect: "",
|
||||||
}
|
});
|
||||||
|
|
||||||
class LocSiteDetails extends Form<any, any, SiteDetailsState> {
|
form.schema = {
|
||||||
state: SiteDetailsState = {
|
name: Joi.string().required().max(450).label(labelName),
|
||||||
loaded : false,
|
address: Joi.string().required().max(450).label(labelAddress),
|
||||||
data: {
|
status: Joi.string().required().max(450).label(labelStatus),
|
||||||
name: "",
|
};
|
||||||
address: "",
|
|
||||||
status: "Active"
|
|
||||||
},
|
|
||||||
errors: {},
|
|
||||||
redirect: "",
|
|
||||||
organisationStatusOptions: [
|
|
||||||
{ _id: "Active", name: "Active" },
|
|
||||||
{ _id: "Pending", name: "Pending" },
|
|
||||||
{ _id: "Blocked", name: "Blocked" },
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
labelName = "Name";
|
useEffect(() => {
|
||||||
labelAddress = "Address";
|
const loadData = async () => {
|
||||||
labelStatus = "Status";
|
if (siteId !== undefined) {
|
||||||
|
|
||||||
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) => {
|
|
||||||
try {
|
try {
|
||||||
const { name, address, status } = this.state.data;
|
const loadedData = await siteService.getSite(BigInt(siteId));
|
||||||
|
if (loadedData) {
|
||||||
const { organisationId } = this.props.router.params;
|
const newData = { ...form.state.data };
|
||||||
var organisationGeneralIdRef = MakeGeneralIdRef(organisationId);
|
newData.name = loadedData.name;
|
||||||
|
newData.address = loadedData.address;
|
||||||
if (this.isEditMode()) {
|
newData.status = loadedData.status;
|
||||||
const { siteId } = this.props.router.params;
|
form.setState({ loaded: true, data: newData });
|
||||||
var siteGeneralIdRef = MakeGeneralIdRef(siteId);
|
} else {
|
||||||
|
form.setState({ loaded: false });
|
||||||
const resposne = await siteService.putSite(siteGeneralIdRef, name, address, status, organisationGeneralIdRef);
|
}
|
||||||
if (resposne) {
|
} catch (ex: any) {
|
||||||
toast.info("Site edited");
|
form.handleGeneralError(ex);
|
||||||
}
|
|
||||||
} 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);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!editMode) {
|
||||||
|
form.setState({ loaded: true });
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
isEditMode = () => {
|
loadData();
|
||||||
const { editMode } = this.props;
|
}, [siteId, editMode]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||||
return editMode;
|
|
||||||
};
|
|
||||||
|
|
||||||
componentDidMount = async () => {
|
const doSubmit = async (buttonName: string) => {
|
||||||
const { siteId } = this.props.router.params;
|
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) {
|
if (editMode) {
|
||||||
try
|
const siteGeneralIdRef = MakeGeneralIdRef(
|
||||||
{
|
siteId ? BigInt(siteId) : undefined,
|
||||||
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>
|
|
||||||
);
|
);
|
||||||
}
|
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;
|
export default SiteDetails;
|
||||||
|
|||||||
@ -71,8 +71,28 @@ const Sites: React.FC = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
void changePage(initialPagedData.page, initialPagedData.pageSize);
|
const loadInitial = async () => {
|
||||||
}, [changePage, organisationId]);
|
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(
|
const onSort = useCallback(
|
||||||
async (nextSortColumn: Column<ReadSite>) => {
|
async (nextSortColumn: Column<ReadSite>) => {
|
||||||
@ -94,7 +114,8 @@ const Sites: React.FC = () => {
|
|||||||
setLoaded(false);
|
setLoaded(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[filters, pagedData, updateFiltersWithOrganisationId],
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
[filters, updateFiltersWithOrganisationId],
|
||||||
);
|
);
|
||||||
|
|
||||||
const onSearch = useCallback(
|
const onSearch = useCallback(
|
||||||
@ -118,9 +139,9 @@ const Sites: React.FC = () => {
|
|||||||
setLoaded(false);
|
setLoaded(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
[
|
[
|
||||||
filters,
|
filters,
|
||||||
pagedData,
|
|
||||||
sortColumn.key,
|
sortColumn.key,
|
||||||
sortColumn.order,
|
sortColumn.order,
|
||||||
updateFiltersWithOrganisationId,
|
updateFiltersWithOrganisationId,
|
||||||
@ -132,7 +153,7 @@ const Sites: React.FC = () => {
|
|||||||
await siteService.deleteSite(item?.id, item?.guid);
|
await siteService.deleteSite(item?.id, item?.guid);
|
||||||
await changePage(pagedData.page, pagedData.pageSize);
|
await changePage(pagedData.page, pagedData.pageSize);
|
||||||
},
|
},
|
||||||
[changePage, pagedData.page, pagedData.pageSize],
|
[changePage], // eslint-disable-line react-hooks/exhaustive-deps
|
||||||
);
|
);
|
||||||
|
|
||||||
const translatedSortColumn = useMemo(
|
const translatedSortColumn = useMemo(
|
||||||
|
|||||||
@ -68,8 +68,26 @@ const Specifications: React.FC = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
void changePage(initialPagedData.page, initialPagedData.pageSize);
|
const loadInitial = async () => {
|
||||||
}, [changePage, siteId]);
|
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(
|
const onSort = useCallback(
|
||||||
async (nextSortColumn: Column<ReadSpecification>) => {
|
async (nextSortColumn: Column<ReadSpecification>) => {
|
||||||
@ -91,7 +109,8 @@ const Specifications: React.FC = () => {
|
|||||||
setLoaded(false);
|
setLoaded(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[filters, pagedData, updateFiltersWithSiteId],
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
[filters, updateFiltersWithSiteId],
|
||||||
);
|
);
|
||||||
|
|
||||||
const onSearch = useCallback(
|
const onSearch = useCallback(
|
||||||
@ -115,13 +134,8 @@ const Specifications: React.FC = () => {
|
|||||||
setLoaded(false);
|
setLoaded(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
filters,
|
[filters, sortColumn.key, sortColumn.order, updateFiltersWithSiteId],
|
||||||
pagedData,
|
|
||||||
sortColumn.key,
|
|
||||||
sortColumn.order,
|
|
||||||
updateFiltersWithSiteId,
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const onDelete = useCallback(
|
const onDelete = useCallback(
|
||||||
@ -134,7 +148,8 @@ const Specifications: React.FC = () => {
|
|||||||
await changePage(pagedData.page, pagedData.pageSize);
|
await changePage(pagedData.page, pagedData.pageSize);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[changePage, pagedData.page, pagedData.pageSize],
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
[changePage],
|
||||||
);
|
);
|
||||||
|
|
||||||
const translatedSortColumn = useMemo(
|
const translatedSortColumn = useMemo(
|
||||||
|
|||||||
@ -1,198 +1,292 @@
|
|||||||
import Joi from "joi";
|
import Joi from "joi";
|
||||||
import React from "react";
|
import React, { useEffect, useRef, useState, useCallback } from "react";
|
||||||
import { Navigate } from "react-router-dom";
|
import { Navigate, useParams } from "react-router-dom";
|
||||||
import { toast } from "react-toastify";
|
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 { InputType } from "../../../components/common/Input";
|
||||||
import Loading from "../../../components/common/Loading";
|
import Loading from "../../../components/common/Loading";
|
||||||
import TemplateFiller from "../../../components/common/TemplateFiller";
|
import TemplateFiller from "../../../components/common/TemplateFiller";
|
||||||
import { GeneralIdRef, MakeGeneralIdRef } from "../../../utils/GeneralIdRef";
|
import { GeneralIdRef, MakeGeneralIdRef } from "../../../utils/GeneralIdRef";
|
||||||
import withRouter from "../../../utils/withRouter";
|
import {
|
||||||
import { CustomFieldValue, PrintSpecificationsGlossary } from "../glossary/services/glossaryService";
|
CustomFieldValue,
|
||||||
|
PrintSpecificationsGlossary,
|
||||||
|
} from "../glossary/services/glossaryService";
|
||||||
import specificationService from "./services/specificationService";
|
import specificationService from "./services/specificationService";
|
||||||
|
import {
|
||||||
|
renderInput,
|
||||||
|
renderButton,
|
||||||
|
renderError,
|
||||||
|
renderGlossaryPicker,
|
||||||
|
} from "../../../components/common/formHelpers";
|
||||||
|
|
||||||
interface SpecificationsDetailsState extends FormState {
|
interface SpecificationsDetailsProps {
|
||||||
formTemplate?: GeneralIdRef;
|
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: {
|
data: {
|
||||||
name: string;
|
name: "",
|
||||||
printSpecifications?: CustomFieldValue[];
|
sigmaId: null as bigint | null,
|
||||||
formInstanceId?: GeneralIdRef;
|
printSpecifications: [] as CustomFieldValue[],
|
||||||
sigmaId: bigint | null;
|
formInstanceId: undefined,
|
||||||
};
|
},
|
||||||
redirect: string;
|
errors: {},
|
||||||
hasErrors: boolean;
|
redirect: "",
|
||||||
}
|
});
|
||||||
|
|
||||||
class LocSpecificationsDetails extends Form<any, any, SpecificationsDetailsState> {
|
const [formTemplate, setFormTemplate] = useState<GeneralIdRef | undefined>(
|
||||||
private TemplateFiller: React.RefObject<TemplateFiller>;
|
undefined,
|
||||||
|
);
|
||||||
|
const [hasErrors, setHasErrors] = useState(false);
|
||||||
|
|
||||||
constructor(props: any) {
|
form.schema = {
|
||||||
super(props);
|
name: Joi.string().required().max(450).label(labelName),
|
||||||
this.TemplateFiller = React.createRef<TemplateFiller>();
|
printSpecifications: Joi.optional(),
|
||||||
}
|
formInstanceId: Joi.optional(),
|
||||||
|
sigmaId: Joi.number().allow(null).label(labelSigmaId),
|
||||||
|
};
|
||||||
|
|
||||||
state: SpecificationsDetailsState = {
|
const isEditMode = () => editMode;
|
||||||
loaded: false,
|
|
||||||
formTemplate: undefined,
|
|
||||||
data: {
|
|
||||||
name: "",
|
|
||||||
sigmaId: null,
|
|
||||||
},
|
|
||||||
errors: {},
|
|
||||||
redirect: "",
|
|
||||||
hasErrors: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
labelName = "Name";
|
const loadFormTemplate = useCallback(
|
||||||
labelPrintSpecification = "Print Specification";
|
async (printSpecifications?: GeneralIdRef) => {
|
||||||
labelStatus = "Status";
|
const { data } = form.state;
|
||||||
labelSigmaId = "SigmaId";
|
const printSpecArray =
|
||||||
|
(data.printSpecifications as CustomFieldValue[]) || [];
|
||||||
|
|
||||||
labelApply = "Save";
|
if (printSpecArray && printSpecArray.length > 0) {
|
||||||
labelSave = "Save and close";
|
if (
|
||||||
|
((printSpecArray[0] as CustomFieldValue).value as GeneralIdRef).id ===
|
||||||
schema = {
|
BigInt(0)
|
||||||
name: Joi.string().required().max(450).label(this.labelName),
|
) {
|
||||||
printSpecifications: Joi.optional(),
|
data.printSpecifications = undefined;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
isEditMode = () => {
|
let template;
|
||||||
const { editMode } = this.props;
|
if (!printSpecArray || printSpecArray.length === 0) {
|
||||||
return editMode;
|
template = undefined;
|
||||||
};
|
} else {
|
||||||
|
template = await specificationService.GetTemplateForPrintSpec(
|
||||||
componentDidMount = async () => {
|
(printSpecArray[0] as CustomFieldValue).value as GeneralIdRef,
|
||||||
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>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
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;
|
export default SpecificationsDetails;
|
||||||
|
|||||||
@ -1,161 +1,291 @@
|
|||||||
import Joi from "joi";
|
import Joi from "joi";
|
||||||
import React from "react";
|
import React, { useEffect } from "react";
|
||||||
import { Navigate } from "react-router-dom";
|
import { Navigate, useParams, useLocation } from "react-router-dom";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import Form from "../../../components/common/Form";
|
import { useForm } from "../../../components/common/useForm";
|
||||||
import { InputType } from "../../../components/common/Input";
|
import { InputType } from "../../../components/common/Input";
|
||||||
import { FormState } from "../../../components/common/Form";
|
import {
|
||||||
import withRouter from "../../../utils/withRouter";
|
renderInput,
|
||||||
|
renderButton,
|
||||||
|
renderError,
|
||||||
|
} from "../../../components/common/formHelpers";
|
||||||
import { MakeGeneralIdRef } from "../../../utils/GeneralIdRef";
|
import { MakeGeneralIdRef } from "../../../utils/GeneralIdRef";
|
||||||
import Loading from "../../../components/common/Loading";
|
import Loading from "../../../components/common/Loading";
|
||||||
import ssoManagerService from "./services/ssoManagerService";
|
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: {
|
data: {
|
||||||
name: string;
|
name: "",
|
||||||
clientId: string,
|
clientId: "",
|
||||||
clientSecret: string,
|
clientSecret: "",
|
||||||
validIssuer: string,
|
validIssuer: "",
|
||||||
authorizationEndpoint: string,
|
authorizationEndpoint: "",
|
||||||
tokenEndpoint: string,
|
tokenEndpoint: "",
|
||||||
isPublic: boolean,
|
isPublic: true,
|
||||||
};
|
},
|
||||||
redirect: string;
|
errors: {},
|
||||||
}
|
redirect: "",
|
||||||
|
});
|
||||||
|
|
||||||
class SsoProviderDetails extends Form<any, any, SsoProviderDetailsState> {
|
form.schema = {
|
||||||
state: SsoProviderDetailsState = {
|
name: Joi.string().required().max(450).label(labelName),
|
||||||
loaded : false,
|
clientId: Joi.string().required().max(450).label(labelClientId),
|
||||||
data: {
|
clientSecret: Joi.string().required().max(450).label(labelClientSecret),
|
||||||
name: "",
|
validIssuer: Joi.string().required().max(450).label(labelValidIssuer),
|
||||||
clientId: "",
|
authorizationEndpoint: Joi.string()
|
||||||
clientSecret: "",
|
.required()
|
||||||
validIssuer: "",
|
.max(450)
|
||||||
authorizationEndpoint: "",
|
.label(labelAuthorizationEndpoint),
|
||||||
tokenEndpoint: "",
|
tokenEndpoint: Joi.string().required().max(450).label(labelTokenEndpoint),
|
||||||
isPublic: true,
|
isPublic: Joi.bool().required().label(labelIsPublic),
|
||||||
},
|
};
|
||||||
errors: {},
|
|
||||||
redirect: "",
|
|
||||||
};
|
|
||||||
|
|
||||||
labelName = "Name";
|
useEffect(() => {
|
||||||
labelClientId = "Client Id";
|
const loadData = async () => {
|
||||||
labelClientSecret = "Client Secret";
|
if (ssoProviderId !== undefined) {
|
||||||
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) => {
|
|
||||||
try {
|
try {
|
||||||
const { name, clientId, clientSecret, validIssuer, authorizationEndpoint, tokenEndpoint, isPublic } = this.state.data;
|
const loadedData = await ssoManagerService.getSsoProvider(
|
||||||
|
BigInt(ssoProviderId),
|
||||||
if (this.isEditMode()) {
|
);
|
||||||
const { ssoProviderId } = this.props.router.params;
|
if (loadedData) {
|
||||||
|
const newData = { ...form.state.data };
|
||||||
var generalIdRef = MakeGeneralIdRef(ssoProviderId);
|
newData.name = loadedData.name;
|
||||||
const response = await ssoManagerService.putSsoProvider(generalIdRef, name, clientId, clientSecret, validIssuer, authorizationEndpoint, tokenEndpoint, isPublic);
|
newData.clientId = loadedData.clientId;
|
||||||
if (response) {
|
newData.clientSecret = loadedData.clientSecret;
|
||||||
toast.info("Sso Provider edited");
|
newData.validIssuer = loadedData.validIssuer;
|
||||||
}
|
newData.authorizationEndpoint = loadedData.authorizationEndpoint;
|
||||||
} else {
|
newData.tokenEndpoint = loadedData.tokenEndpoint;
|
||||||
const response = await ssoManagerService.postSsoProvider(name, clientId, clientSecret, validIssuer, authorizationEndpoint, tokenEndpoint, isPublic);
|
newData.isPublic = loadedData.isPublic;
|
||||||
if (response) {
|
form.setState({ loaded: true, data: newData });
|
||||||
toast.info("New Sso Provider added");
|
} else {
|
||||||
}
|
form.setState({ loaded: false });
|
||||||
}
|
}
|
||||||
|
} catch (ex: any) {
|
||||||
if (buttonName === this.labelSave)
|
form.handleGeneralError(ex);
|
||||||
this.setState({ redirect: "/ssoManager" });
|
|
||||||
}
|
|
||||||
catch(ex: any) {
|
|
||||||
this.handleGeneralError(ex);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!editMode) {
|
||||||
|
form.setState({ loaded: true });
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
isEditMode = () => {
|
loadData();
|
||||||
const { editMode } = this.props;
|
}, [ssoProviderId, editMode]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||||
return editMode;
|
|
||||||
};
|
|
||||||
|
|
||||||
componentDidMount = async () => {
|
const doSubmit = async (buttonName: string) => {
|
||||||
const { ssoProviderId } = this.props.router.params;
|
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) {
|
if (editMode) {
|
||||||
try {
|
const generalIdRef = MakeGeneralIdRef(
|
||||||
const loadedData = await ssoManagerService.getSsoProvider(ssoProviderId);
|
ssoProviderId ? BigInt(ssoProviderId) : undefined,
|
||||||
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>
|
|
||||||
);
|
);
|
||||||
|
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(() => {
|
useEffect(() => {
|
||||||
changePage(pagedData.page, pagedData.pageSize);
|
const loadInitial = async () => {
|
||||||
}, [changePage, pagedData.page, pagedData.pageSize]);
|
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 (
|
return (
|
||||||
<Loading loaded={loaded}>
|
<Loading loaded={loaded}>
|
||||||
|
|||||||
@ -1,144 +1,238 @@
|
|||||||
import Joi from "joi";
|
import Joi from "joi";
|
||||||
import React from "react";
|
import React, { useEffect } from "react";
|
||||||
import { Navigate } from "react-router-dom";
|
import { Navigate, useParams } from "react-router-dom";
|
||||||
import { toast } from "react-toastify";
|
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 { InputType } from "../../../../components/common/Input";
|
||||||
import { GeneralIdRef, MakeGeneralIdRef } from "../../../../utils/GeneralIdRef";
|
import { GeneralIdRef, MakeGeneralIdRef } from "../../../../utils/GeneralIdRef";
|
||||||
import withRouter, { RouterProps } from "../../../../utils/withRouter";
|
|
||||||
import authentication from "../../../frame/services/authenticationService";
|
import authentication from "../../../frame/services/authenticationService";
|
||||||
import userService from "../services/usersService";
|
import userService from "../services/usersService";
|
||||||
import Loading from "../../../../components/common/Loading";
|
import Loading from "../../../../components/common/Loading";
|
||||||
import { CustomFieldValue } from "../../glossary/services/glossaryService";
|
import { CustomFieldValue } from "../../glossary/services/glossaryService";
|
||||||
|
import {
|
||||||
|
renderInput,
|
||||||
|
renderButton,
|
||||||
|
renderError,
|
||||||
|
renderDomainPicker,
|
||||||
|
} from "../../../../components/common/formHelpers";
|
||||||
|
|
||||||
interface GeneralTabProps extends RouterProps {
|
interface GeneralTabProps {
|
||||||
isEditMode: boolean;
|
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: {
|
data: {
|
||||||
firstName: string;
|
firstName: "",
|
||||||
lastName: string;
|
lastName: "",
|
||||||
middleNames: string;
|
middleNames: "",
|
||||||
email: string;
|
email: "",
|
||||||
domain: CustomFieldValue[];
|
domain: [] as CustomFieldValue[],
|
||||||
};
|
},
|
||||||
redirect: string;
|
errors: {},
|
||||||
}
|
redirect: "",
|
||||||
|
});
|
||||||
|
|
||||||
class LocGeneralTab extends Form<GeneralTabProps, any, GeneralTabState> {
|
form.schema = {
|
||||||
state: GeneralTabState = {
|
firstName: Joi.string().required().max(450).label(labelFirstName),
|
||||||
loaded: false,
|
middleNames: Joi.string().allow("").required().label(labelMiddleNames),
|
||||||
data: {
|
lastName: Joi.string().required().label(labelLastName),
|
||||||
firstName: "",
|
email: Joi.string()
|
||||||
lastName: "",
|
.required()
|
||||||
middleNames: "",
|
.email({ tlds: { allow: false } })
|
||||||
email: "",
|
.label(labelEmail),
|
||||||
domain: [],
|
domain: Joi.optional(),
|
||||||
},
|
};
|
||||||
errors: {},
|
|
||||||
redirect: "",
|
|
||||||
};
|
|
||||||
|
|
||||||
labelFirstName = "First name";
|
useEffect(() => {
|
||||||
labelMiddleNames = "Middle names";
|
const loadData = async () => {
|
||||||
labelLastName = "Last name";
|
const newData = { ...form.state.data };
|
||||||
labelEmail = "Mail";
|
|
||||||
labelDomain = "Domain";
|
|
||||||
|
|
||||||
labelApply = "Save";
|
if (userId !== undefined) {
|
||||||
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) => {
|
|
||||||
try {
|
try {
|
||||||
const { isEditMode } = this.props;
|
const loadedData = await userService.getUser(BigInt(userId));
|
||||||
|
if (loadedData) {
|
||||||
const { firstName, middleNames, lastName, email, domain } = this.state.data;
|
newData.firstName = loadedData.firstName;
|
||||||
|
newData.lastName = loadedData.lastName;
|
||||||
if (isEditMode) {
|
newData.middleNames = loadedData.middleNames;
|
||||||
const { userId } = this.props.router.params;
|
newData.email = loadedData.email;
|
||||||
|
newData.domain = [{ value: loadedData.domain } as CustomFieldValue];
|
||||||
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" });
|
|
||||||
} catch (ex: any) {
|
} 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 () => {
|
loadData();
|
||||||
const { userId } = this.props.router.params;
|
}, [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) {
|
if (isEditMode) {
|
||||||
try {
|
const generalIdRef = MakeGeneralIdRef(
|
||||||
const loadedData = await userService.getUser(userId);
|
userId ? BigInt(userId) : undefined,
|
||||||
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>
|
|
||||||
);
|
);
|
||||||
}
|
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;
|
export default GeneralTab;
|
||||||
|
|||||||
@ -102,8 +102,24 @@ const Users: React.FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
changePage(pagedData.page, pagedData.pageSize);
|
const loadInitial = async () => {
|
||||||
}, [changePage, pagedData.page, pagedData.pageSize]);
|
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 (
|
return (
|
||||||
<Loading loaded={loaded}>
|
<Loading loaded={loaded}>
|
||||||
|
|||||||
@ -14,7 +14,8 @@
|
|||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"jsx": "preserve"
|
"jsx": "preserve",
|
||||||
|
"allowImportingTsExtensions": true
|
||||||
},
|
},
|
||||||
"include": ["src", "src/types", "i18next-parser.config.js"]
|
"include": ["src", "src/types", "i18next-parser.config.js"]
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user