@ram_28/kf-ai-sdk 2.0.15 → 2.0.17

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 (130) hide show
  1. package/README.md +22 -14
  2. package/dist/api.cjs +1 -1
  3. package/dist/api.mjs +1 -1
  4. package/dist/auth/authConfig.d.ts +1 -1
  5. package/dist/auth/types.d.ts +1 -1
  6. package/dist/auth/types.d.ts.map +1 -1
  7. package/dist/auth.cjs +1 -1
  8. package/dist/auth.mjs +1 -1
  9. package/dist/bdo/core/BaseBdo.d.ts +1 -1
  10. package/dist/bdo.cjs +1 -1
  11. package/dist/bdo.mjs +3 -3
  12. package/dist/components/hooks/useActivityForm/createActivityItemProxy.d.ts +1 -1
  13. package/dist/components/hooks/useActivityForm/createActivityItemProxy.d.ts.map +1 -1
  14. package/dist/components/hooks/useActivityForm/types.d.ts +6 -7
  15. package/dist/components/hooks/useActivityForm/types.d.ts.map +1 -1
  16. package/dist/components/hooks/useActivityForm/useActivityForm.d.ts.map +1 -1
  17. package/dist/components/hooks/useActivityTable/types.d.ts +7 -6
  18. package/dist/components/hooks/useActivityTable/types.d.ts.map +1 -1
  19. package/dist/components/hooks/useActivityTable/useActivityTable.d.ts +1 -1
  20. package/dist/components/hooks/useActivityTable/useActivityTable.d.ts.map +1 -1
  21. package/dist/components/hooks/useBDOForm/createItemProxy.d.ts.map +1 -0
  22. package/dist/components/hooks/useBDOForm/createResolver.d.ts.map +1 -0
  23. package/dist/components/hooks/useBDOForm/index.d.ts +6 -0
  24. package/dist/components/hooks/useBDOForm/index.d.ts.map +1 -0
  25. package/dist/components/hooks/useBDOForm/shared.d.ts +50 -0
  26. package/dist/components/hooks/useBDOForm/shared.d.ts.map +1 -0
  27. package/dist/components/hooks/{useForm → useBDOForm}/types.d.ts +6 -6
  28. package/dist/components/hooks/useBDOForm/types.d.ts.map +1 -0
  29. package/dist/components/hooks/{useForm/useForm.d.ts → useBDOForm/useBDOForm.d.ts} +4 -4
  30. package/dist/components/hooks/useBDOForm/useBDOForm.d.ts.map +1 -0
  31. package/dist/components/hooks/useBDOTable/types.d.ts +20 -14
  32. package/dist/components/hooks/useBDOTable/types.d.ts.map +1 -1
  33. package/dist/components/hooks/useBDOTable/useBDOTable.d.ts +2 -2
  34. package/dist/components/hooks/useBDOTable/useBDOTable.d.ts.map +1 -1
  35. package/dist/{constants-ConHc1oS.js → constants-Cyi942Yr.js} +5 -5
  36. package/dist/constants-DEmYwKfC.cjs +1 -0
  37. package/dist/filter.cjs +1 -1
  38. package/dist/filter.mjs +1 -1
  39. package/dist/form.cjs +1 -1
  40. package/dist/form.d.ts +1 -1
  41. package/dist/form.d.ts.map +1 -1
  42. package/dist/form.mjs +250 -253
  43. package/dist/form.types.d.ts +1 -1
  44. package/dist/form.types.d.ts.map +1 -1
  45. package/dist/shared-5a7UkED1.js +1180 -0
  46. package/dist/shared-nnmlRVs7.cjs +1 -0
  47. package/dist/table.cjs +1 -1
  48. package/dist/table.mjs +14 -14
  49. package/dist/table.types.d.ts +1 -1
  50. package/dist/table.types.d.ts.map +1 -1
  51. package/dist/types/constants.d.ts +4 -4
  52. package/dist/workflow/Activity.d.ts +22 -7
  53. package/dist/workflow/Activity.d.ts.map +1 -1
  54. package/dist/workflow/client.d.ts +2 -2
  55. package/dist/workflow/client.d.ts.map +1 -1
  56. package/dist/workflow/types.d.ts +7 -3
  57. package/dist/workflow/types.d.ts.map +1 -1
  58. package/dist/workflow.cjs +1 -1
  59. package/dist/workflow.mjs +518 -576
  60. package/docs/README.md +51 -0
  61. package/docs/bdo/README.md +161 -0
  62. package/docs/bdo/api_reference.md +281 -0
  63. package/docs/examples/bdo/create-product.md +69 -0
  64. package/docs/examples/bdo/edit-product-dialog.md +95 -0
  65. package/docs/examples/bdo/filtered-product-table.md +100 -0
  66. package/docs/examples/bdo/product-listing.md +73 -0
  67. package/docs/examples/bdo/supplier-dropdown.md +60 -0
  68. package/docs/examples/workflow/approve-leave-request.md +76 -0
  69. package/docs/examples/workflow/filtered-activity-table.md +101 -0
  70. package/docs/examples/workflow/my-pending-requests.md +90 -0
  71. package/docs/examples/workflow/start-new-workflow.md +47 -0
  72. package/docs/examples/workflow/submit-leave-request.md +72 -0
  73. package/docs/examples/workflow/workflow-progress.md +49 -0
  74. package/docs/useActivityForm/README.md +241 -0
  75. package/docs/useActivityForm/api_reference.md +279 -0
  76. package/docs/useActivityTable/README.md +263 -0
  77. package/docs/useActivityTable/api_reference.md +294 -0
  78. package/docs/useBDOForm/README.md +172 -0
  79. package/docs/useBDOForm/api_reference.md +244 -0
  80. package/docs/useBDOTable/README.md +242 -0
  81. package/docs/useBDOTable/api_reference.md +253 -0
  82. package/docs/useFilter/README.md +323 -0
  83. package/docs/useFilter/api_reference.md +228 -0
  84. package/docs/workflow/README.md +158 -0
  85. package/docs/workflow/api_reference.md +161 -0
  86. package/package.json +2 -2
  87. package/sdk/auth/authConfig.ts +1 -1
  88. package/sdk/auth/types.ts +1 -1
  89. package/sdk/bdo/core/BaseBdo.ts +2 -2
  90. package/sdk/components/hooks/useActivityForm/createActivityItemProxy.ts +1 -1
  91. package/sdk/components/hooks/useActivityForm/createActivityResolver.ts +1 -1
  92. package/sdk/components/hooks/useActivityForm/types.ts +8 -10
  93. package/sdk/components/hooks/useActivityForm/useActivityForm.ts +52 -265
  94. package/sdk/components/hooks/useActivityTable/types.ts +6 -5
  95. package/sdk/components/hooks/useActivityTable/useActivityTable.ts +14 -43
  96. package/sdk/components/hooks/{useForm → useBDOForm}/index.ts +4 -3
  97. package/sdk/components/hooks/useBDOForm/shared.ts +250 -0
  98. package/sdk/components/hooks/{useForm → useBDOForm}/types.ts +9 -9
  99. package/sdk/components/hooks/{useForm/useForm.ts → useBDOForm/useBDOForm.ts} +70 -96
  100. package/sdk/components/hooks/useBDOTable/types.ts +20 -12
  101. package/sdk/components/hooks/useBDOTable/useBDOTable.ts +12 -7
  102. package/sdk/form.ts +2 -2
  103. package/sdk/form.types.ts +4 -4
  104. package/sdk/table.types.ts +2 -0
  105. package/sdk/types/constants.ts +4 -4
  106. package/sdk/workflow/Activity.ts +68 -13
  107. package/sdk/workflow/client.ts +65 -25
  108. package/sdk/workflow/types.ts +10 -2
  109. package/dist/components/hooks/useForm/createItemProxy.d.ts.map +0 -1
  110. package/dist/components/hooks/useForm/createResolver.d.ts.map +0 -1
  111. package/dist/components/hooks/useForm/index.d.ts +0 -5
  112. package/dist/components/hooks/useForm/index.d.ts.map +0 -1
  113. package/dist/components/hooks/useForm/types.d.ts.map +0 -1
  114. package/dist/components/hooks/useForm/useForm.d.ts.map +0 -1
  115. package/dist/constants-QX2RX-wu.cjs +0 -1
  116. package/dist/createResolver-AIgUwoS6.cjs +0 -1
  117. package/dist/createResolver-ZHXQ7QMa.js +0 -1078
  118. package/docs/api.md +0 -95
  119. package/docs/bdo.md +0 -224
  120. package/docs/gaps.md +0 -410
  121. package/docs/useActivityTable.md +0 -481
  122. package/docs/useBDOTable.md +0 -317
  123. package/docs/useFilter.md +0 -188
  124. package/docs/useForm.md +0 -376
  125. package/docs/workflow.md +0 -818
  126. /package/dist/components/hooks/{useForm → useBDOForm}/createItemProxy.d.ts +0 -0
  127. /package/dist/components/hooks/{useForm → useBDOForm}/createResolver.d.ts +0 -0
  128. /package/docs/{useAuth.md → useAuth/README.md} +0 -0
  129. /package/sdk/components/hooks/{useForm → useBDOForm}/createItemProxy.ts +0 -0
  130. /package/sdk/components/hooks/{useForm → useBDOForm}/createResolver.ts +0 -0
package/docs/README.md ADDED
@@ -0,0 +1,51 @@
1
+ # @ram_28/kf-ai-sdk Documentation
2
+
3
+ React SDK for building web applications with type-safe hooks for forms, tables, workflow, and authentication.
4
+
5
+ ## Authentication
6
+
7
+ **[`useAuth`](./useAuth/README.md)** — Cookie-based authentication with `AuthProvider`, login/logout, session management, and role checks. Wrap your app in `<AuthProvider>` and use `useAuth()` to access `user`, `isAuthenticated`, `login()`, `logout()`.
8
+
9
+ ## BDO (Business Data Objects)
10
+
11
+ BDO is the data access layer. See the [BDO module docs](./bdo/README.md) for field classes, Item proxy, and the three-generics pattern.
12
+
13
+ ### When building a form for a BDO record
14
+
15
+ **Use [`useBDOForm`](./useBDOForm/README.md)** · [API Reference](./useBDOForm/api_reference.md)
16
+
17
+ Create, edit, or view a single BDO record. Automatic validation, per-field server sync, and `handleSubmit` to persist.
18
+
19
+ ### When building a table of BDO records
20
+
21
+ **Use [`useBDOTable`](./useBDOTable/README.md)** · [API Reference](./useBDOTable/api_reference.md)
22
+
23
+ List BDO records with sorting, search, filtering, and pagination. Rows are proxies with `.get()` accessors.
24
+
25
+ ### When building a CRUD page (table + form dialog)
26
+
27
+ **Use `useBDOTable` + `useBDOForm` together.**
28
+
29
+ The table lists records; clicking a row opens a form dialog to create or edit.
30
+
31
+ ## Workflow
32
+
33
+ Workflow orchestrates multi-step business processes (e.g., employee submits leave → manager approves). See the [Workflow module docs](./workflow/README.md) for `Workflow`, `Activity`, and instance management.
34
+
35
+ ### When building a form for a workflow activity
36
+
37
+ **Use [`useActivityForm`](./useActivityForm/README.md)** · [API Reference](./useActivityForm/api_reference.md)
38
+
39
+ Fill in an activity's input fields. Same API shape as `useBDOForm` but operates on activity instances. Context-derived readonly fields from prior activities are discovered automatically from BP metadata.
40
+
41
+ ### When building a table of workflow activities
42
+
43
+ **Use [`useActivityTable`](./useActivityTable/README.md)** · [API Reference](./useActivityTable/api_reference.md)
44
+
45
+ List in-progress or completed activity instances. Same API shape as `useBDOTable` with activity system fields (`Status`, `AssignedTo`, `CompletedAt`, `BPInstanceId`).
46
+
47
+ ### When building a workflow page (table + form dialog)
48
+
49
+ **Use `useActivityTable` + `useActivityForm` together.**
50
+
51
+ The table lists activity instances; clicking a row opens a form dialog.
@@ -0,0 +1,161 @@
1
+ # BDO (Business Data Object)
2
+
3
+ Type-safe, role-based data access layer. Each BDO class extends `BaseBdo<TEntity, TEditable, TReadonly>` and exposes CRUD methods filtered by role permissions.
4
+
5
+ ## Imports
6
+
7
+ ```typescript
8
+ // Page component — import the generated role-specific BDO class
9
+ import { AdminProduct } from "../bdo/admin/Product";
10
+ ```
11
+
12
+ ```typescript
13
+ // BDO class definition — used by the js_sdk generator
14
+ import { BaseBdo, StringField, NumberField, BooleanField, DateField, SelectField, ReferenceField } from "@ram_28/kf-ai-sdk/bdo";
15
+ import type { StringFieldType, NumberFieldType, BooleanFieldType, DateFieldType, SelectFieldType, ReferenceFieldType, SystemFieldsType } from "@ram_28/kf-ai-sdk/types";
16
+ import type { ListOptionsType } from "@ram_28/kf-ai-sdk/api/types";
17
+ ```
18
+
19
+ ## Common Mistakes (READ FIRST)
20
+
21
+ 1. **`create()` returns `ItemType`, not `{ _id }`** — It returns a proxy-wrapped item with field accessors, not `CreateUpdateResponseType`. Use `item._id` to get the ID.
22
+ 2. **Use `.get()` to read field values** — `item.Title` returns a field accessor object, not the value. Use `item.Title.get()`.
23
+ 3. **Field names use `_name` not `name`** — System fields like `_created_by` return `{ _id, _name }`. Access the display name with `item._created_by.get()?._name`.
24
+ 4. **Memoize BDO instances in React** — Wrap in `useMemo` to prevent re-creation on every render:
25
+ ```typescript
26
+ const product = useMemo(() => new AdminProduct(), []);
27
+ ```
28
+
29
+ ## Quick Start
30
+
31
+ ```typescript
32
+ const product = new AdminProduct();
33
+
34
+ // Create — returns ItemType (proxy with field accessors)
35
+ const item = await product.create({ Title: "Widget", Price: 29.99 });
36
+ item._id; // "abc123"
37
+ item.Title.get(); // "Widget"
38
+ item.Price.get(); // 29.99
39
+
40
+ // List
41
+ const items = await product.list({ Page: 1, PageSize: 10 });
42
+ items[0].Title.get();
43
+
44
+ // Get single item
45
+ const found = await product.get("abc123");
46
+ found.Title.get(); // "Widget"
47
+
48
+ // Update — returns { _id: string }
49
+ await product.update("abc123", { Price: 39.99 });
50
+
51
+ // Delete — returns { status: string }
52
+ await product.delete("abc123");
53
+ ```
54
+
55
+ ## Usage Guide
56
+
57
+ ### CRUD Operations
58
+
59
+ ```typescript
60
+ const product = new AdminProduct();
61
+
62
+ // Create — returns ItemType with field accessors
63
+ const item = await product.create({
64
+ Title: "Widget",
65
+ Price: 29.99,
66
+ Category: "Electronics",
67
+ });
68
+ item._id; // direct string access
69
+
70
+ // Get single item
71
+ const item = await product.get("abc123");
72
+
73
+ // Update — returns { _id: string }
74
+ const { _id } = await product.update("abc123", { Price: 39.99 });
75
+
76
+ // Delete — returns { status: string }
77
+ const { status } = await product.delete("abc123");
78
+
79
+ // Count
80
+ const total = await product.count();
81
+ const filtered = await product.count({
82
+ Filter: {
83
+ Operator: "And",
84
+ Condition: [
85
+ { Operator: "eq", LHSField: "Category", RHSValue: "Electronics" },
86
+ ],
87
+ },
88
+ });
89
+ ```
90
+
91
+ ### ItemType Field Accessors
92
+
93
+ Every `get()`, `list()`, and `create()` call returns `ItemType` — a proxy with typed field accessors.
94
+
95
+ ```typescript
96
+ const item = await product.get("abc123");
97
+
98
+ // Read values
99
+ item._id; // string (direct, not an accessor)
100
+ item.Title.get(); // string | undefined
101
+ item.Price.getOrDefault(0); // number (never undefined)
102
+
103
+ // Write values (editable fields only)
104
+ item.Title.set("New Title");
105
+
106
+ // Field metadata
107
+ item.Title.label; // "Product Title"
108
+ item.Title.required; // true
109
+ item.Title.readOnly; // false
110
+ item.Title.defaultValue; // undefined
111
+ item.Title.meta; // raw backend field meta
112
+
113
+ // Validation
114
+ item.Title.validate(); // { valid: boolean, errors: string[] }
115
+ item.validate(); // validates all fields, returns { valid, errors }
116
+
117
+ // Serialize
118
+ item.toJSON(); // { Title: "New Title", Price: 29.99, ... }
119
+ ```
120
+
121
+ ### List with Filter, Sort, and Pagination
122
+
123
+ ```typescript
124
+ const items = await product.list({
125
+ Filter: {
126
+ Operator: "And",
127
+ Condition: [
128
+ { Operator: "eq", LHSField: "Category", RHSValue: "Electronics" },
129
+ { Operator: "gte", LHSField: "Price", RHSValue: 10 },
130
+ ],
131
+ },
132
+ Sort: [{ Price: "DESC" }],
133
+ Page: 1,
134
+ PageSize: 20,
135
+ });
136
+ ```
137
+
138
+ ### Metric (Aggregation)
139
+
140
+ ```typescript
141
+ const result = await product.metric({
142
+ GroupBy: ["Category"],
143
+ Metric: [{ Field: "Price", Type: "Avg" }],
144
+ });
145
+ // result.Data = [{ Category: "Electronics", Price: 299.5 }, ...]
146
+ ```
147
+
148
+ ### Pivot (Cross-Tabulation)
149
+
150
+ ```typescript
151
+ const result = await product.pivot({
152
+ Row: ["Category"],
153
+ Column: ["IsActive"],
154
+ Metric: [{ Field: "_id", Type: "Count" }],
155
+ });
156
+ // result.Data = { RowHeader: [...], ColumnHeader: [...], Value: [[...]] }
157
+ ```
158
+
159
+ ## Further Reading
160
+
161
+ - [API Reference](./api_reference.md) — full method signatures, parameter types, and return types
@@ -0,0 +1,281 @@
1
+ ```typescript
2
+ import { BaseBdo, StringField, NumberField, BooleanField, DateField, SelectField, ReferenceField } from "@ram_28/kf-ai-sdk/bdo";
3
+ import type {
4
+ ItemType,
5
+ EditableFieldAccessorType,
6
+ ReadonlyFieldAccessorType,
7
+ ValidationResultType,
8
+ BdoMetaType,
9
+ } from "@ram_28/kf-ai-sdk/bdo/types";
10
+ import type {
11
+ ListOptionsType,
12
+ FilterType,
13
+ ConditionGroupType,
14
+ ConditionType,
15
+ SortType,
16
+ CreateUpdateResponseType,
17
+ DeleteResponseType,
18
+ MetricOptionsType,
19
+ MetricResponseType,
20
+ PivotOptionsType,
21
+ PivotResponseType,
22
+ } from "@ram_28/kf-ai-sdk/api/types";
23
+ import type {
24
+ StringFieldType,
25
+ NumberFieldType,
26
+ BooleanFieldType,
27
+ DateFieldType,
28
+ DateTimeFieldType,
29
+ TextFieldType,
30
+ SelectFieldType,
31
+ ReferenceFieldType,
32
+ UserFieldType,
33
+ FileFieldType,
34
+ ImageFieldType,
35
+ ArrayFieldType,
36
+ ObjectFieldType,
37
+ SystemFieldsType,
38
+ } from "@ram_28/kf-ai-sdk/types";
39
+ ```
40
+
41
+ ## Methods
42
+
43
+ All methods are `protected` on `BaseBdo`. Subclasses expose them as `public` per role.
44
+
45
+ | Method | Params | Returns |
46
+ |--------|--------|---------|
47
+ | `get(id)` | `id: string` | `Promise<ItemType<TEditable, TReadonly>>` |
48
+ | `list(options?)` | `options?: ListOptionsType` | `Promise<ItemType<TEditable, TReadonly>[]>` |
49
+ | `count(options?)` | `options?: ListOptionsType` | `Promise<number>` |
50
+ | `create(data)` | `data: Partial<TEditable>` | `Promise<ItemType<TEditable, TReadonly>>` |
51
+ | `update(id, data)` | `id: string, data: Partial<TEditable>` | `Promise<CreateUpdateResponseType>` |
52
+ | `delete(id)` | `id: string` | `Promise<DeleteResponseType>` |
53
+ | `metric(options)` | `options: Omit<MetricOptionsType, "Type">` | `Promise<MetricResponseType>` |
54
+ | `pivot(options)` | `options: Omit<PivotOptionsType, "Type">` | `Promise<PivotResponseType>` |
55
+
56
+ ## Types
57
+
58
+ ### ItemType\<TEditable, TReadonly\>
59
+
60
+ Proxy-wrapped record returned by `get()`, `list()`, and `create()`. Provides typed field accessors for each field.
61
+
62
+ ```typescript
63
+ type ItemType<TEditable, TReadonly> = {
64
+ readonly _id: string; // direct string access
65
+
66
+ // Editable fields → EditableFieldAccessorType<T>
67
+ // Readonly fields → ReadonlyFieldAccessorType<T>
68
+
69
+ validate(): ValidationResultType; // validates all fields
70
+ toJSON(): Partial<TEditable & TReadonly>;
71
+ };
72
+ ```
73
+
74
+ ### EditableFieldAccessorType\<T\>
75
+
76
+ Accessor for fields the current role can write.
77
+
78
+ ```typescript
79
+ interface EditableFieldAccessorType<T> {
80
+ get(): T | undefined;
81
+ getOrDefault(fallback: T): T;
82
+ set(value: T): void;
83
+ validate(): ValidationResultType;
84
+ readonly label: string;
85
+ readonly required: boolean;
86
+ readonly readOnly: false;
87
+ readonly defaultValue: unknown;
88
+ readonly meta: BaseFieldMetaType;
89
+ }
90
+ ```
91
+
92
+ ### ReadonlyFieldAccessorType\<T\>
93
+
94
+ Accessor for fields the current role can only read. Same as editable but no `set()`.
95
+
96
+ ```typescript
97
+ interface ReadonlyFieldAccessorType<T> {
98
+ get(): T | undefined;
99
+ getOrDefault(fallback: T): T;
100
+ validate(): ValidationResultType;
101
+ readonly label: string;
102
+ readonly required: boolean;
103
+ readonly readOnly: true;
104
+ readonly defaultValue: unknown;
105
+ readonly meta: BaseFieldMetaType;
106
+ }
107
+ ```
108
+
109
+ ### ValidationResultType
110
+
111
+ ```typescript
112
+ interface ValidationResultType {
113
+ valid: boolean;
114
+ errors: string[];
115
+ }
116
+ ```
117
+
118
+ ### ListOptionsType
119
+
120
+ ```typescript
121
+ interface ListOptionsType {
122
+ Filter?: FilterType;
123
+ Sort?: SortType;
124
+ Page?: number; // 1-indexed
125
+ PageSize?: number;
126
+ Search?: string;
127
+ Field?: string[]; // specific fields to return
128
+ }
129
+ ```
130
+
131
+ ### FilterType / ConditionGroupType / ConditionType
132
+
133
+ ```typescript
134
+ // Root filter — alias for ConditionGroupType
135
+ type FilterType = ConditionGroupType;
136
+
137
+ interface ConditionGroupType {
138
+ Operator: "And" | "Or" | "Not";
139
+ Condition: Array<ConditionType | ConditionGroupType>;
140
+ }
141
+
142
+ interface ConditionType {
143
+ Operator: string; // "eq", "neq", "gt", "gte", "lt", "lte", "contains", "startswith", etc.
144
+ LHSField: string; // field name
145
+ RHSValue: any; // comparison value
146
+ RHSType?: string; // defaults to "Constant"
147
+ }
148
+ ```
149
+
150
+ ### SortType
151
+
152
+ ```typescript
153
+ type SortType = Record<string, "ASC" | "DESC">[];
154
+ // Example: [{ "Price": "DESC" }, { "Title": "ASC" }]
155
+ ```
156
+
157
+ ### CreateUpdateResponseType
158
+
159
+ ```typescript
160
+ interface CreateUpdateResponseType {
161
+ _id: string;
162
+ }
163
+ ```
164
+
165
+ ### DeleteResponseType
166
+
167
+ ```typescript
168
+ interface DeleteResponseType {
169
+ status: string;
170
+ }
171
+ ```
172
+
173
+ ### MetricOptionsType
174
+
175
+ Omit `Type` when calling `bdo.metric()` — it is added automatically.
176
+
177
+ ```typescript
178
+ interface MetricOptionsType {
179
+ Type: "Metric"; // omit when calling bdo.metric()
180
+ GroupBy: string[];
181
+ Metric: MetricFieldType[];
182
+ Filter?: FilterType;
183
+ }
184
+
185
+ interface MetricFieldType {
186
+ Field: string;
187
+ Type: string; // "Count" | "Sum" | "Avg" | "Max" | "Min"
188
+ }
189
+ ```
190
+
191
+ ### MetricResponseType
192
+
193
+ ```typescript
194
+ interface MetricResponseType {
195
+ Data: Record<string, any>[];
196
+ }
197
+ ```
198
+
199
+ ### PivotOptionsType
200
+
201
+ Omit `Type` when calling `bdo.pivot()` — it is added automatically.
202
+
203
+ ```typescript
204
+ interface PivotOptionsType {
205
+ Type: "Pivot"; // omit when calling bdo.pivot()
206
+ Row: string[];
207
+ Column: string[];
208
+ Metric: MetricFieldType[];
209
+ Filter?: FilterType;
210
+ }
211
+ ```
212
+
213
+ ### PivotResponseType
214
+
215
+ ```typescript
216
+ interface PivotResponseType {
217
+ Data: {
218
+ RowHeader: PivotHeaderItemType[];
219
+ ColumnHeader: PivotHeaderItemType[];
220
+ Value: (number | string | null)[][];
221
+ };
222
+ }
223
+
224
+ interface PivotHeaderItemType {
225
+ Key: string;
226
+ Children?: PivotHeaderItemType[] | null;
227
+ }
228
+ ```
229
+
230
+ ### SystemFieldsType
231
+
232
+ Seven system-managed fields inherited from `BaseBdo`. Never redeclare in subclasses.
233
+
234
+ ```typescript
235
+ type SystemFieldsType = {
236
+ _id: StringFieldType;
237
+ _created_at: DateTimeFieldType;
238
+ _modified_at: DateTimeFieldType;
239
+ _created_by: UserFieldType;
240
+ _modified_by: UserFieldType;
241
+ _version: StringFieldType;
242
+ _m_version: StringFieldType;
243
+ };
244
+ ```
245
+
246
+ ### Field Value Types
247
+
248
+ | Type | Resolves To |
249
+ |------|-------------|
250
+ | `StringFieldType` | `string` |
251
+ | `TextFieldType` | `string` |
252
+ | `NumberFieldType` | `number` |
253
+ | `BooleanFieldType` | `boolean` |
254
+ | `DateFieldType` | `"YYYY-MM-DD"` |
255
+ | `DateTimeFieldType` | `"YYYY-MM-DDThh:mm:ssZ"` |
256
+ | `SelectFieldType<T>` | `T` |
257
+ | `ReferenceFieldType<T>` | `T` |
258
+ | `UserFieldType` | `{ _id: string; _name: string }` |
259
+ | `ImageFieldType` | `FileType \| null` |
260
+ | `FileFieldType` | `FileType[]` |
261
+ | `ArrayFieldType<T>` | `T[]` |
262
+ | `ObjectFieldType<T>` | `T` |
263
+
264
+ ### Generated Type Patterns
265
+
266
+ The js_sdk generator creates these types per entity:
267
+
268
+ ```typescript
269
+ // entities/Product.ts
270
+ export type ProductType = {
271
+ ProductId: StringFieldType;
272
+ Title: StringFieldType;
273
+ Price: NumberFieldType;
274
+ // ... business fields
275
+ } & SystemFieldsType;
276
+
277
+ // admin/Product.ts
278
+ type AdminProductEditableFieldType = Omit<ProductType, keyof SystemFieldsType>;
279
+ type AdminProductReadonlyFieldType = Record<string, never>;
280
+ // or Pick<ProductType, "Field1" | "Field2"> for limited access
281
+ ```
@@ -0,0 +1,69 @@
1
+ # Create Product
2
+
3
+ > Create a new product using `useBDOForm` with validation, select fields, and submit handling.
4
+
5
+ ```tsx
6
+ import { useMemo } from "react";
7
+ import { useBDOForm } from "@ram_28/kf-ai-sdk/form";
8
+ import type { UseBDOFormReturnType } from "@ram_28/kf-ai-sdk/form/types";
9
+ import { BuyerProduct } from "@/bdo/buyer/Product";
10
+ import type { BuyerProductEntityType } from "@/bdo/buyer/Product";
11
+ import type { FieldErrors } from "react-hook-form";
12
+
13
+ export default function CreateProductForm() {
14
+ const product = useMemo(() => new BuyerProduct(), []);
15
+
16
+ const { register, handleSubmit, errors, isLoading, isSubmitting, watch, setValue }: UseBDOFormReturnType<BuyerProduct> =
17
+ useBDOForm({ bdo: product, defaultValues: { Title: "", Price: 0 } });
18
+
19
+ if (isLoading) return <p>Loading...</p>;
20
+
21
+ const onSuccess = (data: { _id: string }) => console.log("Created:", data._id);
22
+ const onError = (err: FieldErrors<BuyerProductEntityType> | Error) => {
23
+ if (err instanceof Error) console.error(err.message);
24
+ };
25
+
26
+ return (
27
+ <form onSubmit={handleSubmit(onSuccess, onError)}>
28
+ {/* Text input with register() */}
29
+ <label>{product.Title.label} {product.Title.required && <span>*</span>}</label>
30
+ <input {...register(product.Title.id)} />
31
+ {errors.Title && <p>{errors.Title.message}</p>}
32
+
33
+ <label>{product.Description.label}</label>
34
+ <textarea {...register(product.Description.id)} rows={3} />
35
+ {errors.Description && <p>{errors.Description.message}</p>}
36
+
37
+ {/* Number input with register() */}
38
+ <label>{product.Price.label} {product.Price.required && <span>*</span>}</label>
39
+ <input type="number" step="0.01" {...register(product.Price.id)} />
40
+ {errors.Price && <p>{errors.Price.message}</p>}
41
+
42
+ {/* Select field — watch/setValue, not register */}
43
+ <label>{product.Category.label} {product.Category.required && <span>*</span>}</label>
44
+ <select
45
+ value={watch(product.Category.id) ?? ""}
46
+ onChange={(e) => setValue(product.Category.id, e.target.value)}
47
+ >
48
+ <option value="">Select category</option>
49
+ {product.Category.options.map((opt) => (
50
+ <option key={opt.value} value={opt.value}>{opt.label}</option>
51
+ ))}
52
+ </select>
53
+ {errors.Category && <p>{errors.Category.message}</p>}
54
+
55
+ <button type="submit" disabled={isSubmitting}>
56
+ {isSubmitting ? "Saving..." : "Add Product"}
57
+ </button>
58
+ </form>
59
+ );
60
+ }
61
+ ```
62
+
63
+ ## Key Patterns
64
+
65
+ - **Create mode** -- no `recordId` passed to `useBDOForm`; a draft is allocated on mount
66
+ - **`register()`** -- for text and number inputs that fire native change events
67
+ - **`watch()` + `setValue()`** -- for select fields and other custom components
68
+ - **`handleSubmit(onSuccess, onError)`** -- validates, filters to editable fields, calls the API; never call `bdo.create()` manually
69
+ - **Validation errors** -- `errors.FieldName.message` shows constraint violations automatically
@@ -0,0 +1,95 @@
1
+ # Edit Product Dialog
2
+
3
+ > Click a table row to open an edit form in a dialog, save, and refetch the table.
4
+
5
+ ```tsx
6
+ import { useState, useMemo } from "react";
7
+ import { useBDOTable } from "@ram_28/kf-ai-sdk/table";
8
+ import type { UseBDOTableReturnType } from "@ram_28/kf-ai-sdk/table/types";
9
+ import { useBDOForm } from "@ram_28/kf-ai-sdk/form";
10
+ import type { UseBDOFormReturnType } from "@ram_28/kf-ai-sdk/form/types";
11
+ import { BuyerProduct } from "@/bdo/buyer/Product";
12
+ import type { BuyerProductEntityType } from "@/bdo/buyer/Product";
13
+ import type { FieldErrors } from "react-hook-form";
14
+
15
+ export default function ProductPage() {
16
+ const [showForm, setShowForm] = useState(false);
17
+ const [selectedId, setSelectedId] = useState<string | null>(null);
18
+
19
+ const product = useMemo(() => new BuyerProduct(), []);
20
+
21
+ // ── Table ────────────────────────────────────────────────────
22
+ const table: UseBDOTableReturnType<BuyerProduct> = useBDOTable({
23
+ bdo: product,
24
+ initialState: { sort: [{ Title: "ASC" }], pagination: { pageNo: 1, pageSize: 10 } },
25
+ });
26
+
27
+ // ── Form (create when selectedId is null, edit when string) ──
28
+ const { register, handleSubmit, errors, isLoading: formLoading, isSubmitting, watch, setValue, isDirty }: UseBDOFormReturnType<BuyerProduct> =
29
+ useBDOForm({ bdo: product, recordId: selectedId ?? undefined });
30
+
31
+ const handleCreate = () => { setSelectedId(null); setShowForm(true); };
32
+ const handleEdit = (id: string) => { setSelectedId(id); setShowForm(true); };
33
+ const onSuccess = () => { setShowForm(false); setSelectedId(null); table.refetch(); };
34
+ const onError = (err: FieldErrors<BuyerProductEntityType> | Error) => {
35
+ if (err instanceof Error) console.error(err.message);
36
+ };
37
+
38
+ if (table.isLoading) return <p>Loading...</p>;
39
+
40
+ return (
41
+ <div>
42
+ <button onClick={handleCreate}>Add Product</button>
43
+
44
+ <table>
45
+ <thead>
46
+ <tr>
47
+ <th>{product.Title.label}</th>
48
+ <th>{product.Price.label}</th>
49
+ </tr>
50
+ </thead>
51
+ <tbody>
52
+ {table.rows.map((row) => (
53
+ <tr key={row._id} onClick={() => handleEdit(row._id)} style={{ cursor: "pointer" }}>
54
+ <td>{row.Title.get()}</td>
55
+ <td>${row.Price.get()?.toFixed(2)}</td>
56
+ </tr>
57
+ ))}
58
+ </tbody>
59
+ </table>
60
+
61
+ {/* Dialog form */}
62
+ {showForm && (
63
+ <dialog open>
64
+ <h2>{selectedId ? "Edit Product" : "Add Product"}</h2>
65
+ {formLoading ? (
66
+ <p>Loading form...</p>
67
+ ) : (
68
+ <form onSubmit={handleSubmit(onSuccess, onError)}>
69
+ <label>{product.Title.label}</label>
70
+ <input {...register(product.Title.id)} />
71
+ {errors.Title && <p>{errors.Title.message}</p>}
72
+
73
+ <label>{product.Price.label}</label>
74
+ <input type="number" step="0.01" {...register(product.Price.id)} />
75
+ {errors.Price && <p>{errors.Price.message}</p>}
76
+
77
+ <button type="button" onClick={() => setShowForm(false)}>Cancel</button>
78
+ <button type="submit" disabled={isSubmitting || (!!selectedId && !isDirty)}>
79
+ {isSubmitting ? "Saving..." : selectedId ? "Save Changes" : "Add Product"}
80
+ </button>
81
+ </form>
82
+ )}
83
+ </dialog>
84
+ )}
85
+ </div>
86
+ );
87
+ }
88
+ ```
89
+
90
+ ## Key Patterns
91
+
92
+ - **Shared BDO instance** -- `useMemo(() => new BuyerProduct(), [])` is passed to both `useBDOTable` and `useBDOForm`
93
+ - **Create vs edit mode** -- `selectedId` is `null` for create (no `recordId`), or a string for edit
94
+ - **`table.refetch()` after save** -- called in `onSuccess` to refresh the table data
95
+ - **`isDirty` guard** -- disables the submit button in edit mode when no changes have been made