Start Form
The start form collects the data a process needs to start. The platform adds saving as draft, continuing a draft, submitting and the confirmation page with the business key.
File: src/apps/{processId}/{ProcessId}Starter.tsx - opened at /process/start/{processId}.
Minimal start form
import { useTranslation } from "react-i18next";
import { useHideSideNav } from "@/ecc/context/LayoutContext";
import { usePageTitle } from "@/ecc/core/usePageTitle";
import { useExistingProcess } from "@/ecc/context/ProcessStartContext";
import { EccPageWrapper } from "@/ecc/core/EccPageWrapper";
import EccPageHeader from "@/ecc/components/widgets/EccPageHeader";
import { EccPageFooter } from "@/ecc/components/widgets/EccPageFooter";
import { EccPanel } from "@/ecc/components/forms/EccPanel";
import { EccText } from "@/ecc/components/forms/EccText";
import { EccTextarea } from "@/ecc/components/forms/EccTextarea";
import type { EccProcess } from "@/ecc/types/taskTypes";
export default function PurchaseStarter() {
return (
<EccPageWrapper>
<PurchaseStarterContent />
</EccPageWrapper>
);
}
function PurchaseStarterContent() {
useHideSideNav(); // full width, no side menu
const { t } = useTranslation("purchase");
usePageTitle(t("app.purchase.process.name"));
const { existingProcess } = useExistingProcess(); // set when a draft is continued
const data = existingProcess?.inputs ?? null; // business data of the draft
const process: EccProcess = {
eccType: "process",
processId: "purchase",
processName: t("app.purchase.process.name"),
processInstanceId: existingProcess?.processInstanceId, // draft id, if any
};
return (
<div className="ecc-page">
<div className="container-fluid">
<EccPageHeader headline={t("app.purchase.process.name")} text={t("app.purchase.process.description")} />
</div>
<div className="row g-3">
<div className="col-md-6">
<EccPanel title="Request">
<EccText fieldLabel="Title" value="purchase.title" data={data} valueOut editable mandatory />
<EccTextarea fieldLabel="Reason" value="purchase.reason" data={data} valueOut editable mandatory />
</EccPanel>
</div>
</div>
<EccPageFooter process={process} />
</div>
);
}
Ecc components in this example: EccPanel, EccText, EccTextarea - how to use them is described in UI Components. Page frame: EccPageWrapper. Widgets in this example: EccPageHeader, EccPageFooter. Objects in this example: EccProcess.
How the data flows
- Each field reads its value from
databy a path and writes it back to the same path (valueOut) - how paths,valueOutandvalueInitwork is described in Component Basics. datais the saved draft when the user continues one, so the same paths fill the fields again. For a new requestdataisnulland the fields start empty.- EccPageFootercollects the output of all fields into one JSON object:
{ "purchase": { "title": "Laptop for new team member", "reason": "Replacement device" } }
This object is exactly the start data of the process. The top-level key (purchase) is the process variable of the BPMN model, the fields below are its attributes.
Look up the expected start structure in the Schema Explorer (/schema-explorer, process, version, node Start) or with GET /api/v1/schema/process/{processId}/{version}/data.
Footer buttons
Cancel | closes the browser tab |
Save | stores the data as draft; a note field appears for a short comment (e.g. "waiting for quote") |
Submit | starts the process and shows the confirmation page: process id, process name, business key and process instance id - the last two can be copied with one click |
A saved draft appears on the dashboard. Opening it calls /process/start/purchase?id=tmp.… and the start form is pre-filled. After submitting, the draft is deleted automatically.
Callbacks, if you need them:
const [draftId, setDraftId] = useState<string | undefined>(existingProcess?.processInstanceId);
const [info, setInfo] = useState(existingProcess?.info ?? "");
<EccPageFooter
process={{ ...process, processInstanceId: draftId, info: info || undefined }}
onProcessSaved={setDraftId} // id of the saved draft (tmp.…)
onInfoChange={setInfo} // text of the note field
/>
Pre-filling fields
value from the logged-in user |
|
fixed value that must be sent | read-only field with |
value of a draft | automatic through |
const { user } = useAuth();
const fullName = [user?.givenName, user?.familyName].filter(Boolean).join(" ");
<EccText fieldLabel="Name" value="purchase.requester.name" data={data} valueOut valueInit={fullName} />
<EccText fieldLabel="Email" value="purchase.requester.email" data={data} valueOut valueInit={user?.email} editable />
<EccText valueOut="purchase.source" value="web" hidden />
Showing who creates the request
Place EccNewProcessInstance in the header to show the process name, the creating user and - once saved - the draft id:
<EccPageHeader
headline={t("app.purchase.process.name")}
dataRight={<EccNewProcessInstance processId="purchase" name={t("app.purchase.process.name")} processInstanceId={draftId} />}
/>
Dynamic sections
Show a section only for certain answers with a validator - see Page Validator:
<EccPageWrapper validatorClass={PurchaseStarterValidator}>
<PurchaseStarterContent />
</EccPageWrapper>
On this page
- Start Form