@ram_28/kf-ai-sdk 2.0.16 → 2.0.18

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 (105) hide show
  1. package/README.md +16 -8
  2. package/dist/{FileField-BWrSHNRq.js → FileField-CZjS2uLh.js} +3 -3
  3. package/dist/{FileField-eDeuzln8.cjs → FileField-DU4UWo_t.cjs} +1 -1
  4. package/dist/api.cjs +1 -1
  5. package/dist/api.mjs +1 -1
  6. package/dist/auth/authConfig.d.ts +1 -1
  7. package/dist/auth/types.d.ts +1 -1
  8. package/dist/auth/types.d.ts.map +1 -1
  9. package/dist/auth.cjs +1 -1
  10. package/dist/auth.mjs +1 -1
  11. package/dist/bdo/core/Item.d.ts +0 -4
  12. package/dist/bdo/core/Item.d.ts.map +1 -1
  13. package/dist/bdo/fields/ReferenceField.d.ts +1 -1
  14. package/dist/bdo/fields/ReferenceField.d.ts.map +1 -1
  15. package/dist/bdo/fields/SelectField.d.ts +1 -1
  16. package/dist/bdo/fields/SelectField.d.ts.map +1 -1
  17. package/dist/bdo/fields/UserField.d.ts +1 -1
  18. package/dist/bdo/fields/UserField.d.ts.map +1 -1
  19. package/dist/bdo.cjs +1 -1
  20. package/dist/bdo.mjs +53 -62
  21. package/dist/components/hooks/useActivityForm/types.d.ts +4 -5
  22. package/dist/components/hooks/useActivityForm/types.d.ts.map +1 -1
  23. package/dist/components/hooks/useActivityForm/useActivityForm.d.ts.map +1 -1
  24. package/dist/components/hooks/useActivityTable/types.d.ts +5 -4
  25. package/dist/components/hooks/useActivityTable/types.d.ts.map +1 -1
  26. package/dist/components/hooks/useActivityTable/useActivityTable.d.ts.map +1 -1
  27. package/dist/components/hooks/useBDOForm/createItemProxy.d.ts +2 -3
  28. package/dist/components/hooks/useBDOForm/createItemProxy.d.ts.map +1 -1
  29. package/dist/components/hooks/useBDOTable/types.d.ts +20 -12
  30. package/dist/components/hooks/useBDOTable/types.d.ts.map +1 -1
  31. package/dist/components/hooks/useBDOTable/useBDOTable.d.ts +2 -2
  32. package/dist/components/hooks/useBDOTable/useBDOTable.d.ts.map +1 -1
  33. package/dist/{constants-ConHc1oS.js → constants-Cyi942Yr.js} +5 -5
  34. package/dist/constants-DEmYwKfC.cjs +1 -0
  35. package/dist/filter.cjs +1 -1
  36. package/dist/filter.mjs +1 -1
  37. package/dist/form.cjs +1 -1
  38. package/dist/form.mjs +226 -243
  39. package/dist/table.cjs +1 -1
  40. package/dist/table.mjs +15 -16
  41. package/dist/table.types.d.ts +1 -1
  42. package/dist/table.types.d.ts.map +1 -1
  43. package/dist/types/constants.d.ts +1 -1
  44. package/dist/workflow/Activity.d.ts +8 -5
  45. package/dist/workflow/Activity.d.ts.map +1 -1
  46. package/dist/workflow.cjs +1 -1
  47. package/dist/workflow.mjs +461 -476
  48. package/docs/README.md +57 -0
  49. package/docs/bdo/README.md +161 -0
  50. package/docs/bdo/api_reference.md +281 -0
  51. package/docs/examples/bdo/create-product.md +69 -0
  52. package/docs/examples/bdo/edit-product-dialog.md +95 -0
  53. package/docs/examples/bdo/filtered-product-table.md +100 -0
  54. package/docs/examples/bdo/product-listing.md +73 -0
  55. package/docs/examples/bdo/supplier-dropdown.md +60 -0
  56. package/docs/examples/fields/complex-fields.md +248 -0
  57. package/docs/examples/fields/primitive-fields.md +217 -0
  58. package/docs/examples/workflow/approve-leave-request.md +76 -0
  59. package/docs/examples/workflow/filtered-activity-table.md +101 -0
  60. package/docs/examples/workflow/my-pending-requests.md +90 -0
  61. package/docs/examples/workflow/start-new-workflow.md +47 -0
  62. package/docs/examples/workflow/submit-leave-request.md +72 -0
  63. package/docs/examples/workflow/workflow-progress.md +49 -0
  64. package/docs/fields/README.md +141 -0
  65. package/docs/fields/api_reference.md +134 -0
  66. package/docs/useActivityForm/README.md +244 -0
  67. package/docs/useActivityForm/api_reference.md +279 -0
  68. package/docs/useActivityTable/README.md +263 -0
  69. package/docs/useActivityTable/api_reference.md +294 -0
  70. package/docs/useBDOForm/README.md +175 -0
  71. package/docs/useBDOForm/api_reference.md +244 -0
  72. package/docs/useBDOTable/README.md +242 -0
  73. package/docs/useBDOTable/api_reference.md +253 -0
  74. package/docs/useFilter/README.md +323 -0
  75. package/docs/useFilter/api_reference.md +228 -0
  76. package/docs/workflow/README.md +158 -0
  77. package/docs/workflow/api_reference.md +161 -0
  78. package/package.json +1 -1
  79. package/sdk/auth/authConfig.ts +1 -1
  80. package/sdk/auth/types.ts +1 -1
  81. package/sdk/bdo/core/Item.ts +1 -10
  82. package/sdk/bdo/fields/ReferenceField.ts +1 -1
  83. package/sdk/bdo/fields/SelectField.ts +1 -1
  84. package/sdk/bdo/fields/UserField.ts +1 -1
  85. package/sdk/components/hooks/useActivityForm/types.ts +4 -6
  86. package/sdk/components/hooks/useActivityForm/useActivityForm.ts +10 -73
  87. package/sdk/components/hooks/useActivityTable/types.ts +4 -5
  88. package/sdk/components/hooks/useActivityTable/useActivityTable.ts +10 -8
  89. package/sdk/components/hooks/useBDOForm/createItemProxy.ts +17 -58
  90. package/sdk/components/hooks/useBDOTable/types.ts +20 -10
  91. package/sdk/components/hooks/useBDOTable/useBDOTable.ts +12 -8
  92. package/sdk/table.types.ts +2 -0
  93. package/sdk/types/constants.ts +1 -1
  94. package/sdk/workflow/Activity.ts +39 -7
  95. package/dist/constants-QX2RX-wu.cjs +0 -1
  96. package/docs/api.md +0 -95
  97. package/docs/bdo.md +0 -224
  98. package/docs/gaps.md +0 -360
  99. package/docs/useActivityForm.md +0 -393
  100. package/docs/useActivityTable.md +0 -418
  101. package/docs/useBDOForm.md +0 -376
  102. package/docs/useBDOTable.md +0 -284
  103. package/docs/useFilter.md +0 -188
  104. package/docs/workflow.md +0 -560
  105. /package/docs/{useAuth.md → useAuth/README.md} +0 -0
@@ -1,376 +0,0 @@
1
- # useBDOForm
2
-
3
- React hook for BDO forms with validation, API integration, and typed field handling.
4
-
5
- ## Imports
6
-
7
- ```typescript
8
- import { useBDOForm } from "@ram_28/kf-ai-sdk/form";
9
- import { ValidationMode, FormOperation } from "@ram_28/kf-ai-sdk/form";
10
- import type { UseBDOFormOptionsType, UseBDOFormReturnType, FormItemType, FormRegisterType, HandleSubmitType } from "@ram_28/kf-ai-sdk/form/types";
11
- import type { CreateUpdateResponseType } from "@ram_28/kf-ai-sdk/api/types";
12
-
13
- // Pre-built components for special field types
14
- import { ReferenceSelect } from "@/components/ui/reference-select";
15
- import { ImageUpload } from "@/components/ui/image-upload";
16
- import { FileUpload } from "@/components/ui/file-upload";
17
- ```
18
-
19
- ---
20
-
21
- ## Common Mistakes (READ FIRST)
22
-
23
- ### 1. Missing `operation` in useBDOForm options (TS2345)
24
-
25
- ALWAYS include `operation`. Without it, TypeScript cannot resolve the union type.
26
-
27
- ```typescript
28
- // ❌ WRONG — missing operation (TS2345)
29
- useBDOForm({ bdo: product, mode: ValidationMode.OnBlur });
30
-
31
- // ✅ CORRECT — always include operation
32
- useBDOForm({ bdo: product, operation: FormOperation.Create, mode: ValidationMode.OnBlur });
33
- useBDOForm({ bdo: product, operation: FormOperation.Update, recordId: id, mode: ValidationMode.OnBlur });
34
- ```
35
-
36
- ### 2. Annotating ternary with UseBDOFormOptionsType (TS2322)
37
-
38
- `UseBDOFormOptionsType` is a discriminated union. Type-annotating a variable prevents TS narrowing. NEVER annotate — call useBDOForm inline in each branch.
39
-
40
- ```typescript
41
- // ❌ WRONG — type annotation prevents union narrowing (TS2322)
42
- const options: UseBDOFormOptionsType<typeof bdo> = id
43
- ? { bdo, operation: FormOperation.Update, recordId: id, mode: ValidationMode.OnBlur }
44
- : { bdo, operation: FormOperation.Create, mode: ValidationMode.OnBlur };
45
- const formResult = useBDOForm(options);
46
-
47
- // ✅ CORRECT — call useBDOForm inline, no type annotation
48
- const formResult = id
49
- ? useBDOForm({ bdo, operation: FormOperation.Update, recordId: id, mode: ValidationMode.OnBlur })
50
- : useBDOForm({ bdo, operation: FormOperation.Create, mode: ValidationMode.OnBlur });
51
- const { register, handleSubmit, watch, setValue, item, formState: { errors, isSubmitting }, isLoading } = formResult;
52
- ```
53
-
54
- ### 3. Using `.options` on StringField (TS2339)
55
-
56
- ONLY `SelectField` has `.options` getter. `StringField` with `Constraint.Enum` does NOT — use hardcoded `<option>` values from the BDO file.
57
-
58
- ```tsx
59
- // Check the BDO class to determine field type:
60
- // new SelectField({...}) → has .options → use bdo.field.options.map()
61
- // new StringField({..."Constraint": {"Enum": [...]}}) → NO .options → hardcode from Enum array
62
-
63
- // ❌ WRONG — StringField has no .options (TS2339)
64
- // Given: readonly status = new StringField({... "Constraint": { "Enum": ["Active", "Discontinued"] }})
65
- <select {...register(bdo.status.id)}>
66
- {bdo.status.options.map((opt) => ( // TS2339: Property 'options' does not exist on StringField
67
- <option key={opt.value} value={opt.value}>{opt.label}</option>
68
- ))}
69
- </select>
70
-
71
- // ✅ CORRECT for StringField with Enum — hardcode options from BDO Constraint.Enum array
72
- <select {...register(bdo.status.id)}>
73
- <option value="">Select {bdo.status.label}</option>
74
- <option value="Active">Active</option>
75
- <option value="Discontinued">Discontinued</option>
76
- </select>
77
-
78
- // ✅ CORRECT for SelectField — use .options getter
79
- // Given: readonly status = new SelectField({...})
80
- <select {...register(bdo.status.id)}>
81
- <option value="">Select {bdo.status.label}</option>
82
- {bdo.status.options.map((opt) => (
83
- <option key={opt.value} value={opt.value}>{opt.label}</option>
84
- ))}
85
- </select>
86
- ```
87
-
88
- ### 4. Using register() for BooleanField
89
-
90
- HTML checkboxes don't work with register(). Use watch/setValue.
91
-
92
- ```tsx
93
- // ❌ WRONG
94
- <input type="checkbox" {...register(bdo.is_active.id)} />
95
-
96
- // ✅ CORRECT
97
- <Checkbox
98
- checked={Boolean(watch(bdo.is_active.id))}
99
- onCheckedChange={(v) => setValue(bdo.is_active.id, v as boolean, { shouldDirty: true })}
100
- />
101
- ```
102
-
103
- ### 5. Using `<input>` for ReferenceField (should use `<ReferenceSelect>`)
104
-
105
- ReferenceField stores an object `{ _id, _name, ... }`, not a string. Use the pre-built component.
106
-
107
- ```tsx
108
- // ❌ WRONG — text input for reference field
109
- <input {...register(bdo.category.id)} />
110
-
111
- // ✅ CORRECT
112
- <ReferenceSelect
113
- bdoField={bdo.category}
114
- instanceId={id || String(watch("_id") ?? "")}
115
- value={watch(bdo.category.id)}
116
- onChange={(val) => setValue(bdo.category.id, val, { shouldDirty: true })}
117
- />
118
- ```
119
-
120
- ### 6. Using custom Image/File upload (should use template components)
121
-
122
- Use `<ImageUpload>` and `<FileUpload>`. CRITICAL: `instanceId` must work for BOTH edit and create mode.
123
-
124
- ```tsx
125
- // ❌ WRONG — instanceId={id} is undefined in create mode
126
- <ImageUpload field={item.icon} value={watch(bdo.icon.id)} boId={bdo.meta._id} instanceId={id} fieldId={bdo.icon.id} />
127
-
128
- // ✅ CORRECT — ImageUpload (single image)
129
- <ImageUpload
130
- field={item.product_image}
131
- value={watch(bdo.product_image.id)}
132
- boId={bdo.meta._id}
133
- instanceId={id || String(watch("_id") ?? "")}
134
- fieldId={bdo.product_image.id}
135
- />
136
-
137
- // ✅ CORRECT — FileUpload (multi-file)
138
- <FileUpload
139
- field={item.specification_document}
140
- value={watch(bdo.specification_document.id)}
141
- boId={bdo.meta._id}
142
- instanceId={id || String(watch("_id") ?? "")}
143
- fieldId={bdo.specification_document.id}
144
- />
145
- ```
146
-
147
- Props: `field` = item accessor (`item.fieldName`), `value` = `watch(bdo.field.id)`, `boId` = `bdo.meta._id`, `instanceId` = `id || String(watch("_id") ?? "")`, `fieldId` = `bdo.field.id`. Parent component MUST have `"use no memo"` directive.
148
-
149
- ### 7. Wrong handleSubmit onSuccess type
150
-
151
- ```typescript
152
- // ❌ WRONG
153
- const onSuccess = (data: unknown) => { ... };
154
-
155
- // ✅ CORRECT — CreateUpdateResponseType = { _id: string }
156
- import type { CreateUpdateResponseType } from "@ram_28/kf-ai-sdk/api/types";
157
- const onSuccess = (data: CreateUpdateResponseType) => { toast.success("Saved"); navigate("/list"); };
158
- ```
159
-
160
- ### 8. Passing FieldType instead of BDO instance
161
-
162
- ```typescript
163
- // ❌ WRONG
164
- useBDOForm<ProductFieldType>({ ... });
165
-
166
- // ✅ CORRECT — pass BDO class instance
167
- const product = useMemo(() => new SellerProduct(), []);
168
- useBDOForm({ bdo: product, operation: FormOperation.Create, mode: ValidationMode.OnBlur });
169
- ```
170
-
171
- ### 9. Wrong default values for date fields
172
-
173
- ```typescript
174
- // ❌ WRONG — empty string causes type errors
175
- defaultValues: { start_date: "" }
176
-
177
- // ✅ CORRECT
178
- defaultValues: { start_date: undefined }
179
- ```
180
-
181
- ---
182
-
183
- ## Complete Form Example (Create + Edit)
184
-
185
- ```tsx
186
- "use no memo";
187
-
188
- import { useMemo } from "react";
189
- import { useNavigate, useParams } from "react-router-dom";
190
- import { useBDOForm, ValidationMode, FormOperation } from "@ram_28/kf-ai-sdk/form";
191
- import type { CreateUpdateResponseType } from "@ram_28/kf-ai-sdk/api/types";
192
- import { AdminProduct } from "@/bdo/admin/Product";
193
- import { ReferenceSelect } from "@/components/ui/reference-select";
194
- import { ImageUpload } from "@/components/ui/image-upload";
195
- import { FileUpload } from "@/components/ui/file-upload";
196
- import { Checkbox } from "@/components/ui/checkbox";
197
- import { toast } from "sonner";
198
-
199
- export default function ProductForm() {
200
- const { id } = useParams<{ id: string }>();
201
- const navigate = useNavigate();
202
- const bdo = useMemo(() => new AdminProduct(), []);
203
-
204
- // Create/Edit ternary — NO type annotation on result
205
- const formResult = id
206
- ? useBDOForm({ bdo, operation: FormOperation.Update, recordId: id, mode: ValidationMode.OnBlur })
207
- : useBDOForm({ bdo, operation: FormOperation.Create, mode: ValidationMode.OnBlur });
208
-
209
- const { register, handleSubmit, watch, setValue, item, formState: { errors, isSubmitting }, isLoading } = formResult;
210
-
211
- // Loading guard AFTER all hooks
212
- if (isLoading) return <div className="flex items-center justify-center h-full"><div className="animate-spin w-8 h-8 border-4 border-primary border-t-transparent rounded-full" /></div>;
213
-
214
- const onSuccess = (data: CreateUpdateResponseType) => {
215
- toast.success(id ? "Updated" : "Created");
216
- navigate("/products");
217
- };
218
-
219
- const onError = (error: any) => {
220
- toast.error(error instanceof Error ? error.message : "Please fix errors above");
221
- };
222
-
223
- return (
224
- <form onSubmit={handleSubmit(onSuccess, onError)} className="space-y-6">
225
- {/* StringField — register */}
226
- <div>
227
- <label>{bdo.product_name.label}{bdo.product_name.required && <span className="text-red-500"> *</span>}</label>
228
- <input {...register(bdo.product_name.id)} className="w-full border rounded px-3 py-2" />
229
- {errors.product_name && <p className="text-red-600 text-sm">{errors.product_name.message}</p>}
230
- </div>
231
-
232
- {/* NumberField — register */}
233
- <div>
234
- <label>{bdo.unit_price.label}</label>
235
- <input type="number" step="0.01" {...register(bdo.unit_price.id)} className="w-full border rounded px-3 py-2" />
236
- {errors.unit_price && <p className="text-red-600 text-sm">{errors.unit_price.message}</p>}
237
- </div>
238
-
239
- {/* StringField with Constraint.Enum — hardcoded options (NO .options getter) */}
240
- <div>
241
- <label>{bdo.status.label}</label>
242
- <select {...register(bdo.status.id)} className="w-full border rounded px-3 py-2">
243
- <option value="">Select {bdo.status.label}</option>
244
- <option value="Active">Active</option>
245
- <option value="Discontinued">Discontinued</option>
246
- </select>
247
- {errors.status && <p className="text-red-600 text-sm">{errors.status.message}</p>}
248
- </div>
249
-
250
- {/* ReferenceField — ReferenceSelect component */}
251
- <div>
252
- <label>{bdo.category.label}</label>
253
- <ReferenceSelect
254
- bdoField={bdo.category}
255
- instanceId={id || String(watch("_id") ?? "")}
256
- value={watch(bdo.category.id)}
257
- onChange={(val) => setValue(bdo.category.id, val, { shouldDirty: true })}
258
- />
259
- {errors.category && <p className="text-red-600 text-sm">{String(errors.category.message ?? "")}</p>}
260
- </div>
261
-
262
- {/* BooleanField — watch + setValue */}
263
- <div className="flex items-center gap-2">
264
- <Checkbox
265
- checked={Boolean(watch(bdo.is_active.id))}
266
- onCheckedChange={(v) => setValue(bdo.is_active.id, v as boolean, { shouldDirty: true })}
267
- />
268
- <label>{bdo.is_active.label}</label>
269
- </div>
270
-
271
- {/* ImageField — ImageUpload component */}
272
- <div>
273
- <label>{bdo.product_image.label}</label>
274
- <ImageUpload
275
- field={item.product_image}
276
- value={watch(bdo.product_image.id)}
277
- boId={bdo.meta._id}
278
- instanceId={id || String(watch("_id") ?? "")}
279
- fieldId={bdo.product_image.id}
280
- />
281
- </div>
282
-
283
- {/* FileField — FileUpload component */}
284
- <div>
285
- <label>{bdo.specification_document.label}</label>
286
- <FileUpload
287
- field={item.specification_document}
288
- value={watch(bdo.specification_document.id)}
289
- boId={bdo.meta._id}
290
- instanceId={id || String(watch("_id") ?? "")}
291
- fieldId={bdo.specification_document.id}
292
- />
293
- </div>
294
-
295
- {/* TextField — textarea with register */}
296
- <div>
297
- <label>{bdo.description.label}</label>
298
- <textarea {...register(bdo.description.id)} rows={4} className="w-full border rounded px-3 py-2" />
299
- </div>
300
-
301
- <button type="submit" disabled={isSubmitting} className="px-4 py-2 bg-primary text-white rounded">
302
- {isSubmitting ? "Saving..." : id ? "Update" : "Create"}
303
- </button>
304
- </form>
305
- );
306
- }
307
- ```
308
-
309
- ---
310
-
311
- ## Type Definitions
312
-
313
- ### UseBDOFormOptionsType (Discriminated Union)
314
-
315
- ```typescript
316
- type UseBDOFormOptionsType<B extends BaseBdo<any, any, any>> =
317
- | { bdo: B; operation: "create"; defaultValues?: Partial<EditableFieldType>; mode?: ValidationModeType; }
318
- | { bdo: B; operation: "update"; recordId: string; mode?: ValidationModeType; }
319
- | { bdo: B; recordId?: string; defaultValues?: Partial<EditableFieldType>; mode?: ValidationModeType; };
320
- ```
321
-
322
- ### UseBDOFormReturnType
323
-
324
- ```typescript
325
- interface UseBDOFormReturnType<B> {
326
- item: FormItemType<EditableFieldType, ReadonlyFieldType>; // Field accessors (.get(), .set(), .upload())
327
- register: FormRegisterType; // Auto-disables readonly fields
328
- handleSubmit: HandleSubmitType; // Auto-calls bdo.create() or bdo.update()
329
- watch: UseFormWatch; // Watch field values by bdo.field.id
330
- setValue: UseFormSetValue; // Set field values by bdo.field.id
331
- getValues: UseFormGetValues;
332
- control: Control;
333
- formState: FormState;
334
- errors: FieldErrors;
335
- isLoading: boolean; // Fetching record data (edit mode)
336
- isSubmitting: boolean;
337
- isDirty: boolean;
338
- loadError: Error | null;
339
- }
340
- ```
341
-
342
- ### File & Image Types
343
-
344
- ```typescript
345
- interface FileType { _id: string; _name: string; FileName: string; FileExtension: string; Size: number; ContentType: string; }
346
- type ImageFieldType = FileType | null; // Single image, nullable
347
- type FileFieldType = FileType[]; // Array of files
348
- ```
349
-
350
- Image accessor: `item.field.get()` returns `FileType | null`. Has `upload(file: File)`, `deleteAttachment()`, `getDownloadUrl()`.
351
- File accessor: `item.field.get()` returns `FileType[]`. Has `upload(files: File[])`, `deleteAttachment(id)`, `getDownloadUrl(id)`.
352
-
353
- ### Constants
354
-
355
- ```typescript
356
- FormOperation.Create // "create"
357
- FormOperation.Update // "update"
358
- ValidationMode.OnBlur / .OnChange / .OnSubmit / .OnTouched / .All
359
- ```
360
-
361
- ### Field-Type to UI Component Mapping
362
-
363
- | BDO Field Class | UI Pattern |
364
- |---|---|
365
- | `StringField` | `<input {...register(bdo.field.id)} />` |
366
- | `StringField` with `Constraint.Enum` | `<select {...register(bdo.field.id)}>` with hardcoded `<option>` from Enum array |
367
- | `SelectField` | `<select {...register(bdo.field.id)}>` with `bdo.field.options.map()` |
368
- | `TextField` | `<textarea {...register(bdo.field.id)} />` |
369
- | `NumberField` | `<input type="number" {...register(bdo.field.id)} />` |
370
- | `BooleanField` | `<Checkbox checked={watch()} onCheckedChange={v => setValue()} />` |
371
- | `DateField` | `<input type="date" {...register(bdo.field.id)} />` |
372
- | `DateTimeField` | `<input type="datetime-local" {...register(bdo.field.id)} />` |
373
- | `ReferenceField` | `<ReferenceSelect bdoField={bdo.field} instanceId={id \|\| String(watch("_id") ?? "")} value={watch()} onChange={...} />` |
374
- | `UserField` | `<ReferenceSelect bdoField={bdo.field} instanceId={id \|\| String(watch("_id") ?? "")} value={watch()} onChange={...} />` |
375
- | `ImageField` | `<ImageUpload field={item.field} value={watch()} boId={} instanceId={} fieldId={} />` |
376
- | `FileField` | `<FileUpload field={item.field} value={watch()} boId={} instanceId={} fieldId={} />` |
@@ -1,284 +0,0 @@
1
- # useBDOTable
2
-
3
- Hook for BDO (Business Data Object) tables with search, sort, filter, and pagination. Pass a BDO instance and the hook handles the rest.
4
-
5
- ## Imports
6
-
7
- ```typescript
8
- import { useBDOTable } from "@ram_28/kf-ai-sdk/table";
9
- import { ConditionOperator, RHSType } from "@ram_28/kf-ai-sdk/table";
10
- import type { UseBDOTableOptionsType, UseBDOTableReturnType } from "@ram_28/kf-ai-sdk/table/types";
11
- ```
12
-
13
- ---
14
-
15
- ## Common Mistakes (READ FIRST)
16
-
17
- ### 1. Passing `source` instead of `bdo`
18
-
19
- `useBDOTable` takes a `bdo` instance, NOT a `source` string.
20
-
21
- ```typescript
22
- // ❌ WRONG — source is not a valid property on useBDOTable
23
- useBDOTable({ source: product.meta._id });
24
-
25
- // ✅ CORRECT — pass the BDO instance
26
- useBDOTable({ bdo: product });
27
- ```
28
-
29
- ### 2. Passing a raw object instead of a BDO instance
30
-
31
- The `bdo` property expects an object with a `meta` property containing `_id` and `name`. A plain object or entity type will not work.
32
-
33
- ```typescript
34
- // ❌ WRONG — plain object without meta
35
- useBDOTable({ bdo: { _id: 'BO_Product', name: 'Product' } });
36
-
37
- // ✅ CORRECT — a BDO class instance
38
- const product = useMemo(() => new BuyerProduct(), []);
39
- useBDOTable({ bdo: product });
40
- ```
41
-
42
- ### 3. Recreating the BDO on every render
43
-
44
- Constructing the BDO inside the component body without `useMemo` creates a new instance on every render, which destabilizes the query key and causes infinite refetching.
45
-
46
- ```typescript
47
- // ❌ WRONG — new instance every render
48
- function ProductsTable() {
49
- const product = new BuyerProduct();
50
- const table = useBDOTable({ bdo: product }); // infinite refetch loop
51
- }
52
-
53
- // ✅ CORRECT — memoize the instance
54
- function ProductsTable() {
55
- const product = useMemo(() => new BuyerProduct(), []);
56
- const table = useBDOTable({ bdo: product });
57
- }
58
- ```
59
-
60
- ### 4. Using `columns` with useBDOTable
61
-
62
- `useBDOTable` does not accept a `columns` property. Column definitions are a UI concern handled in your rendering logic, not in the hook options.
63
-
64
- ```typescript
65
- // ❌ WRONG — columns is not a hook option
66
- useBDOTable({
67
- bdo: product,
68
- columns: [{ fieldId: 'Title', label: 'Title' }],
69
- });
70
-
71
- // ✅ CORRECT — define columns separately for rendering
72
- const columns = [
73
- { fieldId: product.Title.id, label: product.Title.label },
74
- { fieldId: product.Price.id, label: product.Price.label },
75
- ];
76
- const table = useBDOTable({ bdo: product });
77
- ```
78
-
79
- ### 5. Calling `.get()` on table rows
80
-
81
- Table `rows` are plain objects, NOT `ItemType`. The `.get()` accessor is only available on items returned by `bdo.get()`, `bdo.create()`, or the `useBDOForm` item proxy.
82
-
83
- ```typescript
84
- // ❌ WRONG — rows are plain objects, not ItemType
85
- table.rows.map((row) => row.Title.get());
86
-
87
- // ✅ CORRECT — access properties directly
88
- table.rows.map((row) => row.Title);
89
- ```
90
-
91
- ### 6. Wrong initialState property names
92
-
93
- This is not react-table. Do not use react-table naming conventions.
94
-
95
- ```typescript
96
- // ❌ WRONG — sorting and pageIndex are react-table names
97
- useBDOTable({
98
- bdo: product,
99
- initialState: { sorting: [...], pagination: { pageIndex: 0, pageSize: 10 } },
100
- });
101
-
102
- // ✅ CORRECT — use sort and pageNo (1-indexed)
103
- useBDOTable({
104
- bdo: product,
105
- initialState: {
106
- sort: [{ [product.Title.id]: 'ASC' }],
107
- pagination: { pageNo: 1, pageSize: 10 },
108
- },
109
- });
110
- ```
111
-
112
- ---
113
-
114
- ## Complete Example
115
-
116
- A product listing page with search, filter, sort, and pagination.
117
-
118
- ```tsx
119
- import { useMemo, useState } from "react";
120
- import { useBDOTable } from "@ram_28/kf-ai-sdk/table";
121
- import { ConditionOperator, RHSType } from "@ram_28/kf-ai-sdk/table";
122
- import type { UseBDOTableReturnType } from "@ram_28/kf-ai-sdk/table/types";
123
- import { BuyerProduct } from "../bdo/buyer/Product";
124
- import type { BuyerProductFieldType } from "../bdo/buyer/Product";
125
-
126
- function ProductListPage() {
127
- const productBdo = useMemo(() => new BuyerProduct(), []);
128
- const [selectedCategory, setSelectedCategory] = useState("all");
129
-
130
- const table: UseBDOTableReturnType<BuyerProductFieldType> =
131
- useBDOTable<BuyerProductFieldType>({
132
- bdo: productBdo,
133
- initialState: {
134
- sort: [{ [productBdo.Title.id]: "ASC" }],
135
- pagination: { pageNo: 1, pageSize: 10 },
136
- },
137
- onError: (error) => {
138
- console.error("Table fetch failed:", error.message);
139
- },
140
- onSuccess: (data) => {
141
- console.log("Loaded", data.length, "rows");
142
- },
143
- });
144
-
145
- const handleCategoryChange = (category: string) => {
146
- setSelectedCategory(category);
147
- table.filter.clearAllConditions();
148
- if (category !== "all") {
149
- table.filter.addCondition({
150
- LHSField: productBdo.Category.id,
151
- Operator: ConditionOperator.EQ,
152
- RHSValue: category,
153
- RHSType: RHSType.Constant,
154
- });
155
- }
156
- };
157
-
158
- if (table.isLoading) return <div>Loading...</div>;
159
- if (table.error) {
160
- return (
161
- <div>
162
- <p>Error: {table.error.message}</p>
163
- <button onClick={() => table.refetch()}>Retry</button>
164
- </div>
165
- );
166
- }
167
-
168
- return (
169
- <div>
170
- {/* Search */}
171
- <input
172
- type="text"
173
- placeholder="Search products..."
174
- value={table.search.query}
175
- onChange={(e) => table.search.set(productBdo.Title.id, e.target.value)}
176
- />
177
- {table.search.query && (
178
- <button onClick={table.search.clear}>Clear Search</button>
179
- )}
180
-
181
- {/* Category Filter */}
182
- <select
183
- value={selectedCategory}
184
- onChange={(e) => handleCategoryChange(e.target.value)}
185
- >
186
- <option value="all">All Categories</option>
187
- <option value="Electronics">Electronics</option>
188
- <option value="Books">Books</option>
189
- </select>
190
-
191
- {/* Sort */}
192
- <select
193
- onChange={(e) => {
194
- const [field, dir] = e.target.value.split(":");
195
- table.sort.set(field, dir as "ASC" | "DESC");
196
- }}
197
- >
198
- <option value={`${productBdo.Title.id}:ASC`}>Name A-Z</option>
199
- <option value={`${productBdo.Price.id}:ASC`}>Price: Low to High</option>
200
- <option value={`${productBdo.Price.id}:DESC`}>Price: High to Low</option>
201
- </select>
202
-
203
- {/* Results */}
204
- <p>{table.totalItems} results</p>
205
- <div>
206
- {table.rows.map((row) => (
207
- <div key={row._id}>
208
- <h3>{row.Title}</h3>
209
- <p>${row.Price}</p>
210
- <p>{row.Category}</p>
211
- </div>
212
- ))}
213
- </div>
214
-
215
- {/* Pagination */}
216
- <div>
217
- <button
218
- onClick={table.pagination.goToPrevious}
219
- disabled={!table.pagination.canGoPrevious}
220
- >
221
- Previous
222
- </button>
223
- <span>
224
- Page {table.pagination.pageNo} of {table.pagination.totalPages}
225
- </span>
226
- <button
227
- onClick={table.pagination.goToNext}
228
- disabled={!table.pagination.canGoNext}
229
- >
230
- Next
231
- </button>
232
- </div>
233
- </div>
234
- );
235
- }
236
- ```
237
-
238
- ---
239
-
240
- ## Type Definitions
241
-
242
- ### UseBDOTableOptionsType
243
-
244
- ```typescript
245
- export interface UseBDOTableOptionsType<T> {
246
- /** BDO instance — only meta._id is used (for API routing) */
247
- bdo: {
248
- meta: { readonly _id: string; readonly name: string };
249
- };
250
-
251
- /** Initial state */
252
- initialState?: {
253
- sort?: SortType;
254
- pagination?: PaginationStateType;
255
- filter?: UseFilterOptionsType<T>;
256
- };
257
-
258
- /** Error callback */
259
- onError?: (error: Error) => void;
260
-
261
- /** Success callback — receives rows from current page */
262
- onSuccess?: (data: T[]) => void;
263
- }
264
- ```
265
-
266
- ### UseBDOTableReturnType
267
-
268
- ```typescript
269
- export type UseBDOTableReturnType<T> = UseTableReturnType<T>;
270
- ```
271
-
272
- The return type is identical to `UseTableReturnType<T>`. All properties — `rows`, `totalItems`, `isLoading`, `isFetching`, `error`, `search`, `sort`, `filter`, `pagination`, and `refetch` — behave the same.
273
-
274
- ---
275
-
276
- ## Search, Sort, Filter, and Pagination
277
-
278
- `useBDOTable` supports `initialState`, `onError`, and `onSuccess` options.
279
-
280
- - **Search** — `table.search.set(field, query)`, `table.search.clear()`, 300ms debounce
281
- - **Sort** — `table.sort.toggle(field)`, `table.sort.set(field, direction)`, `table.sort.clear()`
282
- - **Filter** — `table.filter.addCondition(...)`, `table.filter.removeCondition(...)`, `table.filter.clearAllConditions()`
283
- - **Pagination** — `table.pagination.goToNext()`, `table.pagination.goToPrevious()`, `table.pagination.goToPage(n)`, `table.pagination.setPageSize(n)`
284
-