@ram_28/kf-ai-sdk 2.0.14 → 2.0.16

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.
Files changed (157) hide show
  1. package/README.md +10 -9
  2. package/dist/FileField-BWrSHNRq.js +296 -0
  3. package/dist/FileField-eDeuzln8.cjs +1 -0
  4. package/dist/api.cjs +1 -1
  5. package/dist/api.mjs +2 -2
  6. package/dist/auth.cjs +1 -1
  7. package/dist/auth.mjs +1 -1
  8. package/dist/bdo/core/BaseBdo.d.ts +1 -1
  9. package/dist/bdo.cjs +1 -1
  10. package/dist/bdo.mjs +230 -474
  11. package/dist/{client-DnO2KKrw.cjs → client-D5k4SYuw.cjs} +1 -1
  12. package/dist/{client-iQTqFDNI.js → client-_ayziI1d.js} +33 -32
  13. package/dist/components/hooks/index.d.ts +9 -3
  14. package/dist/components/hooks/index.d.ts.map +1 -1
  15. package/dist/{workflow/components → components/hooks}/useActivityForm/createActivityItemProxy.d.ts +9 -5
  16. package/dist/components/hooks/useActivityForm/createActivityItemProxy.d.ts.map +1 -0
  17. package/dist/components/hooks/useActivityForm/createActivityResolver.d.ts +23 -0
  18. package/dist/components/hooks/useActivityForm/createActivityResolver.d.ts.map +1 -0
  19. package/dist/components/hooks/useActivityForm/index.d.ts.map +1 -0
  20. package/dist/{workflow/components → components/hooks}/useActivityForm/types.d.ts +12 -8
  21. package/dist/components/hooks/useActivityForm/types.d.ts.map +1 -0
  22. package/dist/{workflow/components → components/hooks}/useActivityForm/useActivityForm.d.ts +2 -2
  23. package/dist/components/hooks/useActivityForm/useActivityForm.d.ts.map +1 -0
  24. package/dist/components/hooks/useActivityTable/index.d.ts +4 -0
  25. package/dist/components/hooks/useActivityTable/index.d.ts.map +1 -0
  26. package/dist/components/hooks/useActivityTable/types.d.ts +36 -0
  27. package/dist/components/hooks/useActivityTable/types.d.ts.map +1 -0
  28. package/dist/components/hooks/useActivityTable/useActivityTable.d.ts +4 -0
  29. package/dist/components/hooks/useActivityTable/useActivityTable.d.ts.map +1 -0
  30. package/dist/components/hooks/useBDOForm/createItemProxy.d.ts.map +1 -0
  31. package/dist/components/hooks/useBDOForm/createResolver.d.ts.map +1 -0
  32. package/dist/components/hooks/useBDOForm/index.d.ts +6 -0
  33. package/dist/components/hooks/useBDOForm/index.d.ts.map +1 -0
  34. package/dist/components/hooks/useBDOForm/shared.d.ts +50 -0
  35. package/dist/components/hooks/useBDOForm/shared.d.ts.map +1 -0
  36. package/dist/components/hooks/{useForm → useBDOForm}/types.d.ts +6 -6
  37. package/dist/components/hooks/useBDOForm/types.d.ts.map +1 -0
  38. package/dist/components/hooks/{useForm/useForm.d.ts → useBDOForm/useBDOForm.d.ts} +4 -4
  39. package/dist/components/hooks/useBDOForm/useBDOForm.d.ts.map +1 -0
  40. package/dist/components/hooks/useBDOTable/index.d.ts +3 -0
  41. package/dist/components/hooks/useBDOTable/index.d.ts.map +1 -0
  42. package/dist/components/hooks/useBDOTable/types.d.ts +24 -0
  43. package/dist/components/hooks/useBDOTable/types.d.ts.map +1 -0
  44. package/dist/components/hooks/useBDOTable/useBDOTable.d.ts +3 -0
  45. package/dist/components/hooks/useBDOTable/useBDOTable.d.ts.map +1 -0
  46. package/dist/components/hooks/useTable/index.d.ts +2 -2
  47. package/dist/components/hooks/useTable/index.d.ts.map +1 -1
  48. package/dist/components/hooks/useTable/types.d.ts +11 -10
  49. package/dist/components/hooks/useTable/types.d.ts.map +1 -1
  50. package/dist/components/hooks/useTable/useTable.d.ts +1 -1
  51. package/dist/components/hooks/useTable/useTable.d.ts.map +1 -1
  52. package/dist/form.cjs +1 -1
  53. package/dist/form.d.ts +1 -1
  54. package/dist/form.d.ts.map +1 -1
  55. package/dist/form.mjs +279 -344
  56. package/dist/form.types.d.ts +1 -1
  57. package/dist/form.types.d.ts.map +1 -1
  58. package/dist/{metadata-DpfI3zRN.js → metadata-Cc1mBcLS.js} +1 -1
  59. package/dist/{metadata-DgLSJkF5.cjs → metadata-DWXQPDav.cjs} +1 -1
  60. package/dist/shared-5a7UkED1.js +1180 -0
  61. package/dist/shared-nnmlRVs7.cjs +1 -0
  62. package/dist/table.cjs +1 -1
  63. package/dist/table.d.ts +1 -0
  64. package/dist/table.d.ts.map +1 -1
  65. package/dist/table.mjs +17 -192
  66. package/dist/table.types.d.ts +2 -1
  67. package/dist/table.types.d.ts.map +1 -1
  68. package/dist/types/base-fields.d.ts +4 -4
  69. package/dist/types/base-fields.d.ts.map +1 -1
  70. package/dist/types/constants.d.ts +3 -3
  71. package/dist/useTable-CeRklbdT.cjs +1 -0
  72. package/dist/useTable-DS0-WInw.js +203 -0
  73. package/dist/workflow/Activity.d.ts +19 -7
  74. package/dist/workflow/Activity.d.ts.map +1 -1
  75. package/dist/workflow/client.d.ts +2 -2
  76. package/dist/workflow/client.d.ts.map +1 -1
  77. package/dist/workflow/createFieldFromMeta.d.ts +29 -0
  78. package/dist/workflow/createFieldFromMeta.d.ts.map +1 -0
  79. package/dist/workflow/index.d.ts +1 -2
  80. package/dist/workflow/index.d.ts.map +1 -1
  81. package/dist/workflow/types.d.ts +16 -12
  82. package/dist/workflow/types.d.ts.map +1 -1
  83. package/dist/workflow.cjs +1 -1
  84. package/dist/workflow.d.ts +5 -2
  85. package/dist/workflow.d.ts.map +1 -1
  86. package/dist/workflow.mjs +687 -352
  87. package/dist/workflow.types.d.ts +1 -0
  88. package/dist/workflow.types.d.ts.map +1 -1
  89. package/docs/bdo.md +1 -1
  90. package/docs/gaps.md +360 -0
  91. package/docs/useActivityForm.md +393 -0
  92. package/docs/useActivityTable.md +418 -0
  93. package/docs/{useForm.md → useBDOForm.md} +24 -24
  94. package/docs/useBDOTable.md +284 -0
  95. package/docs/workflow.md +148 -297
  96. package/package.json +2 -2
  97. package/sdk/bdo/core/BaseBdo.ts +2 -2
  98. package/sdk/bdo/fields/UserField.ts +1 -1
  99. package/sdk/components/hooks/index.ts +28 -5
  100. package/sdk/components/hooks/useActivityForm/createActivityItemProxy.ts +400 -0
  101. package/sdk/components/hooks/useActivityForm/createActivityResolver.ts +87 -0
  102. package/sdk/{workflow/components → components/hooks}/useActivityForm/types.ts +24 -11
  103. package/sdk/components/hooks/useActivityForm/useActivityForm.ts +478 -0
  104. package/sdk/components/hooks/useActivityTable/index.ts +8 -0
  105. package/sdk/components/hooks/useActivityTable/types.ts +47 -0
  106. package/sdk/components/hooks/useActivityTable/useActivityTable.ts +40 -0
  107. package/sdk/components/hooks/{useForm → useBDOForm}/index.ts +4 -3
  108. package/sdk/components/hooks/useBDOForm/shared.ts +250 -0
  109. package/sdk/components/hooks/{useForm → useBDOForm}/types.ts +9 -9
  110. package/sdk/components/hooks/{useForm/useForm.ts → useBDOForm/useBDOForm.ts} +70 -96
  111. package/sdk/components/hooks/useBDOTable/index.ts +2 -0
  112. package/sdk/components/hooks/useBDOTable/types.ts +22 -0
  113. package/sdk/components/hooks/useBDOTable/useBDOTable.ts +16 -0
  114. package/sdk/components/hooks/useTable/index.ts +3 -3
  115. package/sdk/components/hooks/useTable/types.ts +16 -12
  116. package/sdk/components/hooks/useTable/useTable.ts +56 -49
  117. package/sdk/form.ts +2 -2
  118. package/sdk/form.types.ts +4 -4
  119. package/sdk/table.ts +4 -1
  120. package/sdk/table.types.ts +7 -4
  121. package/sdk/types/base-fields.ts +4 -4
  122. package/sdk/types/constants.ts +3 -3
  123. package/sdk/workflow/Activity.ts +36 -12
  124. package/sdk/workflow/client.ts +65 -12
  125. package/sdk/workflow/createFieldFromMeta.ts +110 -0
  126. package/sdk/workflow/index.ts +1 -6
  127. package/sdk/workflow/types.ts +20 -11
  128. package/sdk/workflow.ts +11 -2
  129. package/sdk/workflow.types.ts +7 -0
  130. package/dist/BaseField-B6da88U7.js +0 -40
  131. package/dist/BaseField-Drp0-OxL.cjs +0 -1
  132. package/dist/components/hooks/useForm/createItemProxy.d.ts.map +0 -1
  133. package/dist/components/hooks/useForm/createResolver.d.ts.map +0 -1
  134. package/dist/components/hooks/useForm/index.d.ts +0 -5
  135. package/dist/components/hooks/useForm/index.d.ts.map +0 -1
  136. package/dist/components/hooks/useForm/types.d.ts.map +0 -1
  137. package/dist/components/hooks/useForm/useForm.d.ts.map +0 -1
  138. package/dist/error-handling-CAoD0Kwb.cjs +0 -1
  139. package/dist/error-handling-CrhTtD88.js +0 -14
  140. package/dist/index.esm-Cj63v5ny.js +0 -1014
  141. package/dist/index.esm-DuwT11sx.cjs +0 -1
  142. package/dist/workflow/components/useActivityForm/createActivityItemProxy.d.ts.map +0 -1
  143. package/dist/workflow/components/useActivityForm/createActivityResolver.d.ts +0 -22
  144. package/dist/workflow/components/useActivityForm/createActivityResolver.d.ts.map +0 -1
  145. package/dist/workflow/components/useActivityForm/index.d.ts.map +0 -1
  146. package/dist/workflow/components/useActivityForm/types.d.ts.map +0 -1
  147. package/dist/workflow/components/useActivityForm/useActivityForm.d.ts.map +0 -1
  148. package/docs/useTable.md +0 -369
  149. package/sdk/workflow/components/useActivityForm/createActivityItemProxy.ts +0 -130
  150. package/sdk/workflow/components/useActivityForm/createActivityResolver.ts +0 -61
  151. package/sdk/workflow/components/useActivityForm/useActivityForm.ts +0 -386
  152. /package/dist/{workflow/components → components/hooks}/useActivityForm/index.d.ts +0 -0
  153. /package/dist/components/hooks/{useForm → useBDOForm}/createItemProxy.d.ts +0 -0
  154. /package/dist/components/hooks/{useForm → useBDOForm}/createResolver.d.ts +0 -0
  155. /package/sdk/{workflow/components → components/hooks}/useActivityForm/index.ts +0 -0
  156. /package/sdk/components/hooks/{useForm → useBDOForm}/createItemProxy.ts +0 -0
  157. /package/sdk/components/hooks/{useForm → useBDOForm}/createResolver.ts +0 -0
@@ -0,0 +1,478 @@
1
+ // ============================================================
2
+ // USE ACTIVITY FORM HOOK (v2 — Metadata-driven)
3
+ // ============================================================
4
+ // React hook for building forms bound to workflow activity input fields.
5
+ // Fetches BP metadata at runtime, discovers Input fields dynamically,
6
+ // and uses update() on blur (not draftStart/draftEnd).
7
+
8
+ import { useState, useEffect, useCallback, useMemo, useRef } from 'react';
9
+ import { useForm as useReactHookForm } from 'react-hook-form';
10
+ import { useQuery } from '@tanstack/react-query';
11
+
12
+ import type { Activity } from '../../../workflow/Activity';
13
+ import type {
14
+ UseActivityFormOptions,
15
+ UseActivityFormReturn,
16
+ AllActivityFields,
17
+ } from './types';
18
+
19
+ import { createActivityResolver } from './createActivityResolver';
20
+ import { createActivityItemProxy } from './createActivityItemProxy';
21
+ import {
22
+ coerceFieldValue,
23
+ coerceRecordForForm,
24
+ createSyncField,
25
+ createEnhancedRegister,
26
+ createEnhancedControl,
27
+ } from '../useBDOForm/shared';
28
+ import { toError } from '../../../utils/error-handling';
29
+ import { getBdoSchema } from '../../../api/metadata';
30
+ import {
31
+ buildFieldsFromInput,
32
+ createFieldFromMeta,
33
+ findFieldInBpActivities,
34
+ } from '../../../workflow/createFieldFromMeta';
35
+ import type { BaseField } from '../../../bdo/fields/BaseField';
36
+
37
+ // ============================================================
38
+ // MAIN HOOK
39
+ // ============================================================
40
+
41
+ export function useActivityForm<A extends Activity<any, any, any>>(
42
+ activity: A,
43
+ options: UseActivityFormOptions<A>,
44
+ ): UseActivityFormReturn<A> {
45
+ const {
46
+ activity_instance_id,
47
+ defaultValues = {},
48
+ mode = 'onBlur',
49
+ enabled = true,
50
+ } = options;
51
+
52
+ // ============================================================
53
+ // STATE
54
+ // ============================================================
55
+
56
+ const [isLoading, setIsLoading] = useState(false);
57
+ const [loadError, setLoadError] = useState<Error | null>(null);
58
+ const [isSubmitting, setIsSubmitting] = useState(false);
59
+
60
+ // Extra readonly fields discovered from read() response (Context-derived)
61
+ const [extraReadonlyFields, setExtraReadonlyFields] = useState<
62
+ Record<string, BaseField<unknown>>
63
+ >({});
64
+
65
+ // Prevent concurrent update calls
66
+ const isComputingRef = useRef(false);
67
+
68
+ // Track last data reference to avoid unnecessary resets
69
+ const lastResetDataRef = useRef<Record<string, unknown> | null>(null);
70
+
71
+ // ============================================================
72
+ // 1. FETCH BP METADATA
73
+ // ============================================================
74
+
75
+ const { data: bpSchema, isLoading: isBpLoading } = useQuery({
76
+ queryKey: ['bp-metadata', activity.meta.businessProcessId],
77
+ queryFn: () => getBdoSchema(activity.meta.businessProcessId),
78
+ staleTime: 30 * 60 * 1000,
79
+ });
80
+
81
+ // ============================================================
82
+ // 2. EXTRACT ACTIVITY DEFINITION FROM BP BLOB
83
+ // ============================================================
84
+
85
+ const activityDef = useMemo(() => {
86
+ const blob = bpSchema?.BDOBlob;
87
+ if (!blob?.Activity) return null;
88
+ return (
89
+ (blob.Activity as any[]).find(
90
+ (a: any) => a.Id === activity.meta.activityId,
91
+ ) ?? null
92
+ );
93
+ }, [bpSchema, activity.meta.activityId]);
94
+
95
+ const isMetadataLoading = isBpLoading;
96
+
97
+ // ============================================================
98
+ // 5. BUILD DYNAMIC FIELDS FROM INPUT METADATA
99
+ // ============================================================
100
+
101
+ const dynamicFields = useMemo(() => {
102
+ if (!activityDef?.Input) return activity._getFields(); // fallback to class fields
103
+ return buildFieldsFromInput(activityDef.Input as Record<string, Record<string, unknown>>);
104
+ }, [activityDef, activity]);
105
+
106
+ // ============================================================
107
+ // 5b. COMBINE ALL FIELDS (Input + extra readonly from Context)
108
+ // ============================================================
109
+
110
+ const allFields = useMemo(
111
+ () => ({
112
+ ...extraReadonlyFields, // readonly fields from other activities
113
+ ...dynamicFields, // Input fields (editable + readonly)
114
+ }),
115
+ [extraReadonlyFields, dynamicFields],
116
+ );
117
+
118
+ // Identify readonly fields (Formula fields, or fields with ReadOnly: true)
119
+ const readonlyFieldNames = useMemo<string[]>(
120
+ () => Object.keys(allFields).filter((k) => allFields[k].readOnly),
121
+ [allFields],
122
+ );
123
+
124
+ // ============================================================
125
+ // 6. RESOLVER (from dynamic fields — type + constraint validation)
126
+ // ============================================================
127
+
128
+ const resolver = useMemo(
129
+ () => createActivityResolver(dynamicFields),
130
+ [dynamicFields],
131
+ );
132
+
133
+ // ============================================================
134
+ // REACT HOOK FORM
135
+ // ============================================================
136
+
137
+ // NOTE: Don't use `values` prop — it continuously syncs and overrides
138
+ // setValue() calls for unregistered fields (Image/File attachments).
139
+ // Instead, we reset once when record arrives (see useEffect below).
140
+ const rhf = useReactHookForm({
141
+ mode,
142
+ defaultValues: defaultValues as any,
143
+ resolver,
144
+ });
145
+
146
+ // ============================================================
147
+ // ACTIVITY OPERATIONS
148
+ // ============================================================
149
+
150
+ const activityRef = useMemo(() => activity._getOps(), [activity]);
151
+
152
+ // ============================================================
153
+ // ITEM PROXY (always in sync with RHF state)
154
+ // ============================================================
155
+
156
+ const item = useMemo(
157
+ () =>
158
+ createActivityItemProxy(activity, rhf as any, activity_instance_id),
159
+ [activity, rhf, activity_instance_id],
160
+ );
161
+
162
+ // ============================================================
163
+ // LOAD EXISTING DATA — activity.read() on mount
164
+ // ============================================================
165
+
166
+ useEffect(() => {
167
+ if (!enabled || isMetadataLoading) return;
168
+
169
+ let active = true;
170
+
171
+ const loadData = async () => {
172
+ setIsLoading(true);
173
+ setLoadError(null);
174
+
175
+ try {
176
+ const data = await activityRef.read(activity_instance_id);
177
+
178
+ if (!active) return;
179
+
180
+ // Populate form with existing data
181
+ if (data && typeof data === 'object') {
182
+ const coerced = coerceRecordForForm(
183
+ dynamicFields,
184
+ data as Record<string, unknown>,
185
+ );
186
+ const merged = { ...defaultValues, ...coerced };
187
+
188
+ if (
189
+ lastResetDataRef.current === null ||
190
+ data !== lastResetDataRef.current
191
+ ) {
192
+ rhf.reset(merged as any);
193
+ lastResetDataRef.current = data as Record<string, unknown>;
194
+ }
195
+
196
+ // Detect extra fields from Context (not in Input metadata)
197
+ const activitySystemFields = new Set([
198
+ '_id',
199
+ 'BPInstanceId',
200
+ 'Status',
201
+ 'AssignedTo',
202
+ 'CompletedAt',
203
+ '_created_at',
204
+ '_modified_at',
205
+ '_created_by',
206
+ '_modified_by',
207
+ '_v',
208
+ '_m_v',
209
+ ]);
210
+
211
+ const extras: Record<string, BaseField<unknown>> = {};
212
+ for (const key of Object.keys(data)) {
213
+ if (!dynamicFields[key] && !activitySystemFields.has(key)) {
214
+ // Look up field definition from other activities in the BP
215
+ const fieldDef = findFieldInBpActivities(
216
+ activityDef,
217
+ bpSchema,
218
+ key,
219
+ );
220
+ if (fieldDef) {
221
+ extras[key] = createFieldFromMeta(key, {
222
+ ...fieldDef,
223
+ ReadOnly: true,
224
+ });
225
+ }
226
+ }
227
+ }
228
+ if (Object.keys(extras).length > 0) {
229
+ setExtraReadonlyFields(extras);
230
+ }
231
+ }
232
+ } catch (error) {
233
+ if (!active) return;
234
+ console.error('Failed to read activity data:', error);
235
+ setLoadError(toError(error));
236
+ } finally {
237
+ if (active) {
238
+ setIsLoading(false);
239
+ }
240
+ }
241
+ };
242
+
243
+ loadData();
244
+
245
+ return () => {
246
+ active = false;
247
+ };
248
+ // eslint-disable-next-line react-hooks/exhaustive-deps
249
+ }, [enabled, isMetadataLoading, activityRef, activity_instance_id]);
250
+
251
+ // ============================================================
252
+ // PER-FIELD SYNC (shared with useBDOForm)
253
+ // ============================================================
254
+
255
+ const syncApiFn = useCallback(
256
+ (fieldName: string, value: unknown) =>
257
+ activityRef.update(activity_instance_id, {
258
+ [fieldName]: value,
259
+ } as any),
260
+ [activityRef, activity_instance_id],
261
+ );
262
+
263
+ const syncField = useMemo(
264
+ () =>
265
+ createSyncField({
266
+ apiFn: syncApiFn,
267
+ allFields,
268
+ readonlyFieldNames,
269
+ rhf,
270
+ isComputingRef,
271
+ }),
272
+ [syncApiFn, allFields, readonlyFieldNames, rhf],
273
+ );
274
+
275
+ const syncOnChange = mode === 'onChange' || mode === 'all';
276
+ const syncOnBlur =
277
+ mode === 'onBlur' || mode === 'onTouched' || mode === 'all';
278
+
279
+ const register = useMemo(
280
+ () =>
281
+ createEnhancedRegister({
282
+ rhf,
283
+ allFields,
284
+ syncField,
285
+ syncOnBlur,
286
+ syncOnChange,
287
+ }),
288
+ [rhf, allFields, syncField, syncOnBlur, syncOnChange],
289
+ ) as UseActivityFormReturn<A>['register'];
290
+
291
+ const enhancedControl = useMemo(
292
+ () =>
293
+ createEnhancedControl({
294
+ control: rhf.control,
295
+ syncField,
296
+ syncOnBlur,
297
+ syncOnChange,
298
+ }),
299
+ [rhf.control, syncField, syncOnBlur, syncOnChange],
300
+ );
301
+
302
+ // ============================================================
303
+ // HANDLE SUBMIT — activity.update()
304
+ // ============================================================
305
+
306
+ const handleSubmit = useCallback(
307
+ (
308
+ onSuccess?: (
309
+ data: AllActivityFields<A>,
310
+ e?: React.BaseSyntheticEvent,
311
+ ) => void | Promise<void>,
312
+ onError?: (
313
+ error: any,
314
+ e?: React.BaseSyntheticEvent,
315
+ ) => void | Promise<void>,
316
+ ) => {
317
+ return rhf.handleSubmit(
318
+ async (data, event) => {
319
+ setIsSubmitting(true);
320
+
321
+ try {
322
+ // Only send dirty (changed) fields — matches useBDOForm update behavior
323
+ // Use getValues() to capture Image/File values set via setValue()
324
+ // that RHF resolver doesn't include in `data`
325
+ const cleanedData: Record<string, unknown> = {};
326
+ const readonlySet = new Set(readonlyFieldNames);
327
+ const dirtyFields = rhf.formState.dirtyFields;
328
+ const allValues = rhf.getValues() as Record<string, unknown>;
329
+
330
+ for (const key of Object.keys(allValues)) {
331
+ if (readonlySet.has(key) || !dirtyFields[key]) continue;
332
+ const value =
333
+ allValues[key] !== undefined
334
+ ? allValues[key]
335
+ : (data as Record<string, unknown>)[key];
336
+ const field = allFields[key];
337
+ cleanedData[key] = field
338
+ ? coerceFieldValue(field, value)
339
+ : value;
340
+ }
341
+
342
+ // Save via activity.update()
343
+ if (Object.keys(cleanedData).length > 0) {
344
+ await activityRef.update(
345
+ activity_instance_id,
346
+ cleanedData as any,
347
+ );
348
+ }
349
+
350
+ await onSuccess?.(data as AllActivityFields<A>, event);
351
+ } catch (error) {
352
+ onError?.(toError(error), event);
353
+ } finally {
354
+ setIsSubmitting(false);
355
+ }
356
+ },
357
+ (errors, event) => {
358
+ onError?.(errors, event);
359
+ },
360
+ );
361
+ },
362
+ [rhf, activityRef, readonlyFieldNames, allFields, activity_instance_id],
363
+ ) as UseActivityFormReturn<A>['handleSubmit'];
364
+
365
+ // ============================================================
366
+ // HANDLE COMPLETE — activity.update() + activity.complete()
367
+ // ============================================================
368
+
369
+ const handleComplete = useCallback(
370
+ (
371
+ onSuccess?: (
372
+ data: AllActivityFields<A>,
373
+ e?: React.BaseSyntheticEvent,
374
+ ) => void | Promise<void>,
375
+ onError?: (
376
+ error: any,
377
+ e?: React.BaseSyntheticEvent,
378
+ ) => void | Promise<void>,
379
+ ) => {
380
+ return rhf.handleSubmit(
381
+ async (data, event) => {
382
+ setIsSubmitting(true);
383
+
384
+ try {
385
+ // Only send dirty (changed) fields — matches useBDOForm update behavior
386
+ // Use getValues() to capture Image/File values set via setValue()
387
+ // that RHF resolver doesn't include in `data`
388
+ const cleanedData: Record<string, unknown> = {};
389
+ const readonlySet = new Set(readonlyFieldNames);
390
+ const dirtyFields = rhf.formState.dirtyFields;
391
+ const allValues = rhf.getValues() as Record<string, unknown>;
392
+
393
+ for (const key of Object.keys(allValues)) {
394
+ if (readonlySet.has(key) || !dirtyFields[key]) continue;
395
+ const value =
396
+ allValues[key] !== undefined
397
+ ? allValues[key]
398
+ : (data as Record<string, unknown>)[key];
399
+ const field = allFields[key];
400
+ cleanedData[key] = field
401
+ ? coerceFieldValue(field, value)
402
+ : value;
403
+ }
404
+
405
+ if (Object.keys(cleanedData).length > 0) {
406
+ await activityRef.update(
407
+ activity_instance_id,
408
+ cleanedData as any,
409
+ );
410
+ }
411
+ await activityRef.complete(activity_instance_id);
412
+ await onSuccess?.(data as AllActivityFields<A>, event);
413
+ } catch (error) {
414
+ onError?.(toError(error), event);
415
+ } finally {
416
+ setIsSubmitting(false);
417
+ }
418
+ },
419
+ (errors, event) => {
420
+ onError?.(errors, event);
421
+ },
422
+ );
423
+ },
424
+ [rhf, activityRef, readonlyFieldNames, allFields, activity_instance_id],
425
+ ) as UseActivityFormReturn<A>['handleComplete'];
426
+
427
+ // ============================================================
428
+ // CLEAR ERRORS
429
+ // ============================================================
430
+
431
+ const clearErrors = useCallback((): void => {
432
+ rhf.clearErrors();
433
+ }, [rhf]);
434
+
435
+ // ============================================================
436
+ // RETURN
437
+ // ============================================================
438
+
439
+ const hasError = !!loadError;
440
+
441
+ return {
442
+ // Item proxy
443
+ item,
444
+
445
+ // Activity reference
446
+ activity,
447
+
448
+ // Form methods
449
+ register,
450
+ handleSubmit,
451
+ handleComplete,
452
+ watch: rhf.watch as any,
453
+ setValue: rhf.setValue as any,
454
+ getValues: rhf.getValues as any,
455
+ reset: rhf.reset as any,
456
+ trigger: rhf.trigger as any,
457
+ control: enhancedControl as any,
458
+
459
+ // Flattened form state
460
+ errors: rhf.formState.errors as any,
461
+ isValid: rhf.formState.isValid,
462
+ isDirty: rhf.formState.isDirty,
463
+ isSubmitting: rhf.formState.isSubmitting || isSubmitting,
464
+ isSubmitSuccessful: rhf.formState.isSubmitSuccessful,
465
+
466
+ // Loading
467
+ isLoading: isLoading || isMetadataLoading,
468
+ isMetadataLoading,
469
+ loadError,
470
+ hasError,
471
+
472
+ // Metadata
473
+ bpMetadata: bpSchema ?? null,
474
+
475
+ // Operations
476
+ clearErrors,
477
+ };
478
+ }
@@ -0,0 +1,8 @@
1
+ export { useActivityTable } from './useActivityTable';
2
+ export { ActivityTableStatus } from './types';
3
+ export type {
4
+ UseActivityTableOptionsType,
5
+ UseActivityTableReturnType,
6
+ ActivityTableStatusType,
7
+ ActivityRowType,
8
+ } from './types';
@@ -0,0 +1,47 @@
1
+ import type { Activity } from '../../../workflow/Activity';
2
+ import type { ActivityInstanceFieldsType } from '../../../workflow/types';
3
+ import type { UseTableReturnType, PaginationStateType } from '../useTable/types';
4
+ import type { UseFilterOptionsType } from '../useFilter/types';
5
+ import type { SortType } from '../../../types/common';
6
+
7
+ /**
8
+ * Activity table status — determines which API to call
9
+ */
10
+ export const ActivityTableStatus = {
11
+ InProgress: 'inprogress',
12
+ Completed: 'completed',
13
+ } as const;
14
+
15
+ export type ActivityTableStatusType =
16
+ (typeof ActivityTableStatus)[keyof typeof ActivityTableStatus];
17
+
18
+ /**
19
+ * Row type for activity table data.
20
+ * System fields and entity fields are flat at the top level.
21
+ */
22
+ export type ActivityRowType<A extends Activity<any, any, any>> =
23
+ A extends Activity<infer E, any, any>
24
+ ? ActivityInstanceFieldsType & E
25
+ : never;
26
+
27
+ export interface UseActivityTableOptionsType<
28
+ A extends Activity<any, any, any>,
29
+ > {
30
+ /** The activity instance to fetch data for */
31
+ activity: A;
32
+ /** Which operation — determines endpoint (inprogress vs completed) */
33
+ status: ActivityTableStatusType;
34
+ /** Initial state */
35
+ initialState?: {
36
+ sort?: SortType;
37
+ pagination?: PaginationStateType;
38
+ filter?: UseFilterOptionsType<ActivityRowType<A>>;
39
+ };
40
+ /** Error callback */
41
+ onError?: (error: Error) => void;
42
+ /** Success callback with row data */
43
+ onSuccess?: (data: ActivityRowType<A>[]) => void;
44
+ }
45
+
46
+ export type UseActivityTableReturnType<A extends Activity<any, any, any>> =
47
+ UseTableReturnType<ActivityRowType<A>>;
@@ -0,0 +1,40 @@
1
+ import { useMemo } from 'react';
2
+ import { useTable } from '../useTable';
3
+ import type { Activity } from '../../../workflow/Activity';
4
+ import type {
5
+ UseActivityTableOptionsType,
6
+ UseActivityTableReturnType,
7
+ ActivityRowType,
8
+ } from './types';
9
+
10
+ export function useActivityTable<A extends Activity<any, any, any>>(
11
+ options: UseActivityTableOptionsType<A>,
12
+ ): UseActivityTableReturnType<A> {
13
+ const { activity, status, ...rest } = options;
14
+ const { businessProcessId, activityId } = activity.meta;
15
+
16
+ const ops = useMemo(() => activity._getOps(), [activity]);
17
+
18
+ const listFn = useMemo(
19
+ () =>
20
+ status === 'inprogress'
21
+ ? (opts: any) => ops.inProgressList(opts)
22
+ : (opts: any) => ops.completedList(opts),
23
+ [ops, status],
24
+ );
25
+
26
+ const countFn = useMemo(
27
+ () =>
28
+ status === 'inprogress'
29
+ ? (opts: any) => ops.inProgressCount(opts)
30
+ : (opts: any) => ops.completedCount(opts),
31
+ [ops, status],
32
+ );
33
+
34
+ return useTable<ActivityRowType<A>>({
35
+ queryKey: ['activity-table', businessProcessId, activityId, status],
36
+ listFn,
37
+ countFn,
38
+ ...rest,
39
+ });
40
+ }
@@ -1,9 +1,10 @@
1
- export { useForm } from "./useForm";
1
+ export { useBDOForm } from "./useBDOForm";
2
2
  export { createResolver } from "./createResolver";
3
3
  export { createItemProxy } from "./createItemProxy";
4
+ export { coerceFieldValue, coerceRecordForForm } from "./shared";
4
5
  export type {
5
- UseFormOptionsType,
6
- UseFormReturnType,
6
+ UseBDOFormOptionsType,
7
+ UseBDOFormReturnType,
7
8
  FormItemType,
8
9
  EditableFormFieldAccessorType,
9
10
  ReadonlyFormFieldAccessorType,