@ram_28/kf-ai-sdk 2.0.2 → 2.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/BaseField-B6da88U7.js +40 -0
- package/dist/BaseField-Drp0-OxL.cjs +1 -0
- package/dist/api/client.d.ts +7 -0
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/index.d.ts +1 -1
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api.cjs +1 -1
- package/dist/api.mjs +3 -3
- package/dist/auth.cjs +1 -1
- package/dist/auth.mjs +2 -2
- package/dist/bdo/core/BaseBdo.d.ts +4 -0
- package/dist/bdo/core/BaseBdo.d.ts.map +1 -1
- package/dist/bdo.cjs +1 -1
- package/dist/bdo.mjs +91 -118
- package/dist/client-BULEEaCP.js +222 -0
- package/dist/client-DtPpfJc1.cjs +1 -0
- package/dist/components/hooks/useForm/index.d.ts +1 -1
- package/dist/components/hooks/useForm/index.d.ts.map +1 -1
- package/dist/components/hooks/useForm/types.d.ts +15 -2
- package/dist/components/hooks/useForm/types.d.ts.map +1 -1
- package/dist/components/hooks/useForm/useDraftInteraction.d.ts +26 -0
- package/dist/components/hooks/useForm/useDraftInteraction.d.ts.map +1 -0
- package/dist/components/hooks/useForm/useForm.d.ts +1 -0
- package/dist/components/hooks/useForm/useForm.d.ts.map +1 -1
- package/dist/{constants-CM9xOACN.js → constants-BQrBcCON.js} +5 -5
- package/dist/error-handling-CAoD0Kwb.cjs +1 -0
- package/dist/error-handling-CrhTtD88.js +14 -0
- package/dist/filter.mjs +1 -1
- package/dist/form.cjs +1 -1
- package/dist/form.mjs +313 -1187
- package/dist/form.types.d.ts +1 -1
- package/dist/form.types.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm-Cj63v5ny.js +1014 -0
- package/dist/index.esm-DuwT11sx.cjs +1 -0
- package/dist/{metadata-BN57S6W9.cjs → metadata-BJWukIqS.cjs} +1 -1
- package/dist/{metadata-P7DGCgIG.js → metadata-CJuFxytC.js} +1 -1
- package/dist/table.cjs +1 -1
- package/dist/table.mjs +83 -93
- package/dist/types/constants.d.ts +2 -2
- package/dist/types/constants.d.ts.map +1 -1
- package/dist/workflow/Activity.d.ts +85 -0
- package/dist/workflow/Activity.d.ts.map +1 -0
- package/dist/workflow/ActivityInstance.d.ts +96 -0
- package/dist/workflow/ActivityInstance.d.ts.map +1 -0
- package/dist/workflow/client.d.ts +39 -0
- package/dist/workflow/client.d.ts.map +1 -0
- package/dist/workflow/components/useActivityForm/createActivityItemProxy.d.ts +16 -0
- package/dist/workflow/components/useActivityForm/createActivityItemProxy.d.ts.map +1 -0
- package/dist/workflow/components/useActivityForm/createActivityResolver.d.ts +22 -0
- package/dist/workflow/components/useActivityForm/createActivityResolver.d.ts.map +1 -0
- package/dist/workflow/components/useActivityForm/index.d.ts +3 -0
- package/dist/workflow/components/useActivityForm/index.d.ts.map +1 -0
- package/dist/workflow/components/useActivityForm/types.d.ts +80 -0
- package/dist/workflow/components/useActivityForm/types.d.ts.map +1 -0
- package/dist/workflow/components/useActivityForm/useActivityForm.d.ts +4 -0
- package/dist/workflow/components/useActivityForm/useActivityForm.d.ts.map +1 -0
- package/dist/workflow/index.d.ts +8 -0
- package/dist/workflow/index.d.ts.map +1 -0
- package/dist/workflow/types.d.ts +53 -0
- package/dist/workflow/types.d.ts.map +1 -0
- package/dist/workflow.cjs +1 -0
- package/dist/workflow.d.ts +8 -0
- package/dist/workflow.d.ts.map +1 -0
- package/dist/workflow.mjs +565 -0
- package/dist/workflow.types.cjs +1 -0
- package/dist/workflow.types.d.ts +2 -0
- package/dist/workflow.types.d.ts.map +1 -0
- package/dist/workflow.types.mjs +1 -0
- package/docs/workflow.md +703 -0
- package/package.json +21 -1
- package/sdk/api/client.ts +85 -52
- package/sdk/api/index.ts +1 -0
- package/sdk/api/metadata.ts +4 -4
- package/sdk/bdo/core/BaseBdo.ts +10 -0
- package/sdk/components/hooks/useForm/index.ts +1 -0
- package/sdk/components/hooks/useForm/types.ts +17 -3
- package/sdk/components/hooks/useForm/useDraftInteraction.ts +251 -0
- package/sdk/components/hooks/useForm/useForm.ts +115 -24
- package/sdk/form.types.ts +1 -0
- package/sdk/index.ts +6 -0
- package/sdk/types/constants.ts +2 -2
- package/sdk/workflow/Activity.ts +181 -0
- package/sdk/workflow/ActivityInstance.ts +339 -0
- package/sdk/workflow/client.ts +208 -0
- package/sdk/workflow/components/useActivityForm/createActivityItemProxy.ts +126 -0
- package/sdk/workflow/components/useActivityForm/createActivityResolver.ts +61 -0
- package/sdk/workflow/components/useActivityForm/index.ts +5 -0
- package/sdk/workflow/components/useActivityForm/types.ts +166 -0
- package/sdk/workflow/components/useActivityForm/useActivityForm.ts +386 -0
- package/sdk/workflow/index.ts +20 -0
- package/sdk/workflow/types.ts +84 -0
- package/sdk/workflow.ts +25 -0
- package/sdk/workflow.types.ts +11 -0
- package/dist/client-Bo-RLKJi.cjs +0 -1
- package/dist/client-eA4VvNTo.js +0 -178
package/docs/workflow.md
ADDED
|
@@ -0,0 +1,703 @@
|
|
|
1
|
+
# Workflow SDK API
|
|
2
|
+
|
|
3
|
+
The Workflow SDK provides a type-safe client for orchestrating business processes (workflows). Each workflow has typed Activity classes with field definitions, and a React hook (`useActivityForm`) for building forms bound to activity input fields.
|
|
4
|
+
|
|
5
|
+
## Imports
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
// Runtime exports
|
|
9
|
+
import {
|
|
10
|
+
Workflow,
|
|
11
|
+
Activity,
|
|
12
|
+
ActivityInstance,
|
|
13
|
+
useActivityForm,
|
|
14
|
+
} from "@ram_28/kf-ai-sdk/workflow";
|
|
15
|
+
|
|
16
|
+
// Type-only exports
|
|
17
|
+
import type {
|
|
18
|
+
ActivityInstanceFieldsType,
|
|
19
|
+
ActivityProgressType,
|
|
20
|
+
WorkflowStartResponseType,
|
|
21
|
+
UseActivityFormOptions,
|
|
22
|
+
UseActivityFormReturn,
|
|
23
|
+
} from "@ram_28/kf-ai-sdk/workflow";
|
|
24
|
+
|
|
25
|
+
// Field classes (for defining Activity fields)
|
|
26
|
+
import {
|
|
27
|
+
StringField,
|
|
28
|
+
NumberField,
|
|
29
|
+
BooleanField,
|
|
30
|
+
DateTimeField,
|
|
31
|
+
SelectField,
|
|
32
|
+
ReferenceField,
|
|
33
|
+
} from "@ram_28/kf-ai-sdk/bdo/fields";
|
|
34
|
+
|
|
35
|
+
// Field types (for entity type definitions)
|
|
36
|
+
import type {
|
|
37
|
+
StringFieldType,
|
|
38
|
+
NumberFieldType,
|
|
39
|
+
BooleanFieldType,
|
|
40
|
+
DateFieldType,
|
|
41
|
+
DateTimeFieldType,
|
|
42
|
+
SelectFieldType,
|
|
43
|
+
ReferenceFieldType,
|
|
44
|
+
} from "@ram_28/kf-ai-sdk/types";
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Type Definitions
|
|
50
|
+
|
|
51
|
+
### WorkflowStartResponseType
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
interface WorkflowStartResponseType {
|
|
55
|
+
activityId: string; // First activity ID in the workflow
|
|
56
|
+
activityInstanceId: string; // Instance ID for the started activity
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### ActivityProgressType
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
interface ActivityProgressType {
|
|
64
|
+
Stage?: string;
|
|
65
|
+
Progress?: number;
|
|
66
|
+
[key: string]: any;
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### ActivityInstanceFieldsType
|
|
71
|
+
|
|
72
|
+
System fields present on every activity instance. Returned alongside activity-specific fields from `getInstanceList()`.
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
type ActivityInstanceFieldsType = {
|
|
76
|
+
_id: StringFieldType;
|
|
77
|
+
Status: SelectFieldType<"InProgress" | "Completed">;
|
|
78
|
+
AssignedTo: ReferenceFieldType<{ _id: StringFieldType; username: StringFieldType }>;
|
|
79
|
+
CompletedAt: DateTimeFieldType;
|
|
80
|
+
};
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### UseActivityFormOptions\<A\>
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
interface UseActivityFormOptions<A extends Activity<any, any, any>> {
|
|
87
|
+
/** Activity instance identifier (from wf.start() or getInstanceList()) */
|
|
88
|
+
activity_instance_id: string;
|
|
89
|
+
|
|
90
|
+
/** Default form values */
|
|
91
|
+
defaultValues?: Partial<ExtractActivityEditable<A>>;
|
|
92
|
+
|
|
93
|
+
/** Validation mode (default: "onBlur") */
|
|
94
|
+
mode?: "onBlur" | "onChange" | "onSubmit" | "onTouched" | "all";
|
|
95
|
+
|
|
96
|
+
/** Whether to load activity data on mount (default: true) */
|
|
97
|
+
enabled?: boolean;
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### UseActivityFormReturn\<A\>
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
interface UseActivityFormReturn<A extends Activity<any, any, any>> {
|
|
105
|
+
// Core
|
|
106
|
+
item: FormItemType<EditableFields, ReadonlyFields>;
|
|
107
|
+
activity: A;
|
|
108
|
+
register: FormRegisterType<EditableFields, ReadonlyFields>;
|
|
109
|
+
handleSubmit: HandleSubmitType; // Save the activity form
|
|
110
|
+
handleComplete: HandleSubmitType; // Complete the activity
|
|
111
|
+
|
|
112
|
+
// RHF methods
|
|
113
|
+
watch: UseFormWatch;
|
|
114
|
+
setValue: UseFormSetValue;
|
|
115
|
+
getValues: UseFormGetValues;
|
|
116
|
+
reset: UseFormReset;
|
|
117
|
+
trigger: UseFormTrigger;
|
|
118
|
+
control: Control;
|
|
119
|
+
|
|
120
|
+
// Form state
|
|
121
|
+
errors: FieldErrors;
|
|
122
|
+
isValid: boolean;
|
|
123
|
+
isDirty: boolean;
|
|
124
|
+
isSubmitting: boolean;
|
|
125
|
+
isSubmitSuccessful: boolean;
|
|
126
|
+
|
|
127
|
+
// Loading
|
|
128
|
+
isLoading: boolean;
|
|
129
|
+
loadError: Error | null;
|
|
130
|
+
hasError: boolean;
|
|
131
|
+
|
|
132
|
+
// Operations
|
|
133
|
+
clearErrors: () => void;
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Generated Workflow SDK
|
|
140
|
+
|
|
141
|
+
Each workflow generates a TypeScript SDK with typed Activity classes and a Workflow class. These are defined in `src/bdo/workflows/` and should never be created manually.
|
|
142
|
+
|
|
143
|
+
### Example: SimpleLeaveProcess SDK
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
// --- Activity classes ---
|
|
147
|
+
|
|
148
|
+
export type EmployeeInputEntityType = {
|
|
149
|
+
StartDate: DateFieldType;
|
|
150
|
+
EndDate: DateFieldType;
|
|
151
|
+
LeaveType: SelectFieldType<"PTO" | "Sick" | "Parental">;
|
|
152
|
+
LeaveDays: NumberFieldType;
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
export type EmployeeInputEditable = Omit<EmployeeInputEntityType, "LeaveDays">;
|
|
156
|
+
export type EmployeeInputReadonly = Pick<EmployeeInputEntityType, "LeaveDays">;
|
|
157
|
+
|
|
158
|
+
export class EmployeeInputActivity extends Activity<
|
|
159
|
+
EmployeeInputEntityType,
|
|
160
|
+
EmployeeInputEditable,
|
|
161
|
+
EmployeeInputReadonly
|
|
162
|
+
> {
|
|
163
|
+
readonly meta = {
|
|
164
|
+
businessProcessId: "SimpleLeaveProcess",
|
|
165
|
+
activityId: "EMPLOYEE_INPUT",
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
readonly StartDate = new DateTimeField({ id: "StartDate", label: "Start Date" });
|
|
169
|
+
readonly EndDate = new DateTimeField({ id: "EndDate", label: "End Date" });
|
|
170
|
+
readonly LeaveType = new SelectField<"PTO" | "Sick" | "Parental">({
|
|
171
|
+
id: "LeaveType", label: "Leave Type",
|
|
172
|
+
options: [
|
|
173
|
+
{ value: "PTO", label: "PTO" },
|
|
174
|
+
{ value: "Sick", label: "Sick" },
|
|
175
|
+
{ value: "Parental", label: "Parental" },
|
|
176
|
+
],
|
|
177
|
+
});
|
|
178
|
+
readonly LeaveDays = new NumberField({ id: "LeaveDays", label: "Leave Days", editable: false });
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export type ManagerApprovalEntityType = {
|
|
182
|
+
ManagerApproved: BooleanFieldType;
|
|
183
|
+
ManagerReason: StringFieldType;
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
export class ManagerApprovalActivity extends Activity<
|
|
187
|
+
ManagerApprovalEntityType,
|
|
188
|
+
ManagerApprovalEntityType,
|
|
189
|
+
{}
|
|
190
|
+
> {
|
|
191
|
+
readonly meta = {
|
|
192
|
+
businessProcessId: "SimpleLeaveProcess",
|
|
193
|
+
activityId: "MANAGER_APPROVAL",
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
readonly ManagerApproved = new BooleanField({ id: "ManagerApproved", label: "Manager Approved" });
|
|
197
|
+
readonly ManagerReason = new StringField({ id: "ManagerReason", label: "Manager's Reason" });
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// --- Workflow class ---
|
|
201
|
+
|
|
202
|
+
export class SimpleLeaveProcess {
|
|
203
|
+
async start(): Promise<WorkflowStartResponseType>;
|
|
204
|
+
|
|
205
|
+
employeeInputActivity(): EmployeeInputActivity;
|
|
206
|
+
managerApprovalActivity(): ManagerApprovalActivity;
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## Activity Class
|
|
213
|
+
|
|
214
|
+
Each Activity class provides methods to query and access activity instances.
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
const activity = wf.employeeInputActivity();
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### getInstanceList(options?)
|
|
221
|
+
|
|
222
|
+
List activity instances with optional filtering and pagination.
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
const result = await activity.getInstanceList({
|
|
226
|
+
Page: 1,
|
|
227
|
+
PageSize: 20,
|
|
228
|
+
Filter: {
|
|
229
|
+
Operator: "And",
|
|
230
|
+
Condition: [
|
|
231
|
+
{ LHSField: "Status", Operator: "EQ", RHSValue: "InProgress", RHSType: "Constant" },
|
|
232
|
+
],
|
|
233
|
+
},
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
for (const item of result.Data) {
|
|
237
|
+
console.log(item._id, item.Status, item.StartDate);
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### instanceMetrics(options)
|
|
242
|
+
|
|
243
|
+
Get aggregated metrics for activity instances.
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
const metrics = await activity.instanceMetrics({
|
|
247
|
+
Metric: [{ Field: "Status", Function: "Count" }],
|
|
248
|
+
});
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### getInstance(instanceId)
|
|
252
|
+
|
|
253
|
+
Get a typed ActivityInstance with field accessors and persistence methods.
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
const instance = await activity.getInstance("inst_abc123");
|
|
257
|
+
|
|
258
|
+
// Field accessors (BDO Item pattern)
|
|
259
|
+
instance._id; // "inst_abc123"
|
|
260
|
+
instance.StartDate.get(); // read value (typed)
|
|
261
|
+
instance.StartDate.set("2026-03-01"); // set value (editable fields only)
|
|
262
|
+
instance.StartDate.meta; // { id: "StartDate", label: "Start Date", ... }
|
|
263
|
+
instance.LeaveDays.get(); // read computed/readonly field
|
|
264
|
+
// instance.LeaveDays.set(...) // NOT available — readonly, no set()
|
|
265
|
+
|
|
266
|
+
// Utility methods
|
|
267
|
+
instance.toJSON(); // convert to plain object
|
|
268
|
+
instance.validate(); // validate all fields
|
|
269
|
+
|
|
270
|
+
// Persistence methods
|
|
271
|
+
await instance.update({ StartDate: "2026-03-01" }); // update fields
|
|
272
|
+
await instance.save({ StartDate: "2026-03-01" }); // save and commit
|
|
273
|
+
await instance.complete(); // complete the activity
|
|
274
|
+
const progress = await instance.progress(); // get progress
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
## useActivityForm Hook
|
|
280
|
+
|
|
281
|
+
React hook for building forms bound to workflow activity input fields. Integrates with `react-hook-form`.
|
|
282
|
+
|
|
283
|
+
### Options
|
|
284
|
+
|
|
285
|
+
| Property | Type | Default | Description |
|
|
286
|
+
|----------|------|---------|-------------|
|
|
287
|
+
| `activity_instance_id` | `string` | *required* | Activity instance ID (from `wf.start()` or `getInstanceList()`) |
|
|
288
|
+
| `defaultValues` | `Partial<Editable>` | `{}` | Initial form values |
|
|
289
|
+
| `mode` | `"onBlur" \| "onChange" \| "onSubmit" \| "onTouched" \| "all"` | `"onBlur"` | Validation timing |
|
|
290
|
+
| `enabled` | `boolean` | `true` | Whether to load activity data on mount |
|
|
291
|
+
|
|
292
|
+
### Lifecycle
|
|
293
|
+
|
|
294
|
+
```
|
|
295
|
+
Mount
|
|
296
|
+
|
|
|
297
|
+
|-> Load activity instance data -> populate form
|
|
298
|
+
|
|
|
299
|
+
v
|
|
300
|
+
User edits field -> blurs
|
|
301
|
+
|
|
|
302
|
+
|-> Field validation (BaseField.validate)
|
|
303
|
+
|-> If valid + readonly fields exist -> update computed fields
|
|
304
|
+
|
|
|
305
|
+
v
|
|
306
|
+
User clicks Save
|
|
307
|
+
|
|
|
308
|
+
|-> handleSubmit -> save activity data
|
|
309
|
+
|
|
|
310
|
+
v
|
|
311
|
+
User clicks Complete
|
|
312
|
+
|
|
|
313
|
+
|-> handleComplete -> complete activity
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### Return Value
|
|
317
|
+
|
|
318
|
+
| Property | Type | Description |
|
|
319
|
+
|----------|------|-------------|
|
|
320
|
+
| `item` | `FormItemType` | Proxy with typed field accessors (`.get()`, `.set()`, `.meta`) |
|
|
321
|
+
| `activity` | `A` | The Activity instance |
|
|
322
|
+
| `register` | `FormRegisterType` | Smart register (auto-disables readonly fields) |
|
|
323
|
+
| `handleSubmit` | `HandleSubmitType` | Save activity data |
|
|
324
|
+
| `handleComplete` | `HandleSubmitType` | Complete the activity |
|
|
325
|
+
| `watch` | `UseFormWatch` | Watch field values |
|
|
326
|
+
| `setValue` | `UseFormSetValue` | Set field value programmatically |
|
|
327
|
+
| `getValues` | `UseFormGetValues` | Get current field values |
|
|
328
|
+
| `reset` | `UseFormReset` | Reset form to default values |
|
|
329
|
+
| `trigger` | `UseFormTrigger` | Trigger validation |
|
|
330
|
+
| `control` | `Control` | RHF control (for Controller components) |
|
|
331
|
+
| `errors` | `FieldErrors` | Validation errors |
|
|
332
|
+
| `isValid` | `boolean` | Form is valid |
|
|
333
|
+
| `isDirty` | `boolean` | Form has been modified |
|
|
334
|
+
| `isSubmitting` | `boolean` | Currently submitting |
|
|
335
|
+
| `isSubmitSuccessful` | `boolean` | Last submission succeeded |
|
|
336
|
+
| `isLoading` | `boolean` | Loading activity data |
|
|
337
|
+
| `loadError` | `Error \| null` | Load error |
|
|
338
|
+
| `hasError` | `boolean` | Any error active |
|
|
339
|
+
| `clearErrors` | `() => void` | Clear all form errors |
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
## Use Case: Employee Creating Leave
|
|
344
|
+
|
|
345
|
+
### Step 1 — Start the workflow
|
|
346
|
+
|
|
347
|
+
```typescript
|
|
348
|
+
import { SimpleLeaveProcess } from "@/bdo/workflows/SimpleLeaveProcess";
|
|
349
|
+
import type { WorkflowStartResponseType } from "@ram_28/kf-ai-sdk/workflow";
|
|
350
|
+
|
|
351
|
+
const wf = new SimpleLeaveProcess();
|
|
352
|
+
const { activityId, activityInstanceId }: WorkflowStartResponseType = await wf.start();
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
### Step 2 — React component with useActivityForm
|
|
356
|
+
|
|
357
|
+
```tsx
|
|
358
|
+
import { useMemo } from "react";
|
|
359
|
+
import { useActivityForm } from "@ram_28/kf-ai-sdk/workflow";
|
|
360
|
+
import type { UseActivityFormOptions } from "@ram_28/kf-ai-sdk/workflow";
|
|
361
|
+
import type { FieldErrors } from "react-hook-form";
|
|
362
|
+
import { SimpleLeaveProcess, EmployeeInputActivity } from "@/bdo/workflows/SimpleLeaveProcess";
|
|
363
|
+
|
|
364
|
+
interface LeaveRequestFormProps {
|
|
365
|
+
activityInstanceId: string;
|
|
366
|
+
onComplete: () => void;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function LeaveRequestForm({ activityInstanceId, onComplete }: LeaveRequestFormProps) {
|
|
370
|
+
// 1. Get the typed activity from the workflow
|
|
371
|
+
const activity = useMemo(() => new SimpleLeaveProcess().employeeInputActivity(), []);
|
|
372
|
+
|
|
373
|
+
// 2. Hook options
|
|
374
|
+
const options: UseActivityFormOptions<EmployeeInputActivity> = {
|
|
375
|
+
activity_instance_id: activityInstanceId,
|
|
376
|
+
defaultValues: {
|
|
377
|
+
StartDate: undefined,
|
|
378
|
+
EndDate: undefined,
|
|
379
|
+
LeaveType: undefined,
|
|
380
|
+
},
|
|
381
|
+
mode: "onBlur",
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
// 3. Initialize hook
|
|
385
|
+
const {
|
|
386
|
+
register,
|
|
387
|
+
handleSubmit,
|
|
388
|
+
handleComplete,
|
|
389
|
+
item,
|
|
390
|
+
errors,
|
|
391
|
+
isLoading,
|
|
392
|
+
isSubmitting,
|
|
393
|
+
loadError,
|
|
394
|
+
} = useActivityForm(activity, options);
|
|
395
|
+
|
|
396
|
+
if (isLoading) return <div>Loading...</div>;
|
|
397
|
+
if (loadError) return <div>Error: {loadError.message}</div>;
|
|
398
|
+
|
|
399
|
+
// 4. Handlers
|
|
400
|
+
const onSaveSuccess = (): void => {
|
|
401
|
+
console.log("Saved!");
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
const onCompleteSuccess = (): void => {
|
|
405
|
+
console.log("Leave request submitted!");
|
|
406
|
+
onComplete();
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
const onError = (error: FieldErrors | Error): void => {
|
|
410
|
+
if (error instanceof Error) {
|
|
411
|
+
console.error("API Error:", error.message);
|
|
412
|
+
} else {
|
|
413
|
+
console.error("Validation errors:", error);
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
return (
|
|
418
|
+
<form>
|
|
419
|
+
<h2>Leave Request</h2>
|
|
420
|
+
|
|
421
|
+
{/* Start Date */}
|
|
422
|
+
<div>
|
|
423
|
+
<label>{activity.StartDate.meta.label}</label>
|
|
424
|
+
<input type="date" {...register(activity.StartDate.meta.id)} />
|
|
425
|
+
{errors.StartDate && <span>{errors.StartDate.message}</span>}
|
|
426
|
+
</div>
|
|
427
|
+
|
|
428
|
+
{/* End Date */}
|
|
429
|
+
<div>
|
|
430
|
+
<label>{activity.EndDate.meta.label}</label>
|
|
431
|
+
<input type="date" {...register(activity.EndDate.meta.id)} />
|
|
432
|
+
{errors.EndDate && <span>{errors.EndDate.message}</span>}
|
|
433
|
+
</div>
|
|
434
|
+
|
|
435
|
+
{/* Leave Type */}
|
|
436
|
+
<div>
|
|
437
|
+
<label>{activity.LeaveType.meta.label}</label>
|
|
438
|
+
<select {...register(activity.LeaveType.meta.id)}>
|
|
439
|
+
<option value="">Select type</option>
|
|
440
|
+
<option value="PTO">PTO</option>
|
|
441
|
+
<option value="Sick">Sick</option>
|
|
442
|
+
<option value="Parental">Parental</option>
|
|
443
|
+
</select>
|
|
444
|
+
{errors.LeaveType && <span>{errors.LeaveType.message}</span>}
|
|
445
|
+
</div>
|
|
446
|
+
|
|
447
|
+
{/* Leave Days (readonly — auto-disabled, computed by server) */}
|
|
448
|
+
<div>
|
|
449
|
+
<label>{activity.LeaveDays.meta.label}</label>
|
|
450
|
+
<input type="number" {...register(activity.LeaveDays.meta.id)} />
|
|
451
|
+
</div>
|
|
452
|
+
|
|
453
|
+
{/* Actions */}
|
|
454
|
+
<div>
|
|
455
|
+
<button type="button" onClick={handleSubmit(onSaveSuccess, onError)}>
|
|
456
|
+
{isSubmitting ? "Saving..." : "Save Draft"}
|
|
457
|
+
</button>
|
|
458
|
+
<button type="button" onClick={handleComplete(onCompleteSuccess, onError)}>
|
|
459
|
+
{isSubmitting ? "Submitting..." : "Submit Leave Request"}
|
|
460
|
+
</button>
|
|
461
|
+
</div>
|
|
462
|
+
</form>
|
|
463
|
+
);
|
|
464
|
+
}
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
### Full flow orchestration
|
|
468
|
+
|
|
469
|
+
```tsx
|
|
470
|
+
import { useState } from "react";
|
|
471
|
+
import { SimpleLeaveProcess } from "@/bdo/workflows/SimpleLeaveProcess";
|
|
472
|
+
import type { WorkflowStartResponseType } from "@ram_28/kf-ai-sdk/workflow";
|
|
473
|
+
|
|
474
|
+
function LeaveRequestPage() {
|
|
475
|
+
const [instanceId, setInstanceId] = useState<string | null>(null);
|
|
476
|
+
|
|
477
|
+
const startLeaveRequest = async () => {
|
|
478
|
+
const wf = new SimpleLeaveProcess();
|
|
479
|
+
const result: WorkflowStartResponseType = await wf.start();
|
|
480
|
+
setInstanceId(result.activityInstanceId);
|
|
481
|
+
};
|
|
482
|
+
|
|
483
|
+
if (!instanceId) {
|
|
484
|
+
return <button onClick={startLeaveRequest}>New Leave Request</button>;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
return (
|
|
488
|
+
<LeaveRequestForm
|
|
489
|
+
activityInstanceId={instanceId}
|
|
490
|
+
onComplete={() => setInstanceId(null)}
|
|
491
|
+
/>
|
|
492
|
+
);
|
|
493
|
+
}
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
---
|
|
497
|
+
|
|
498
|
+
## Use Case: Manager Approving Leave
|
|
499
|
+
|
|
500
|
+
### Step 1 — List in-progress items
|
|
501
|
+
|
|
502
|
+
```typescript
|
|
503
|
+
import { SimpleLeaveProcess } from "@/bdo/workflows/SimpleLeaveProcess";
|
|
504
|
+
|
|
505
|
+
const wf = new SimpleLeaveProcess();
|
|
506
|
+
const activity = wf.managerApprovalActivity();
|
|
507
|
+
|
|
508
|
+
const result = await activity.getInstanceList({
|
|
509
|
+
Filter: {
|
|
510
|
+
Operator: "And",
|
|
511
|
+
Condition: [
|
|
512
|
+
{ LHSField: "Status", Operator: "EQ", RHSValue: "InProgress", RHSType: "Constant" },
|
|
513
|
+
],
|
|
514
|
+
},
|
|
515
|
+
Page: 1,
|
|
516
|
+
PageSize: 20,
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
for (const item of result.Data) {
|
|
520
|
+
console.log(item._id, item.Status, item.AssignedTo.username);
|
|
521
|
+
}
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
### Step 2 — Approval form component
|
|
525
|
+
|
|
526
|
+
```tsx
|
|
527
|
+
import { useMemo } from "react";
|
|
528
|
+
import { useActivityForm } from "@ram_28/kf-ai-sdk/workflow";
|
|
529
|
+
import type { UseActivityFormOptions } from "@ram_28/kf-ai-sdk/workflow";
|
|
530
|
+
import type { FieldErrors } from "react-hook-form";
|
|
531
|
+
import { SimpleLeaveProcess, ManagerApprovalActivity } from "@/bdo/workflows/SimpleLeaveProcess";
|
|
532
|
+
|
|
533
|
+
interface ApprovalFormProps {
|
|
534
|
+
activityInstanceId: string;
|
|
535
|
+
onComplete: () => void;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
function ApprovalForm({ activityInstanceId, onComplete }: ApprovalFormProps) {
|
|
539
|
+
const activity = useMemo(() => new SimpleLeaveProcess().managerApprovalActivity(), []);
|
|
540
|
+
|
|
541
|
+
const options: UseActivityFormOptions<ManagerApprovalActivity> = {
|
|
542
|
+
activity_instance_id: activityInstanceId,
|
|
543
|
+
defaultValues: {
|
|
544
|
+
ManagerApproved: false,
|
|
545
|
+
ManagerReason: "",
|
|
546
|
+
},
|
|
547
|
+
mode: "onBlur",
|
|
548
|
+
};
|
|
549
|
+
|
|
550
|
+
const {
|
|
551
|
+
register,
|
|
552
|
+
handleComplete,
|
|
553
|
+
errors,
|
|
554
|
+
isLoading,
|
|
555
|
+
isSubmitting,
|
|
556
|
+
loadError,
|
|
557
|
+
} = useActivityForm(activity, options);
|
|
558
|
+
|
|
559
|
+
if (isLoading) return <div>Loading...</div>;
|
|
560
|
+
if (loadError) return <div>Error: {loadError.message}</div>;
|
|
561
|
+
|
|
562
|
+
const onSuccess = (): void => {
|
|
563
|
+
console.log("Approval submitted!");
|
|
564
|
+
onComplete();
|
|
565
|
+
};
|
|
566
|
+
|
|
567
|
+
const onError = (error: FieldErrors | Error): void => {
|
|
568
|
+
if (error instanceof Error) console.error("API Error:", error.message);
|
|
569
|
+
};
|
|
570
|
+
|
|
571
|
+
return (
|
|
572
|
+
<form>
|
|
573
|
+
<h2>Leave Approval</h2>
|
|
574
|
+
|
|
575
|
+
<div>
|
|
576
|
+
<label>
|
|
577
|
+
<input type="checkbox" {...register(activity.ManagerApproved.meta.id)} />
|
|
578
|
+
{activity.ManagerApproved.meta.label}
|
|
579
|
+
</label>
|
|
580
|
+
</div>
|
|
581
|
+
|
|
582
|
+
<div>
|
|
583
|
+
<label>{activity.ManagerReason.meta.label}</label>
|
|
584
|
+
<textarea {...register(activity.ManagerReason.meta.id)} rows={4} />
|
|
585
|
+
</div>
|
|
586
|
+
|
|
587
|
+
<button type="button" onClick={handleComplete(onSuccess, onError)}>
|
|
588
|
+
{isSubmitting ? "Submitting..." : "Submit Decision"}
|
|
589
|
+
</button>
|
|
590
|
+
</form>
|
|
591
|
+
);
|
|
592
|
+
}
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
---
|
|
596
|
+
|
|
597
|
+
## Use Case: Programmatic ActivityInstance
|
|
598
|
+
|
|
599
|
+
For non-form scenarios (scripts, server-side, batch processing):
|
|
600
|
+
|
|
601
|
+
```typescript
|
|
602
|
+
import { SimpleLeaveProcess } from "@/bdo/workflows/SimpleLeaveProcess";
|
|
603
|
+
|
|
604
|
+
const wf = new SimpleLeaveProcess();
|
|
605
|
+
const activity = wf.employeeInputActivity();
|
|
606
|
+
|
|
607
|
+
// Get a typed instance
|
|
608
|
+
const instance = await activity.getInstance("inst_abc123");
|
|
609
|
+
|
|
610
|
+
// Read fields
|
|
611
|
+
console.log(instance.StartDate.get()); // "2026-02-01"
|
|
612
|
+
console.log(instance.LeaveType.get()); // "PTO"
|
|
613
|
+
console.log(instance.LeaveDays.get()); // 5 (computed)
|
|
614
|
+
|
|
615
|
+
// Write editable fields
|
|
616
|
+
instance.StartDate.set("2026-03-01");
|
|
617
|
+
instance.EndDate.set("2026-03-05");
|
|
618
|
+
|
|
619
|
+
// Field metadata
|
|
620
|
+
console.log(instance.StartDate.meta.label); // "Start Date"
|
|
621
|
+
|
|
622
|
+
// Persist changes
|
|
623
|
+
await instance.update({ StartDate: "2026-03-01", EndDate: "2026-03-05" });
|
|
624
|
+
|
|
625
|
+
// Save and commit
|
|
626
|
+
await instance.save({ StartDate: "2026-03-01", EndDate: "2026-03-05" });
|
|
627
|
+
|
|
628
|
+
// Complete activity
|
|
629
|
+
await instance.complete();
|
|
630
|
+
|
|
631
|
+
// Check progress
|
|
632
|
+
const progress = await instance.progress();
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
---
|
|
636
|
+
|
|
637
|
+
## Filtering Reference
|
|
638
|
+
|
|
639
|
+
### In-progress items
|
|
640
|
+
|
|
641
|
+
```typescript
|
|
642
|
+
const result = await activity.getInstanceList({
|
|
643
|
+
Filter: {
|
|
644
|
+
Operator: "And",
|
|
645
|
+
Condition: [
|
|
646
|
+
{ LHSField: "Status", Operator: "EQ", RHSValue: "InProgress", RHSType: "Constant" },
|
|
647
|
+
],
|
|
648
|
+
},
|
|
649
|
+
});
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
### Completed items
|
|
653
|
+
|
|
654
|
+
```typescript
|
|
655
|
+
const result = await activity.getInstanceList({
|
|
656
|
+
Filter: {
|
|
657
|
+
Operator: "And",
|
|
658
|
+
Condition: [
|
|
659
|
+
{ LHSField: "Status", Operator: "EQ", RHSValue: "Completed", RHSType: "Constant" },
|
|
660
|
+
],
|
|
661
|
+
},
|
|
662
|
+
});
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
### Assigned to a specific user
|
|
666
|
+
|
|
667
|
+
```typescript
|
|
668
|
+
const result = await activity.getInstanceList({
|
|
669
|
+
Filter: {
|
|
670
|
+
Operator: "And",
|
|
671
|
+
Condition: [
|
|
672
|
+
{ LHSField: "AssignedTo._id", Operator: "EQ", RHSValue: userId, RHSType: "Constant" },
|
|
673
|
+
],
|
|
674
|
+
},
|
|
675
|
+
});
|
|
676
|
+
```
|
|
677
|
+
|
|
678
|
+
### Combined: In-progress + assigned to user
|
|
679
|
+
|
|
680
|
+
```typescript
|
|
681
|
+
const result = await activity.getInstanceList({
|
|
682
|
+
Filter: {
|
|
683
|
+
Operator: "And",
|
|
684
|
+
Condition: [
|
|
685
|
+
{ LHSField: "Status", Operator: "EQ", RHSValue: "InProgress", RHSType: "Constant" },
|
|
686
|
+
{ LHSField: "AssignedTo._id", Operator: "EQ", RHSValue: userId, RHSType: "Constant" },
|
|
687
|
+
],
|
|
688
|
+
},
|
|
689
|
+
});
|
|
690
|
+
```
|
|
691
|
+
|
|
692
|
+
---
|
|
693
|
+
|
|
694
|
+
## ActivityInstance System Fields Reference
|
|
695
|
+
|
|
696
|
+
| Field | Type | Description |
|
|
697
|
+
|-------|------|-------------|
|
|
698
|
+
| `_id` | `StringFieldType` | Unique activity instance identifier |
|
|
699
|
+
| `Status` | `SelectFieldType<"InProgress" \| "Completed">` | Current status |
|
|
700
|
+
| `AssignedTo` | `ReferenceFieldType<UserRefType>` | Assigned user (has `._id` and `.username`) |
|
|
701
|
+
| `CompletedAt` | `DateTimeFieldType` | Completion timestamp (`"YYYY-MM-DDTHH:MM:SS"`) |
|
|
702
|
+
|
|
703
|
+
---
|