Working on the create activity page
This commit is contained in:
parent
6f328afbf2
commit
156d822cf5
@ -37,6 +37,7 @@
|
|||||||
"ConfirmEmailResent": "Confirm e-mail resent",
|
"ConfirmEmailResent": "Confirm e-mail resent",
|
||||||
"ConfirmPassword": "Confirm Password",
|
"ConfirmPassword": "Confirm Password",
|
||||||
"Continuous": "Continuous",
|
"Continuous": "Continuous",
|
||||||
|
"CreateActivity": "Create Activity",
|
||||||
"Created": "Created",
|
"Created": "Created",
|
||||||
"CustomField": "Custom Field",
|
"CustomField": "Custom Field",
|
||||||
"CustomFieldEdited": "Custom Field edited",
|
"CustomFieldEdited": "Custom Field edited",
|
||||||
|
|||||||
19
src/App.tsx
19
src/App.tsx
@ -46,6 +46,7 @@ import SsoProviderDetails from "./modules/manager/ssoManager/SsoProviderDetails"
|
|||||||
import { Namespaces } from "./i18n/i18n";
|
import { Namespaces } from "./i18n/i18n";
|
||||||
import WorkflowTemplateManager from "./modules/manager/workflowTemplates/WorkflowTemplateManager";
|
import WorkflowTemplateManager from "./modules/manager/workflowTemplates/WorkflowTemplateManager";
|
||||||
import WorkflowTemplateDetails from "./modules/manager/workflowTemplates/WorkflowTemplateDetails";
|
import WorkflowTemplateDetails from "./modules/manager/workflowTemplates/WorkflowTemplateDetails";
|
||||||
|
import CreateActivity from "./modules/manager/activity/CreateActivity";
|
||||||
|
|
||||||
function GetSecureRoutes() {
|
function GetSecureRoutes() {
|
||||||
const { t } = useTranslation(Namespaces.Common);
|
const { t } = useTranslation(Namespaces.Common);
|
||||||
@ -84,7 +85,6 @@ function GetSecureRoutes() {
|
|||||||
</Mainframe>
|
</Mainframe>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
path="/specifications/:organisationId/:siteId/add"
|
path="/specifications/:organisationId/:siteId/add"
|
||||||
element={
|
element={
|
||||||
@ -109,7 +109,6 @@ function GetSecureRoutes() {
|
|||||||
</Mainframe>
|
</Mainframe>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
path="/site/:organisationId/add"
|
path="/site/:organisationId/add"
|
||||||
element={
|
element={
|
||||||
@ -135,7 +134,6 @@ function GetSecureRoutes() {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Route path="/site/" element={<Navigate replace to="/404" />} />
|
<Route path="/site/" element={<Navigate replace to="/404" />} />
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
path="/organisations"
|
path="/organisations"
|
||||||
element={
|
element={
|
||||||
@ -160,7 +158,6 @@ function GetSecureRoutes() {
|
|||||||
</Mainframe>
|
</Mainframe>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Route path="/glossaries/add/" element={<Navigate replace to="/404" />} />
|
<Route path="/glossaries/add/" element={<Navigate replace to="/404" />} />
|
||||||
<Route
|
<Route
|
||||||
path="/glossaries/add/:glossaryId"
|
path="/glossaries/add/:glossaryId"
|
||||||
@ -198,7 +195,6 @@ function GetSecureRoutes() {
|
|||||||
</Mainframe>
|
</Mainframe>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
path="/forms/add"
|
path="/forms/add"
|
||||||
element={
|
element={
|
||||||
@ -223,7 +219,6 @@ function GetSecureRoutes() {
|
|||||||
</Mainframe>
|
</Mainframe>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
path="/customfields/add"
|
path="/customfields/add"
|
||||||
element={
|
element={
|
||||||
@ -248,7 +243,6 @@ function GetSecureRoutes() {
|
|||||||
</Mainframe>
|
</Mainframe>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
path="/sequence/add"
|
path="/sequence/add"
|
||||||
element={
|
element={
|
||||||
@ -273,7 +267,6 @@ function GetSecureRoutes() {
|
|||||||
</Mainframe>
|
</Mainframe>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
path="/domains/add"
|
path="/domains/add"
|
||||||
element={
|
element={
|
||||||
@ -322,7 +315,6 @@ function GetSecureRoutes() {
|
|||||||
</Mainframe>
|
</Mainframe>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
path="/users/add"
|
path="/users/add"
|
||||||
element={
|
element={
|
||||||
@ -347,7 +339,6 @@ function GetSecureRoutes() {
|
|||||||
</Mainframe>
|
</Mainframe>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
path="/ssoManager"
|
path="/ssoManager"
|
||||||
element={
|
element={
|
||||||
@ -388,6 +379,14 @@ function GetSecureRoutes() {
|
|||||||
</Mainframe>
|
</Mainframe>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<Route
|
||||||
|
path="/activity/createActivity"
|
||||||
|
element={
|
||||||
|
<Mainframe title={t("CreateActivity")}>
|
||||||
|
<CreateActivity />
|
||||||
|
</Mainframe>
|
||||||
|
}
|
||||||
|
/>
|
||||||
<Route
|
<Route
|
||||||
path="/workflowTemplates"
|
path="/workflowTemplates"
|
||||||
element={
|
element={
|
||||||
|
|||||||
@ -25,6 +25,7 @@ import Expando from "./expando";
|
|||||||
import ErrorBlock from "./ErrorBlock";
|
import ErrorBlock from "./ErrorBlock";
|
||||||
import SsoProviderPicker from "../pickers/SsoProviderPicker";
|
import SsoProviderPicker from "../pickers/SsoProviderPicker";
|
||||||
import { FormData, FormError } from "./useForm";
|
import { FormData, FormError } from "./useForm";
|
||||||
|
import WorkflowTemplatePicker from "../pickers/WorkflowTemplatePicker";
|
||||||
|
|
||||||
export const renderButton = (
|
export const renderButton = (
|
||||||
label: string,
|
label: string,
|
||||||
@ -575,6 +576,28 @@ export const renderTemplatePicker = (
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const renderWorkflowTemplatePicker = (
|
||||||
|
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 (
|
||||||
|
<WorkflowTemplatePicker
|
||||||
|
includeLabel={includeLabel}
|
||||||
|
name={name}
|
||||||
|
label={label}
|
||||||
|
value={templateValue}
|
||||||
|
error={errors[name]}
|
||||||
|
onChange={onChange}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const renderUserPicker = (
|
export const renderUserPicker = (
|
||||||
name: string,
|
name: string,
|
||||||
label: string,
|
label: string,
|
||||||
|
|||||||
@ -87,6 +87,10 @@ interface UseFormReturn {
|
|||||||
) => void;
|
) => void;
|
||||||
handleTemplateFormPickerChange: (name: string, value: GeneralIdRef) => void;
|
handleTemplateFormPickerChange: (name: string, value: GeneralIdRef) => void;
|
||||||
handleUserPickerChange: (name: string, value: GeneralIdRef) => void;
|
handleUserPickerChange: (name: string, value: GeneralIdRef) => void;
|
||||||
|
handleWorkflowTemplatePickerChange: (
|
||||||
|
name: string,
|
||||||
|
value: GeneralIdRef,
|
||||||
|
) => void;
|
||||||
handleSsoProviderPickerChange: (name: string, value: GeneralIdRef) => void;
|
handleSsoProviderPickerChange: (name: string, value: GeneralIdRef) => void;
|
||||||
handleToggleChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
handleToggleChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
||||||
setState: (updates: Partial<FormState>) => void;
|
setState: (updates: Partial<FormState>) => void;
|
||||||
@ -529,6 +533,17 @@ export const useForm = (initialState: FormState): UseFormReturn => {
|
|||||||
[state.data, validate, setState],
|
[state.data, validate, setState],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleWorkflowTemplatePickerChange = 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(
|
const handleUserPickerChange = useCallback(
|
||||||
(name: string, value: GeneralIdRef) => {
|
(name: string, value: GeneralIdRef) => {
|
||||||
const data: FormData = { ...state.data };
|
const data: FormData = { ...state.data };
|
||||||
@ -663,6 +678,7 @@ export const useForm = (initialState: FormState): UseFormReturn => {
|
|||||||
handleTemplateFormPickerChange,
|
handleTemplateFormPickerChange,
|
||||||
handleUserPickerChange,
|
handleUserPickerChange,
|
||||||
handleSsoProviderPickerChange,
|
handleSsoProviderPickerChange,
|
||||||
|
handleWorkflowTemplatePickerChange,
|
||||||
handleToggleChange,
|
handleToggleChange,
|
||||||
handleTasksChange,
|
handleTasksChange,
|
||||||
setState,
|
setState,
|
||||||
@ -693,6 +709,7 @@ export const useForm = (initialState: FormState): UseFormReturn => {
|
|||||||
handleTemplateFormPickerChange,
|
handleTemplateFormPickerChange,
|
||||||
handleUserPickerChange,
|
handleUserPickerChange,
|
||||||
handleSsoProviderPickerChange,
|
handleSsoProviderPickerChange,
|
||||||
|
handleWorkflowTemplatePickerChange,
|
||||||
handleToggleChange,
|
handleToggleChange,
|
||||||
handleTasksChange,
|
handleTasksChange,
|
||||||
setState,
|
setState,
|
||||||
|
|||||||
83
src/components/pickers/WorkflowTemplatePicker.tsx
Normal file
83
src/components/pickers/WorkflowTemplatePicker.tsx
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
import React, { useEffect, useState, useCallback } from "react";
|
||||||
|
import Select from "../common/Select";
|
||||||
|
import Option from "../common/option";
|
||||||
|
import { GeneralIdRef, MakeGeneralIdRef } from "../../utils/GeneralIdRef";
|
||||||
|
import templateVersionsService from "../../modules/manager/workflowTemplates/services/WorkflowTemplateService";
|
||||||
|
import ErrorBlock from "../common/ErrorBlock";
|
||||||
|
|
||||||
|
interface WorkflowTemplatePickerProps {
|
||||||
|
includeLabel?: boolean;
|
||||||
|
name: string;
|
||||||
|
label: string;
|
||||||
|
error?: string;
|
||||||
|
value?: GeneralIdRef;
|
||||||
|
onChange?: (name: string, value: GeneralIdRef) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function WorkflowTemplatePicker({
|
||||||
|
includeLabel,
|
||||||
|
name,
|
||||||
|
label,
|
||||||
|
error,
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
}: WorkflowTemplatePickerProps) {
|
||||||
|
const [options, setOptions] = useState<Option[]>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
async function load() {
|
||||||
|
const workflowTemplates = await templateVersionsService.getTemplates(
|
||||||
|
0,
|
||||||
|
10,
|
||||||
|
"name",
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
if (workflowTemplates) {
|
||||||
|
const opts: Option[] = (workflowTemplates.data as any[]).map((x) => ({
|
||||||
|
_id: x.id,
|
||||||
|
name: x.workflowName,
|
||||||
|
}));
|
||||||
|
setOptions(opts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
load();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const doOnChange = useCallback(
|
||||||
|
(n: string, v: bigint) => {
|
||||||
|
const generalIdRef = MakeGeneralIdRef(v);
|
||||||
|
if (onChange) onChange(n, generalIdRef);
|
||||||
|
},
|
||||||
|
[onChange],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleChange = useCallback(
|
||||||
|
(e: React.ChangeEvent<HTMLSelectElement>) => {
|
||||||
|
const input = e.currentTarget;
|
||||||
|
doOnChange(input.name, BigInt(input.value));
|
||||||
|
},
|
||||||
|
[doOnChange],
|
||||||
|
);
|
||||||
|
|
||||||
|
let id = "";
|
||||||
|
if (value !== undefined && !Number.isNaN(value.id)) {
|
||||||
|
id = String(value.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Select
|
||||||
|
includeLabel={includeLabel}
|
||||||
|
name={name}
|
||||||
|
label={label}
|
||||||
|
error={error}
|
||||||
|
value={id}
|
||||||
|
options={options}
|
||||||
|
includeBlankFirstEntry={true}
|
||||||
|
onChange={handleChange}
|
||||||
|
/>
|
||||||
|
<ErrorBlock error={error}></ErrorBlock>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
92
src/modules/manager/activity/CreateActivity.tsx
Normal file
92
src/modules/manager/activity/CreateActivity.tsx
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { Namespaces } from "../../../i18n/i18n";
|
||||||
|
import { useFormWithGuard } from "../../../components/common/useFormRouter";
|
||||||
|
import Joi from "joi";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import {
|
||||||
|
renderInput,
|
||||||
|
renderWorkflowTemplatePicker,
|
||||||
|
} from "../../../components/common/formHelpers";
|
||||||
|
import { InputType } from "../../../components/common/Input";
|
||||||
|
import templateVersionsService from "../workflowTemplates/services/WorkflowTemplateService";
|
||||||
|
|
||||||
|
const CreateActivity: React.FC = () => {
|
||||||
|
const { t } = useTranslation(Namespaces.Common);
|
||||||
|
const [selectedWorkflowTemplateName, setSelectedWorkflowTemplateName] =
|
||||||
|
useState<string>();
|
||||||
|
|
||||||
|
const form = useFormWithGuard({
|
||||||
|
loaded: true,
|
||||||
|
data: {
|
||||||
|
workflowTemplate: undefined,
|
||||||
|
},
|
||||||
|
errors: {},
|
||||||
|
redirect: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
form.schema = {
|
||||||
|
workflowTemplate: Joi.object().required().label(t("WorkflowTemplate")),
|
||||||
|
activityName: Joi.string().max(450).label(t("ActivityName")),
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const loadData = async () => {
|
||||||
|
form.setState({ loaded: true });
|
||||||
|
};
|
||||||
|
|
||||||
|
loadData();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const workflowTemplate = form.state.data.workflowTemplate as
|
||||||
|
| { id?: bigint }
|
||||||
|
| undefined;
|
||||||
|
|
||||||
|
if (workflowTemplate?.id === undefined || workflowTemplate.id === 0n) {
|
||||||
|
setSelectedWorkflowTemplateName(undefined);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadWorkflowTemplateName = async () => {
|
||||||
|
const templateVersion = await templateVersionsService.getTemplateVersion(
|
||||||
|
workflowTemplate.id!,
|
||||||
|
);
|
||||||
|
setSelectedWorkflowTemplateName(templateVersion?.workflowName);
|
||||||
|
};
|
||||||
|
|
||||||
|
loadWorkflowTemplateName();
|
||||||
|
}, [form.state.data.workflowTemplate]);
|
||||||
|
|
||||||
|
const now = new Date();
|
||||||
|
const datePrefix = `${now.getFullYear()}${String(now.getMonth() + 1).padStart(2, "0")}${String(now.getDate()).padStart(2, "0")} ${String(now.getHours()).padStart(2, "0")}${String(now.getMinutes()).padStart(2, "0")}${String(now.getSeconds()).padStart(2, "0")}`;
|
||||||
|
const defaultActivityName = `${datePrefix} ${selectedWorkflowTemplateName ?? "New Activity"}`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form>
|
||||||
|
{renderWorkflowTemplatePicker(
|
||||||
|
true,
|
||||||
|
"workflowTemplate",
|
||||||
|
t("WorkflowTemplate"),
|
||||||
|
form.state.data,
|
||||||
|
form.state.errors,
|
||||||
|
form.handleWorkflowTemplatePickerChange,
|
||||||
|
)}
|
||||||
|
{renderInput(
|
||||||
|
"activityName",
|
||||||
|
t("ActivityName"),
|
||||||
|
form.state.data,
|
||||||
|
form.state.errors,
|
||||||
|
InputType.text,
|
||||||
|
false,
|
||||||
|
"",
|
||||||
|
defaultActivityName,
|
||||||
|
0,
|
||||||
|
true,
|
||||||
|
undefined,
|
||||||
|
form.handleChange,
|
||||||
|
)}
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CreateActivity;
|
||||||
@ -126,6 +126,11 @@ const WotkflowTemplateManager: React.FC = () => {
|
|||||||
{t("Add")}
|
{t("Add")}
|
||||||
</Button>
|
</Button>
|
||||||
</Permission>
|
</Permission>
|
||||||
|
<Permission privilegeKey="CreateActivity">
|
||||||
|
<Button buttonType={ButtonType.primary} to="/activity/createActivity">
|
||||||
|
{t("CreateActivity")}
|
||||||
|
</Button>
|
||||||
|
</Permission>
|
||||||
<hr />
|
<hr />
|
||||||
<WorkflowTemplateManagerTable
|
<WorkflowTemplateManagerTable
|
||||||
data={pagedData}
|
data={pagedData}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user