@ram_28/kf-ai-sdk 1.0.20 → 1.0.22
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/api/client.d.ts.map +1 -1
- package/dist/api/datetime.d.ts +59 -10
- package/dist/api/datetime.d.ts.map +1 -1
- package/dist/api/index.d.ts +3 -2
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api.cjs +1 -1
- package/dist/api.d.ts +1 -1
- package/dist/api.d.ts.map +1 -1
- package/dist/api.mjs +43 -21
- package/dist/api.types.d.ts +2 -1
- package/dist/api.types.d.ts.map +1 -1
- package/dist/auth/AuthProvider.d.ts.map +1 -1
- package/dist/auth.cjs +1 -1
- package/dist/auth.mjs +34 -34
- package/dist/base-types.d.ts +1 -1
- package/dist/base-types.d.ts.map +1 -1
- package/dist/client-BIkaIr2y.js +217 -0
- package/dist/client-DxjRcEtN.cjs +1 -0
- package/dist/components/hooks/useForm/apiClient.d.ts +45 -4
- package/dist/components/hooks/useForm/apiClient.d.ts.map +1 -1
- package/dist/components/hooks/useForm/types.d.ts +8 -0
- package/dist/components/hooks/useForm/types.d.ts.map +1 -1
- package/dist/components/hooks/useForm/useForm.d.ts.map +1 -1
- package/dist/form.cjs +1 -1
- package/dist/form.mjs +1028 -1051
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/kanban.cjs +1 -1
- package/dist/kanban.mjs +1 -1
- package/dist/{metadata-0lZAfuTP.cjs → metadata-Bz8zJqC1.cjs} +1 -1
- package/dist/{metadata-B88D_pVS.js → metadata-VbQzyD2C.js} +1 -1
- package/dist/table.cjs +1 -1
- package/dist/table.mjs +1 -1
- package/dist/types/base-fields.d.ts +71 -17
- package/dist/types/base-fields.d.ts.map +1 -1
- package/dist/types/common.d.ts +0 -12
- package/dist/types/common.d.ts.map +1 -1
- package/package.json +1 -1
- package/sdk/api/client.ts +3 -41
- package/sdk/api/datetime.ts +98 -14
- package/sdk/api/index.ts +12 -6
- package/sdk/api.ts +6 -3
- package/sdk/api.types.ts +3 -4
- package/sdk/auth/AuthProvider.tsx +22 -24
- package/sdk/base-types.ts +2 -0
- package/sdk/components/hooks/useForm/apiClient.ts +118 -4
- package/sdk/components/hooks/useForm/types.ts +9 -0
- package/sdk/components/hooks/useForm/useForm.ts +79 -60
- package/sdk/index.ts +3 -0
- package/sdk/types/base-fields.ts +71 -17
- package/sdk/types/common.ts +2 -13
- package/dist/client-DgtkT50N.cjs +0 -1
- package/dist/client-V-WzUb8H.js +0 -237
package/sdk/base-types.ts
CHANGED
|
@@ -135,7 +135,62 @@ export async function submitFormData<T = any>(
|
|
|
135
135
|
// ============================================================
|
|
136
136
|
|
|
137
137
|
/**
|
|
138
|
-
* Fetch reference field data
|
|
138
|
+
* Fetch reference field data using the fetchField API
|
|
139
|
+
* This correctly uses instance context for filter evaluation
|
|
140
|
+
*/
|
|
141
|
+
export async function fetchReferenceFieldData(
|
|
142
|
+
boId: string,
|
|
143
|
+
instanceId: string,
|
|
144
|
+
fieldId: string
|
|
145
|
+
): Promise<Array<{ Value: string; Label: string }>> {
|
|
146
|
+
try {
|
|
147
|
+
// Calls GET /{boId}/{instanceId}/field/{fieldId}/fetch
|
|
148
|
+
return await api(boId).fetchField(instanceId, fieldId);
|
|
149
|
+
} catch (error) {
|
|
150
|
+
console.error(`Reference data fetch error for ${fieldId}:`, error);
|
|
151
|
+
return [];
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Fetch all reference data for a form
|
|
157
|
+
* @param boId - The Business Object ID
|
|
158
|
+
* @param instanceId - The instance ID (draftId for create, recordId for update)
|
|
159
|
+
* @param referenceFieldIds - Array of reference field IDs to fetch
|
|
160
|
+
*/
|
|
161
|
+
export async function fetchAllReferenceFieldData(
|
|
162
|
+
boId: string,
|
|
163
|
+
instanceId: string,
|
|
164
|
+
referenceFieldIds: string[]
|
|
165
|
+
): Promise<Record<string, Array<{ Value: string; Label: string }>>> {
|
|
166
|
+
const referenceData: Record<string, Array<{ Value: string; Label: string }>> = {};
|
|
167
|
+
|
|
168
|
+
// Fetch all reference data in parallel
|
|
169
|
+
const fetchPromises = referenceFieldIds.map(async (fieldId) => {
|
|
170
|
+
try {
|
|
171
|
+
const data = await fetchReferenceFieldData(boId, instanceId, fieldId);
|
|
172
|
+
return [fieldId, data] as const;
|
|
173
|
+
} catch (error) {
|
|
174
|
+
console.warn(`Failed to fetch reference data for ${fieldId}:`, error);
|
|
175
|
+
return [fieldId, []] as const;
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
const results = await Promise.allSettled(fetchPromises);
|
|
180
|
+
|
|
181
|
+
results.forEach((result) => {
|
|
182
|
+
if (result.status === "fulfilled") {
|
|
183
|
+
const [fieldId, data] = result.value;
|
|
184
|
+
referenceData[fieldId] = [...data];
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
return referenceData;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* @deprecated Use fetchReferenceFieldData instead
|
|
193
|
+
* Legacy function that fetches reference data using list() API
|
|
139
194
|
*/
|
|
140
195
|
export async function fetchReferenceData(
|
|
141
196
|
businessObject: string,
|
|
@@ -171,7 +226,8 @@ export async function fetchReferenceData(
|
|
|
171
226
|
}
|
|
172
227
|
|
|
173
228
|
/**
|
|
174
|
-
*
|
|
229
|
+
* @deprecated Use fetchAllReferenceFieldData instead
|
|
230
|
+
* Legacy function that fetches all reference data using list() API
|
|
175
231
|
*/
|
|
176
232
|
export async function fetchAllReferenceData(
|
|
177
233
|
referenceFields: Record<string, any>
|
|
@@ -239,18 +295,26 @@ export function validateFormData<T>(
|
|
|
239
295
|
* Clean form data before submission
|
|
240
296
|
* - For create: returns all non-computed, non-undefined fields
|
|
241
297
|
* - For update: returns only fields that changed from originalData
|
|
298
|
+
* - Transforms Reference fields to JSON format expected by backend
|
|
299
|
+
*
|
|
300
|
+
* @param data - Form data to clean
|
|
301
|
+
* @param computedFields - Array of computed field names to exclude
|
|
302
|
+
* @param operation - "create" or "update"
|
|
303
|
+
* @param originalData - Original data for comparison (update only)
|
|
304
|
+
* @param fieldTypes - Map of field names to their BDO types (e.g., { "SupplierInfo": "Reference" })
|
|
242
305
|
*/
|
|
243
306
|
export function cleanFormData<T>(
|
|
244
307
|
data: Partial<T>,
|
|
245
308
|
computedFields: string[],
|
|
246
309
|
operation: FormOperationType = "create",
|
|
247
|
-
originalData?: Partial<T
|
|
310
|
+
originalData?: Partial<T>,
|
|
311
|
+
fieldTypes?: Record<string, string>
|
|
248
312
|
): Partial<T> {
|
|
249
313
|
const cleanedData: Partial<T> = {};
|
|
250
314
|
|
|
251
315
|
Object.keys(data).forEach((key) => {
|
|
252
316
|
const fieldKey = key as keyof T;
|
|
253
|
-
|
|
317
|
+
let value = data[fieldKey];
|
|
254
318
|
|
|
255
319
|
// Skip computed fields
|
|
256
320
|
if (computedFields.includes(key)) {
|
|
@@ -262,6 +326,12 @@ export function cleanFormData<T>(
|
|
|
262
326
|
return;
|
|
263
327
|
}
|
|
264
328
|
|
|
329
|
+
// Transform Reference fields to JSON format expected by backend
|
|
330
|
+
// Backend expects: {"_id": "...", "_name": "..."} or a JSON string that parses to this
|
|
331
|
+
if (fieldTypes?.[key] === "Reference" && value !== null) {
|
|
332
|
+
value = transformReferenceValue(value) as any;
|
|
333
|
+
}
|
|
334
|
+
|
|
265
335
|
// For create: include all non-computed, non-undefined fields
|
|
266
336
|
if (operation === "create") {
|
|
267
337
|
cleanedData[fieldKey] = value;
|
|
@@ -289,6 +359,50 @@ export function cleanFormData<T>(
|
|
|
289
359
|
return cleanedData;
|
|
290
360
|
}
|
|
291
361
|
|
|
362
|
+
/**
|
|
363
|
+
* Transform a Reference/Lookup field value to the format expected by backend
|
|
364
|
+
*
|
|
365
|
+
* Backend expects Reference fields as either:
|
|
366
|
+
* - A dict with at minimum {"_id": "..."}
|
|
367
|
+
* - For Lookup fields, the full referenced record can be passed
|
|
368
|
+
* - A JSON string that parses to this format
|
|
369
|
+
*
|
|
370
|
+
* This function handles various input formats:
|
|
371
|
+
* - Plain string ID: "SUPP-001" → {"_id": "SUPP-001"}
|
|
372
|
+
* - Object with _id: preserves ALL properties (for lookup fields with full data)
|
|
373
|
+
* - JSON string: '{"_id": "..."}' → parsed and validated
|
|
374
|
+
*/
|
|
375
|
+
export function transformReferenceValue(value: any): Record<string, any> | null {
|
|
376
|
+
if (value === null || value === undefined || value === "") {
|
|
377
|
+
return null;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// Already an object with _id - preserve ALL properties (for lookup fields with full data)
|
|
381
|
+
if (typeof value === "object" && value._id) {
|
|
382
|
+
return { ...value };
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// String value - could be plain ID or JSON string
|
|
386
|
+
if (typeof value === "string") {
|
|
387
|
+
// Try to parse as JSON first
|
|
388
|
+
try {
|
|
389
|
+
const parsed = JSON.parse(value);
|
|
390
|
+
if (typeof parsed === "object" && parsed._id) {
|
|
391
|
+
return { ...parsed };
|
|
392
|
+
}
|
|
393
|
+
// Parsed but not a valid reference object - treat original as ID
|
|
394
|
+
} catch {
|
|
395
|
+
// Not valid JSON - treat as plain ID string
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// Plain string ID
|
|
399
|
+
return { _id: value };
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Unknown format - return as-is (let backend handle/reject it)
|
|
403
|
+
return value;
|
|
404
|
+
}
|
|
405
|
+
|
|
292
406
|
// ============================================================
|
|
293
407
|
// ERROR HANDLING
|
|
294
408
|
// ============================================================
|
|
@@ -304,6 +304,15 @@ export interface UseFormOptionsType<
|
|
|
304
304
|
* @default "interactive"
|
|
305
305
|
*/
|
|
306
306
|
interactionMode?: InteractionModeType;
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Enable draft API calls in update mode
|
|
310
|
+
* When false (default), no draft API calls (e.g., /instance_id/draft) are made during
|
|
311
|
+
* field blur in update mode. The update API is only called on form submission.
|
|
312
|
+
* When true, draft API calls are made on blur for computed field dependencies.
|
|
313
|
+
* @default false
|
|
314
|
+
*/
|
|
315
|
+
enableDraftInUpdateMode?: boolean;
|
|
307
316
|
}
|
|
308
317
|
|
|
309
318
|
// ============================================================
|
|
@@ -16,14 +16,14 @@ import type {
|
|
|
16
16
|
FormFieldConfigType,
|
|
17
17
|
} from "./types";
|
|
18
18
|
|
|
19
|
-
import { processSchema
|
|
19
|
+
import { processSchema } from "./schemaParser.utils";
|
|
20
20
|
|
|
21
21
|
import {
|
|
22
22
|
fetchFormSchemaWithCache,
|
|
23
23
|
fetchRecord,
|
|
24
24
|
submitFormData,
|
|
25
|
-
fetchAllReferenceData,
|
|
26
25
|
cleanFormData,
|
|
26
|
+
transformReferenceValue,
|
|
27
27
|
} from "./apiClient";
|
|
28
28
|
|
|
29
29
|
import { api } from "../../../api";
|
|
@@ -40,7 +40,7 @@ import {
|
|
|
40
40
|
// ============================================================
|
|
41
41
|
|
|
42
42
|
export function useForm<T extends Record<string, any> = Record<string, any>>(
|
|
43
|
-
options: UseFormOptionsType<T
|
|
43
|
+
options: UseFormOptionsType<T>,
|
|
44
44
|
): UseFormReturnType<T> {
|
|
45
45
|
const {
|
|
46
46
|
source,
|
|
@@ -54,6 +54,7 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
|
|
|
54
54
|
skipSchemaFetch = false,
|
|
55
55
|
schema: manualSchema,
|
|
56
56
|
interactionMode = "interactive",
|
|
57
|
+
enableDraftInUpdateMode = false,
|
|
57
58
|
} = options;
|
|
58
59
|
|
|
59
60
|
// Derived interaction mode flags
|
|
@@ -63,9 +64,13 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
|
|
|
63
64
|
// STATE MANAGEMENT
|
|
64
65
|
// ============================================================
|
|
65
66
|
|
|
66
|
-
const [schemaConfig, setSchemaConfig] =
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
const [schemaConfig, setSchemaConfig] = useState<FormSchemaConfigType | null>(
|
|
68
|
+
null,
|
|
69
|
+
);
|
|
70
|
+
// Reference data for cross-field validation - populated lazily by UI components if needed
|
|
71
|
+
const [referenceData, _setReferenceData] = useState<Record<string, any[]>>(
|
|
72
|
+
{},
|
|
73
|
+
);
|
|
69
74
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
70
75
|
const [lastFormValues] = useState<Partial<T>>({});
|
|
71
76
|
|
|
@@ -176,22 +181,11 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
|
|
|
176
181
|
const processed = processSchema(
|
|
177
182
|
schema as any,
|
|
178
183
|
{}, // Pass empty object - validation functions get live values from react-hook-form
|
|
179
|
-
userRole
|
|
184
|
+
userRole,
|
|
180
185
|
);
|
|
181
186
|
setSchemaConfig(processed);
|
|
182
|
-
|
|
183
|
-
//
|
|
184
|
-
const refFields = extractReferenceFields(processed);
|
|
185
|
-
if (Object.keys(refFields).length > 0) {
|
|
186
|
-
fetchAllReferenceData(refFields)
|
|
187
|
-
.then(setReferenceData)
|
|
188
|
-
.catch((err) => {
|
|
189
|
-
const error = toError(err);
|
|
190
|
-
console.warn("Failed to fetch reference data:", error);
|
|
191
|
-
// Notify via callback but don't block form - reference data is non-critical
|
|
192
|
-
onSchemaErrorRef.current?.(error);
|
|
193
|
-
});
|
|
194
|
-
}
|
|
187
|
+
// Reference data is fetched lazily by UI components when dropdowns are opened
|
|
188
|
+
// using the fetchField API with proper instance context (draftId/recordId)
|
|
195
189
|
} catch (error) {
|
|
196
190
|
console.error("Schema processing failed:", error);
|
|
197
191
|
onSchemaErrorRef.current?.(toError(error));
|
|
@@ -219,7 +213,7 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
|
|
|
219
213
|
!schemaConfig ||
|
|
220
214
|
!enabled ||
|
|
221
215
|
draftId ||
|
|
222
|
-
draftCreationStartedRef.current
|
|
216
|
+
draftCreationStartedRef.current // Prevent duplicate calls in React strict mode
|
|
223
217
|
) {
|
|
224
218
|
return;
|
|
225
219
|
}
|
|
@@ -321,7 +315,7 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
|
|
|
321
315
|
const field = schemaConfig.fields[fieldName];
|
|
322
316
|
if (field._bdoField.Formula) {
|
|
323
317
|
const fieldDeps = getFieldDependencies(
|
|
324
|
-
field._bdoField.Formula.ExpressionTree
|
|
318
|
+
field._bdoField.Formula.ExpressionTree,
|
|
325
319
|
);
|
|
326
320
|
fieldDeps.forEach((dep) => {
|
|
327
321
|
// Only add non-computed fields as dependencies
|
|
@@ -353,14 +347,20 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
|
|
|
353
347
|
return;
|
|
354
348
|
}
|
|
355
349
|
|
|
356
|
-
// Determine if draft should be triggered based on interaction mode
|
|
357
|
-
// For update mode
|
|
350
|
+
// Determine if draft should be triggered based on interaction mode and configuration
|
|
351
|
+
// For update mode: skip draft API calls unless explicitly enabled via enableDraftInUpdateMode
|
|
358
352
|
// Interactive mode (create only): Always trigger draft API on blur
|
|
359
353
|
// Non-interactive mode: Only trigger for computed field dependencies
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
354
|
+
if (operation === "update" && !enableDraftInUpdateMode) {
|
|
355
|
+
// Skip draft API calls in update mode when enableDraftInUpdateMode is false (default)
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
const shouldTrigger =
|
|
360
|
+
isInteractiveMode && operation !== "update"
|
|
361
|
+
? true // Interactive mode (create only): always trigger
|
|
362
|
+
: computedFieldDependencies.length > 0 &&
|
|
363
|
+
computedFieldDependencies.includes(fieldName as Path<T>);
|
|
364
364
|
|
|
365
365
|
if (!shouldTrigger) {
|
|
366
366
|
return;
|
|
@@ -422,7 +422,7 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
|
|
|
422
422
|
|
|
423
423
|
// Get computed field names to exclude from payload
|
|
424
424
|
const computedFieldNames = new Set(
|
|
425
|
-
schemaConfig.computedFields || []
|
|
425
|
+
schemaConfig.computedFields || [],
|
|
426
426
|
);
|
|
427
427
|
|
|
428
428
|
// Find fields that changed from baseline (excluding computed fields)
|
|
@@ -430,7 +430,7 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
|
|
|
430
430
|
// Skip _id and computed fields
|
|
431
431
|
if (key === "_id" || computedFieldNames.has(key)) return;
|
|
432
432
|
|
|
433
|
-
|
|
433
|
+
let currentValue = (currentValues as any)[key];
|
|
434
434
|
const baselineValue = (baseline as any)[key];
|
|
435
435
|
|
|
436
436
|
// Include if value has changed (using JSON.stringify for deep comparison)
|
|
@@ -443,6 +443,11 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
|
|
|
443
443
|
currentValue !== undefined;
|
|
444
444
|
|
|
445
445
|
if (hasChanged && isNonEmpty) {
|
|
446
|
+
// Transform Reference fields to format expected by backend
|
|
447
|
+
const fieldConfig = schemaConfig.fields[key];
|
|
448
|
+
if (fieldConfig?._bdoField?.Type === "Reference") {
|
|
449
|
+
currentValue = transformReferenceValue(currentValue);
|
|
450
|
+
}
|
|
446
451
|
(changedFields as any)[key] = currentValue;
|
|
447
452
|
}
|
|
448
453
|
});
|
|
@@ -470,7 +475,10 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
|
|
|
470
475
|
let computedFieldsResponse;
|
|
471
476
|
if (operation === "update" && recordId) {
|
|
472
477
|
// Update mode: use draftPatch (both interactive and non-interactive)
|
|
473
|
-
computedFieldsResponse = await client.draftPatch(
|
|
478
|
+
computedFieldsResponse = await client.draftPatch(
|
|
479
|
+
recordId,
|
|
480
|
+
payload,
|
|
481
|
+
);
|
|
474
482
|
} else if (isInteractiveMode && draftId) {
|
|
475
483
|
// Interactive create: use draftInteraction with _id
|
|
476
484
|
computedFieldsResponse = await client.draftInteraction(payload);
|
|
@@ -493,7 +501,7 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
|
|
|
493
501
|
shouldValidate: false,
|
|
494
502
|
});
|
|
495
503
|
}
|
|
496
|
-
}
|
|
504
|
+
},
|
|
497
505
|
);
|
|
498
506
|
|
|
499
507
|
// Update baseline with computed fields from successful API response
|
|
@@ -502,7 +510,7 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
|
|
|
502
510
|
if (computedFieldNames.has(fieldName)) {
|
|
503
511
|
(lastSyncedValuesRef.current as any)[fieldName] = value;
|
|
504
512
|
}
|
|
505
|
-
}
|
|
513
|
+
},
|
|
506
514
|
);
|
|
507
515
|
}
|
|
508
516
|
} catch (error) {
|
|
@@ -531,7 +539,8 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
|
|
|
531
539
|
computedFieldDependencies,
|
|
532
540
|
isInteractiveMode,
|
|
533
541
|
draftId,
|
|
534
|
-
|
|
542
|
+
enableDraftInUpdateMode,
|
|
543
|
+
],
|
|
535
544
|
);
|
|
536
545
|
|
|
537
546
|
// ============================================================
|
|
@@ -553,18 +562,16 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
|
|
|
553
562
|
|
|
554
563
|
// Cross-field validation
|
|
555
564
|
// Transform ValidationRule[] to the format expected by validateCrossField
|
|
556
|
-
const transformedRules = schemaConfig.crossFieldValidation.map(
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
})
|
|
562
|
-
);
|
|
565
|
+
const transformedRules = schemaConfig.crossFieldValidation.map((rule) => ({
|
|
566
|
+
Id: rule.Id,
|
|
567
|
+
Condition: { ExpressionTree: rule.ExpressionTree },
|
|
568
|
+
Message: rule.Message || `Validation failed for ${rule.Name}`,
|
|
569
|
+
}));
|
|
563
570
|
|
|
564
571
|
const crossFieldErrors = validateCrossField(
|
|
565
572
|
transformedRules,
|
|
566
573
|
values as any,
|
|
567
|
-
referenceData
|
|
574
|
+
referenceData,
|
|
568
575
|
);
|
|
569
576
|
|
|
570
577
|
if (crossFieldErrors.length > 0) {
|
|
@@ -603,11 +610,14 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
|
|
|
603
610
|
*/
|
|
604
611
|
const handleSubmit = useCallback(
|
|
605
612
|
(
|
|
606
|
-
onSuccess?: (
|
|
613
|
+
onSuccess?: (
|
|
614
|
+
data: T,
|
|
615
|
+
e?: React.BaseSyntheticEvent,
|
|
616
|
+
) => void | Promise<void>,
|
|
607
617
|
onError?: (
|
|
608
618
|
error: import("react-hook-form").FieldErrors<T> | Error,
|
|
609
|
-
e?: React.BaseSyntheticEvent
|
|
610
|
-
) => void | Promise<void
|
|
619
|
+
e?: React.BaseSyntheticEvent,
|
|
620
|
+
) => void | Promise<void>,
|
|
611
621
|
) => {
|
|
612
622
|
return rhfForm.handleSubmit(
|
|
613
623
|
// RHF onValid handler - validation passed, now do cross-field + API
|
|
@@ -627,13 +637,13 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
|
|
|
627
637
|
Id: rule.Id,
|
|
628
638
|
Condition: { ExpressionTree: rule.ExpressionTree },
|
|
629
639
|
Message: rule.Message || `Validation failed for ${rule.Name}`,
|
|
630
|
-
})
|
|
640
|
+
}),
|
|
631
641
|
);
|
|
632
642
|
|
|
633
643
|
const crossFieldErrors = validateCrossField(
|
|
634
644
|
transformedRules,
|
|
635
645
|
data as any,
|
|
636
|
-
referenceData
|
|
646
|
+
referenceData,
|
|
637
647
|
);
|
|
638
648
|
|
|
639
649
|
if (crossFieldErrors.length > 0) {
|
|
@@ -649,12 +659,21 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
|
|
|
649
659
|
return;
|
|
650
660
|
}
|
|
651
661
|
|
|
662
|
+
// Extract field types from schema for Reference field transformation
|
|
663
|
+
const fieldTypes: Record<string, string> = {};
|
|
664
|
+
Object.entries(schemaConfig.fields).forEach(
|
|
665
|
+
([fieldName, field]) => {
|
|
666
|
+
fieldTypes[fieldName] = field._bdoField.Type;
|
|
667
|
+
},
|
|
668
|
+
);
|
|
669
|
+
|
|
652
670
|
// Clean data for submission
|
|
653
671
|
const cleanedData = cleanFormData(
|
|
654
672
|
data as any,
|
|
655
673
|
schemaConfig.computedFields,
|
|
656
674
|
operation,
|
|
657
|
-
recordData as Partial<T> | undefined
|
|
675
|
+
recordData as Partial<T> | undefined,
|
|
676
|
+
fieldTypes,
|
|
658
677
|
);
|
|
659
678
|
|
|
660
679
|
let result;
|
|
@@ -667,7 +686,7 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
|
|
|
667
686
|
// Interactive create: must have draftId
|
|
668
687
|
if (!draftId) {
|
|
669
688
|
throw new Error(
|
|
670
|
-
"Interactive create mode requires a draft ID. Draft creation may have failed."
|
|
689
|
+
"Interactive create mode requires a draft ID. Draft creation may have failed.",
|
|
671
690
|
);
|
|
672
691
|
}
|
|
673
692
|
// POST /{bdo_id}/draft with _id in payload
|
|
@@ -687,7 +706,7 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
|
|
|
687
706
|
source,
|
|
688
707
|
operation,
|
|
689
708
|
cleanedData,
|
|
690
|
-
recordId
|
|
709
|
+
recordId,
|
|
691
710
|
);
|
|
692
711
|
|
|
693
712
|
if (!result.success) {
|
|
@@ -716,7 +735,7 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
|
|
|
716
735
|
// RHF onInvalid handler - validation failed
|
|
717
736
|
(errors, event) => {
|
|
718
737
|
onError?.(errors, event);
|
|
719
|
-
}
|
|
738
|
+
},
|
|
720
739
|
);
|
|
721
740
|
},
|
|
722
741
|
[
|
|
@@ -729,7 +748,7 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
|
|
|
729
748
|
recordData,
|
|
730
749
|
isInteractiveMode,
|
|
731
750
|
draftId,
|
|
732
|
-
]
|
|
751
|
+
],
|
|
733
752
|
);
|
|
734
753
|
|
|
735
754
|
// ============================================================
|
|
@@ -740,7 +759,7 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
|
|
|
740
759
|
<K extends keyof T>(fieldName: K): FormFieldConfigType | null => {
|
|
741
760
|
return schemaConfig?.fields[fieldName as string] || null;
|
|
742
761
|
},
|
|
743
|
-
[schemaConfig]
|
|
762
|
+
[schemaConfig],
|
|
744
763
|
);
|
|
745
764
|
|
|
746
765
|
const getFields = useCallback((): Record<keyof T, FormFieldConfigType> => {
|
|
@@ -758,7 +777,7 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
|
|
|
758
777
|
<K extends keyof T>(fieldName: K): boolean => {
|
|
759
778
|
return !!schemaConfig?.fields[fieldName as string];
|
|
760
779
|
},
|
|
761
|
-
[schemaConfig]
|
|
780
|
+
[schemaConfig],
|
|
762
781
|
);
|
|
763
782
|
|
|
764
783
|
const isFieldRequired = useCallback(
|
|
@@ -767,7 +786,7 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
|
|
|
767
786
|
schemaConfig?.requiredFields.includes(fieldName as string) || false
|
|
768
787
|
);
|
|
769
788
|
},
|
|
770
|
-
[schemaConfig]
|
|
789
|
+
[schemaConfig],
|
|
771
790
|
);
|
|
772
791
|
|
|
773
792
|
const isFieldComputed = useCallback(
|
|
@@ -776,7 +795,7 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
|
|
|
776
795
|
schemaConfig?.computedFields.includes(fieldName as string) || false
|
|
777
796
|
);
|
|
778
797
|
},
|
|
779
|
-
[schemaConfig]
|
|
798
|
+
[schemaConfig],
|
|
780
799
|
);
|
|
781
800
|
|
|
782
801
|
// ============================================================
|
|
@@ -806,12 +825,12 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
|
|
|
806
825
|
|
|
807
826
|
const computedFields = useMemo<Array<keyof T>>(
|
|
808
827
|
() => (schemaConfig?.computedFields as Array<keyof T>) || [],
|
|
809
|
-
[schemaConfig]
|
|
828
|
+
[schemaConfig],
|
|
810
829
|
);
|
|
811
830
|
|
|
812
831
|
const requiredFields = useMemo<Array<keyof T>>(
|
|
813
832
|
() => (schemaConfig?.requiredFields as Array<keyof T>) || [],
|
|
814
|
-
[schemaConfig]
|
|
833
|
+
[schemaConfig],
|
|
815
834
|
);
|
|
816
835
|
|
|
817
836
|
// ============================================================
|
|
@@ -864,7 +883,7 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
|
|
|
864
883
|
value,
|
|
865
884
|
[rule],
|
|
866
885
|
currentValues,
|
|
867
|
-
lastFormValues as T | undefined
|
|
886
|
+
lastFormValues as T | undefined,
|
|
868
887
|
);
|
|
869
888
|
if (!result.isValid) {
|
|
870
889
|
return result.message || rule.Message || "Invalid value";
|
|
@@ -936,7 +955,7 @@ export function useForm<T extends Record<string, any> = Record<string, any>>(
|
|
|
936
955
|
onBlur: enhancedOnBlur,
|
|
937
956
|
});
|
|
938
957
|
},
|
|
939
|
-
[rhfForm, validationRules, triggerComputationAfterValidation, mode]
|
|
958
|
+
[rhfForm, validationRules, triggerComputationAfterValidation, mode],
|
|
940
959
|
);
|
|
941
960
|
|
|
942
961
|
return {
|
package/sdk/index.ts
CHANGED