Working on the create activity page

This commit is contained in:
Colin Dawson 2026-03-04 22:38:53 +00:00
parent 6f328afbf2
commit 156d822cf5
7 changed files with 230 additions and 10 deletions

View File

@ -37,6 +37,7 @@
"ConfirmEmailResent": "Confirm e-mail resent",
"ConfirmPassword": "Confirm Password",
"Continuous": "Continuous",
"CreateActivity": "Create Activity",
"Created": "Created",
"CustomField": "Custom Field",
"CustomFieldEdited": "Custom Field edited",

View File

@ -46,6 +46,7 @@ import SsoProviderDetails from "./modules/manager/ssoManager/SsoProviderDetails"
import { Namespaces } from "./i18n/i18n";
import WorkflowTemplateManager from "./modules/manager/workflowTemplates/WorkflowTemplateManager";
import WorkflowTemplateDetails from "./modules/manager/workflowTemplates/WorkflowTemplateDetails";
import CreateActivity from "./modules/manager/activity/CreateActivity";
function GetSecureRoutes() {
const { t } = useTranslation(Namespaces.Common);
@ -84,7 +85,6 @@ function GetSecureRoutes() {
</Mainframe>
}
/>
<Route
path="/specifications/:organisationId/:siteId/add"
element={
@ -109,7 +109,6 @@ function GetSecureRoutes() {
</Mainframe>
}
/>
<Route
path="/site/:organisationId/add"
element={
@ -135,7 +134,6 @@ function GetSecureRoutes() {
}
/>
<Route path="/site/" element={<Navigate replace to="/404" />} />
<Route
path="/organisations"
element={
@ -160,7 +158,6 @@ function GetSecureRoutes() {
</Mainframe>
}
/>
<Route path="/glossaries/add/" element={<Navigate replace to="/404" />} />
<Route
path="/glossaries/add/:glossaryId"
@ -198,7 +195,6 @@ function GetSecureRoutes() {
</Mainframe>
}
/>
<Route
path="/forms/add"
element={
@ -223,7 +219,6 @@ function GetSecureRoutes() {
</Mainframe>
}
/>
<Route
path="/customfields/add"
element={
@ -248,7 +243,6 @@ function GetSecureRoutes() {
</Mainframe>
}
/>
<Route
path="/sequence/add"
element={
@ -273,7 +267,6 @@ function GetSecureRoutes() {
</Mainframe>
}
/>
<Route
path="/domains/add"
element={
@ -322,7 +315,6 @@ function GetSecureRoutes() {
</Mainframe>
}
/>
<Route
path="/users/add"
element={
@ -347,7 +339,6 @@ function GetSecureRoutes() {
</Mainframe>
}
/>
<Route
path="/ssoManager"
element={
@ -388,6 +379,14 @@ function GetSecureRoutes() {
</Mainframe>
}
/>
<Route
path="/activity/createActivity"
element={
<Mainframe title={t("CreateActivity")}>
<CreateActivity />
</Mainframe>
}
/>
<Route
path="/workflowTemplates"
element={

View File

@ -25,6 +25,7 @@ import Expando from "./expando";
import ErrorBlock from "./ErrorBlock";
import SsoProviderPicker from "../pickers/SsoProviderPicker";
import { FormData, FormError } from "./useForm";
import WorkflowTemplatePicker from "../pickers/WorkflowTemplatePicker";
export const renderButton = (
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 = (
name: string,
label: string,

View File

@ -87,6 +87,10 @@ interface UseFormReturn {
) => void;
handleTemplateFormPickerChange: (name: string, value: GeneralIdRef) => void;
handleUserPickerChange: (name: string, value: GeneralIdRef) => void;
handleWorkflowTemplatePickerChange: (
name: string,
value: GeneralIdRef,
) => void;
handleSsoProviderPickerChange: (name: string, value: GeneralIdRef) => void;
handleToggleChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
setState: (updates: Partial<FormState>) => void;
@ -529,6 +533,17 @@ export const useForm = (initialState: FormState): UseFormReturn => {
[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(
(name: string, value: GeneralIdRef) => {
const data: FormData = { ...state.data };
@ -663,6 +678,7 @@ export const useForm = (initialState: FormState): UseFormReturn => {
handleTemplateFormPickerChange,
handleUserPickerChange,
handleSsoProviderPickerChange,
handleWorkflowTemplatePickerChange,
handleToggleChange,
handleTasksChange,
setState,
@ -693,6 +709,7 @@ export const useForm = (initialState: FormState): UseFormReturn => {
handleTemplateFormPickerChange,
handleUserPickerChange,
handleSsoProviderPickerChange,
handleWorkflowTemplatePickerChange,
handleToggleChange,
handleTasksChange,
setState,

View 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>
</>
);
}

View 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;

View File

@ -126,6 +126,11 @@ const WotkflowTemplateManager: React.FC = () => {
{t("Add")}
</Button>
</Permission>
<Permission privilegeKey="CreateActivity">
<Button buttonType={ButtonType.primary} to="/activity/createActivity">
{t("CreateActivity")}
</Button>
</Permission>
<hr />
<WorkflowTemplateManagerTable
data={pagedData}