@ram_28/kf-ai-sdk 2.0.14 → 2.0.15

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 (119) hide show
  1. package/README.md +2 -1
  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.cjs +1 -1
  9. package/dist/bdo.mjs +228 -472
  10. package/dist/{client-DnO2KKrw.cjs → client-D5k4SYuw.cjs} +1 -1
  11. package/dist/{client-iQTqFDNI.js → client-_ayziI1d.js} +33 -32
  12. package/dist/components/hooks/index.d.ts +9 -3
  13. package/dist/components/hooks/index.d.ts.map +1 -1
  14. package/dist/{workflow/components → components/hooks}/useActivityForm/createActivityItemProxy.d.ts +9 -5
  15. package/dist/components/hooks/useActivityForm/createActivityItemProxy.d.ts.map +1 -0
  16. package/dist/components/hooks/useActivityForm/createActivityResolver.d.ts +23 -0
  17. package/dist/components/hooks/useActivityForm/createActivityResolver.d.ts.map +1 -0
  18. package/dist/components/hooks/useActivityForm/index.d.ts.map +1 -0
  19. package/dist/{workflow/components → components/hooks}/useActivityForm/types.d.ts +11 -7
  20. package/dist/components/hooks/useActivityForm/types.d.ts.map +1 -0
  21. package/dist/{workflow/components → components/hooks}/useActivityForm/useActivityForm.d.ts +2 -2
  22. package/dist/components/hooks/useActivityForm/useActivityForm.d.ts.map +1 -0
  23. package/dist/components/hooks/useActivityTable/index.d.ts +4 -0
  24. package/dist/components/hooks/useActivityTable/index.d.ts.map +1 -0
  25. package/dist/components/hooks/useActivityTable/types.d.ts +36 -0
  26. package/dist/components/hooks/useActivityTable/types.d.ts.map +1 -0
  27. package/dist/components/hooks/useActivityTable/useActivityTable.d.ts +4 -0
  28. package/dist/components/hooks/useActivityTable/useActivityTable.d.ts.map +1 -0
  29. package/dist/components/hooks/useBDOTable/index.d.ts +3 -0
  30. package/dist/components/hooks/useBDOTable/index.d.ts.map +1 -0
  31. package/dist/components/hooks/useBDOTable/types.d.ts +26 -0
  32. package/dist/components/hooks/useBDOTable/types.d.ts.map +1 -0
  33. package/dist/components/hooks/useBDOTable/useBDOTable.d.ts +3 -0
  34. package/dist/components/hooks/useBDOTable/useBDOTable.d.ts.map +1 -0
  35. package/dist/components/hooks/useTable/index.d.ts +2 -2
  36. package/dist/components/hooks/useTable/index.d.ts.map +1 -1
  37. package/dist/components/hooks/useTable/types.d.ts +11 -10
  38. package/dist/components/hooks/useTable/types.d.ts.map +1 -1
  39. package/dist/components/hooks/useTable/useTable.d.ts +1 -1
  40. package/dist/components/hooks/useTable/useTable.d.ts.map +1 -1
  41. package/dist/createResolver-AIgUwoS6.cjs +1 -0
  42. package/dist/createResolver-ZHXQ7QMa.js +1078 -0
  43. package/dist/form.cjs +1 -1
  44. package/dist/form.mjs +252 -314
  45. package/dist/{metadata-DpfI3zRN.js → metadata-Cc1mBcLS.js} +1 -1
  46. package/dist/{metadata-DgLSJkF5.cjs → metadata-DWXQPDav.cjs} +1 -1
  47. package/dist/table.cjs +1 -1
  48. package/dist/table.d.ts +1 -0
  49. package/dist/table.d.ts.map +1 -1
  50. package/dist/table.mjs +16 -192
  51. package/dist/table.types.d.ts +2 -1
  52. package/dist/table.types.d.ts.map +1 -1
  53. package/dist/types/base-fields.d.ts +4 -4
  54. package/dist/types/base-fields.d.ts.map +1 -1
  55. package/dist/useTable-CeRklbdT.cjs +1 -0
  56. package/dist/useTable-DS0-WInw.js +203 -0
  57. package/dist/workflow/Activity.d.ts +9 -9
  58. package/dist/workflow/Activity.d.ts.map +1 -1
  59. package/dist/workflow/client.d.ts.map +1 -1
  60. package/dist/workflow/createFieldFromMeta.d.ts +29 -0
  61. package/dist/workflow/createFieldFromMeta.d.ts.map +1 -0
  62. package/dist/workflow/index.d.ts +1 -2
  63. package/dist/workflow/index.d.ts.map +1 -1
  64. package/dist/workflow/types.d.ts +12 -12
  65. package/dist/workflow/types.d.ts.map +1 -1
  66. package/dist/workflow.cjs +1 -1
  67. package/dist/workflow.d.ts +5 -2
  68. package/dist/workflow.d.ts.map +1 -1
  69. package/dist/workflow.mjs +716 -338
  70. package/dist/workflow.types.d.ts +1 -0
  71. package/dist/workflow.types.d.ts.map +1 -1
  72. package/docs/gaps.md +410 -0
  73. package/docs/useActivityTable.md +481 -0
  74. package/docs/useBDOTable.md +317 -0
  75. package/docs/workflow.md +143 -34
  76. package/package.json +1 -1
  77. package/sdk/bdo/fields/UserField.ts +1 -1
  78. package/sdk/components/hooks/index.ts +28 -5
  79. package/sdk/components/hooks/useActivityForm/createActivityItemProxy.ts +400 -0
  80. package/sdk/components/hooks/useActivityForm/createActivityResolver.ts +87 -0
  81. package/sdk/{workflow/components → components/hooks}/useActivityForm/types.ts +21 -8
  82. package/sdk/components/hooks/useActivityForm/useActivityForm.ts +628 -0
  83. package/sdk/components/hooks/useActivityTable/index.ts +8 -0
  84. package/sdk/components/hooks/useActivityTable/types.ts +45 -0
  85. package/sdk/components/hooks/useActivityTable/useActivityTable.ts +71 -0
  86. package/sdk/components/hooks/useBDOTable/index.ts +2 -0
  87. package/sdk/components/hooks/useBDOTable/types.ts +24 -0
  88. package/sdk/components/hooks/useBDOTable/useBDOTable.ts +15 -0
  89. package/sdk/components/hooks/useTable/index.ts +3 -3
  90. package/sdk/components/hooks/useTable/types.ts +16 -12
  91. package/sdk/components/hooks/useTable/useTable.ts +56 -49
  92. package/sdk/table.ts +4 -1
  93. package/sdk/table.types.ts +7 -4
  94. package/sdk/types/base-fields.ts +4 -4
  95. package/sdk/workflow/Activity.ts +14 -13
  96. package/sdk/workflow/client.ts +21 -8
  97. package/sdk/workflow/createFieldFromMeta.ts +110 -0
  98. package/sdk/workflow/index.ts +1 -6
  99. package/sdk/workflow/types.ts +13 -12
  100. package/sdk/workflow.ts +11 -2
  101. package/sdk/workflow.types.ts +7 -0
  102. package/dist/BaseField-B6da88U7.js +0 -40
  103. package/dist/BaseField-Drp0-OxL.cjs +0 -1
  104. package/dist/error-handling-CAoD0Kwb.cjs +0 -1
  105. package/dist/error-handling-CrhTtD88.js +0 -14
  106. package/dist/index.esm-Cj63v5ny.js +0 -1014
  107. package/dist/index.esm-DuwT11sx.cjs +0 -1
  108. package/dist/workflow/components/useActivityForm/createActivityItemProxy.d.ts.map +0 -1
  109. package/dist/workflow/components/useActivityForm/createActivityResolver.d.ts +0 -22
  110. package/dist/workflow/components/useActivityForm/createActivityResolver.d.ts.map +0 -1
  111. package/dist/workflow/components/useActivityForm/index.d.ts.map +0 -1
  112. package/dist/workflow/components/useActivityForm/types.d.ts.map +0 -1
  113. package/dist/workflow/components/useActivityForm/useActivityForm.d.ts.map +0 -1
  114. package/docs/useTable.md +0 -369
  115. package/sdk/workflow/components/useActivityForm/createActivityItemProxy.ts +0 -130
  116. package/sdk/workflow/components/useActivityForm/createActivityResolver.ts +0 -61
  117. package/sdk/workflow/components/useActivityForm/useActivityForm.ts +0 -386
  118. /package/dist/{workflow/components → components/hooks}/useActivityForm/index.d.ts +0 -0
  119. /package/sdk/{workflow/components → components/hooks}/useActivityForm/index.ts +0 -0
@@ -0,0 +1,317 @@
1
+ # useBDOTable
2
+
3
+ Thin wrapper around `useTable` for BDO (Business Data Object) tables. Instead of manually wiring up `queryKey`, `listFn`, and `countFn`, you 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 `meta`, `list()`, and `count()`. A plain object or entity type will not work.
32
+
33
+ ```typescript
34
+ // ❌ WRONG — plain object without list/count methods
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 `useForm` 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 with list() and count() methods */
247
+ bdo: {
248
+ meta: { readonly _id: string; readonly name: string };
249
+ list(options?: any): Promise<any>;
250
+ count(options?: any): Promise<any>;
251
+ };
252
+
253
+ /** Initial state */
254
+ initialState?: {
255
+ sort?: SortType;
256
+ pagination?: PaginationStateType;
257
+ filter?: UseFilterOptionsType<T>;
258
+ };
259
+
260
+ /** Error callback */
261
+ onError?: (error: Error) => void;
262
+
263
+ /** Success callback — receives rows from current page */
264
+ onSuccess?: (data: T[]) => void;
265
+ }
266
+ ```
267
+
268
+ ### UseBDOTableReturnType
269
+
270
+ ```typescript
271
+ export type UseBDOTableReturnType<T> = UseTableReturnType<T>;
272
+ ```
273
+
274
+ The return type is identical to `UseTableReturnType<T>`. All properties — `rows`, `totalItems`, `isLoading`, `isFetching`, `error`, `search`, `sort`, `filter`, `pagination`, and `refetch` — behave the same.
275
+
276
+ ---
277
+
278
+ ## Search, Sort, Filter, and Pagination
279
+
280
+ These features are inherited from the base `useTable` hook. `useBDOTable` passes `initialState`, `onError`, and `onSuccess` straight through.
281
+
282
+ - **Search** — `table.search.set(field, query)`, `table.search.clear()`, 300ms debounce
283
+ - **Sort** — `table.sort.toggle(field)`, `table.sort.set(field, direction)`, `table.sort.clear()`
284
+ - **Filter** — `table.filter.addCondition(...)`, `table.filter.removeCondition(...)`, `table.filter.clearAllConditions()`
285
+ - **Pagination** — `table.pagination.goToNext()`, `table.pagination.goToPrevious()`, `table.pagination.goToPage(n)`, `table.pagination.setPageSize(n)`
286
+
287
+ ---
288
+
289
+ ## Migration Guide: `useTable` to `useBDOTable`
290
+
291
+ ### Before (useTable)
292
+
293
+ ```typescript
294
+ const table = useTable<BuyerProductFieldType>({
295
+ queryKey: ["table", product.meta._id],
296
+ listFn: (opts) => product.list(opts),
297
+ countFn: (opts) => product.count(opts),
298
+ initialState: { sort: [{ [product.Title.id]: "ASC" }], pagination: { pageNo: 1, pageSize: 10 } },
299
+ });
300
+ ```
301
+
302
+ ### After (useBDOTable)
303
+
304
+ ```typescript
305
+ const table = useBDOTable<BuyerProductFieldType>({
306
+ bdo: product,
307
+ initialState: { sort: [{ [product.Title.id]: "ASC" }], pagination: { pageNo: 1, pageSize: 10 } },
308
+ });
309
+ ```
310
+
311
+ | Property | `useTable` | `useBDOTable` |
312
+ |----------|-----------|---------------|
313
+ | Data source | `queryKey` + `listFn` + `countFn` | `bdo` (single property) |
314
+ | Query key | Manual: `["table", bdo.meta._id]` | Automatic: derived from `bdo.meta._id` |
315
+ | List function | Manual: `(opts) => bdo.list(opts)` | Automatic: bound from `bdo.list()` |
316
+ | Count function | Manual: `(opts) => bdo.count(opts)` | Automatic: bound from `bdo.count()` |
317
+ | Return type | `UseTableReturnType<T>` | `UseBDOTableReturnType<T>` (alias) |
package/docs/workflow.md CHANGED
@@ -11,6 +11,8 @@ import {
11
11
  Activity,
12
12
  ActivityInstance,
13
13
  useActivityForm,
14
+ useActivityTable,
15
+ ActivityTableStatus,
14
16
  } from "@ram_28/kf-ai-sdk/workflow";
15
17
 
16
18
  // Type-only exports
@@ -20,6 +22,10 @@ import type {
20
22
  WorkflowStartResponseType,
21
23
  UseActivityFormOptions,
22
24
  UseActivityFormReturn,
25
+ UseActivityTableOptionsType,
26
+ UseActivityTableReturnType,
27
+ ActivityTableStatusType,
28
+ ActivityRowType,
23
29
  } from "@ram_28/kf-ai-sdk/workflow";
24
30
 
25
31
  // Field classes (for defining Activity fields)
@@ -31,7 +37,7 @@ import {
31
37
  DateTimeField,
32
38
  SelectField,
33
39
  ReferenceField,
34
- } from "@ram_28/kf-ai-sdk/bdo/fields";
40
+ } from '@ram_28/kf-ai-sdk/bdo/fields';
35
41
 
36
42
  // Field types (for entity type definitions)
37
43
  import type {
@@ -42,7 +48,7 @@ import type {
42
48
  DateTimeFieldType,
43
49
  SelectFieldType,
44
50
  ReferenceFieldType,
45
- } from "@ram_28/kf-ai-sdk/types";
51
+ } from '@ram_28/kf-ai-sdk/types';
46
52
  ```
47
53
 
48
54
  ---
@@ -82,11 +88,18 @@ System fields present on every activity instance. Returned alongside activity-sp
82
88
  type ActivityInstanceFieldsType = {
83
89
  _id: StringFieldType;
84
90
  Status: SelectFieldType<"InProgress" | "Completed">;
85
- AssignedTo: ReferenceFieldType<{ _id: StringFieldType; username: StringFieldType }>;
91
+ AssignedTo: UserFieldType[];
86
92
  CompletedAt: DateTimeFieldType;
87
93
  };
88
94
  ```
89
95
 
96
+ ### Activity Table Types
97
+
98
+ See the dedicated [useActivityTable documentation](./useActivityTable.md) for `ActivityTableStatus`, `ActivityRowType`, `UseActivityTableOptionsType`, and `UseActivityTableReturnType`.
99
+
100
+ **Key change:** Entity fields are now nested under `ADO` instead of being flattened at the top level. Access entity fields as `row.ADO.FieldName`.
101
+
102
+
90
103
  ### UseActivityFormOptions\<A\>
91
104
 
92
105
  ```typescript
@@ -141,6 +154,13 @@ interface UseActivityFormReturn<A extends Activity<any, any, any>> {
141
154
  }
142
155
  ```
143
156
 
157
+ ### File & Image Types
158
+
159
+ Image accessor: `item.field.get()` returns `FileType | null`. Has `upload(file: File)`, `deleteAttachment()`, `getDownloadUrl()`.
160
+ File accessor: `item.field.get()` returns `FileType[]`. Has `upload(files: File[])`, `deleteAttachment(id)`, `getDownloadUrl(id)`.
161
+
162
+ Activity forms always have an instance ID, so attachment operations work immediately — no draft creation is needed.
163
+
144
164
  ---
145
165
 
146
166
  ## Generated Workflow SDK
@@ -250,21 +270,30 @@ Each Activity class provides methods to query and access activity instances. Lis
250
270
  const activity = wf.employeeInputActivity();
251
271
  ```
252
272
 
253
- ### getInProgressList()
273
+ ### getInProgressList(options?)
254
274
 
255
- List in-progress activity instances. Filtering and pagination are handled server-side automatically.
275
+ List in-progress activity instances. Accepts optional `ListOptionsType` payload for server-side filtering, sorting, and pagination.
256
276
 
257
277
  ```typescript
278
+ // No options — returns all in-progress items (default pagination)
258
279
  const result = await activity.getInProgressList();
259
280
 
260
281
  for (const item of result.Data) {
261
282
  console.log(item._id, item.Status, item.StartDate);
262
283
  }
284
+
285
+ // With options — server-side filter, sort, and pagination
286
+ const filtered = await activity.getInProgressList({
287
+ Filter: { Operator: 'And', Condition: [{ LHSField: 'Status', Operator: 'EQ', RHSValue: 'InProgress', RHSType: 'Constant' }] },
288
+ Sort: [{ '_created_at': 'DESC' }],
289
+ Page: 1,
290
+ PageSize: 10,
291
+ });
263
292
  ```
264
293
 
265
- ### getCompletedList()
294
+ ### getCompletedList(options?)
266
295
 
267
- List completed activity instances. Filtering and pagination are handled server-side automatically.
296
+ List completed activity instances. Same options as `getInProgressList`.
268
297
 
269
298
  ```typescript
270
299
  const result = await activity.getCompletedList();
@@ -274,20 +303,22 @@ for (const item of result.Data) {
274
303
  }
275
304
  ```
276
305
 
277
- ### inProgressMetrics()
306
+ ### inProgressMetrics(options?)
278
307
 
279
- Get aggregated metrics for in-progress activity instances.
308
+ Get count of in-progress activity instances. Returns `CountResponseType` (`{ Count: number }`).
280
309
 
281
310
  ```typescript
282
- const metrics = await activity.inProgressMetrics();
311
+ const { Count } = await activity.inProgressMetrics();
312
+ console.log('In-progress count:', Count);
283
313
  ```
284
314
 
285
- ### completedMetrics()
315
+ ### completedMetrics(options?)
286
316
 
287
- Get aggregated metrics for completed activity instances.
317
+ Get count of completed activity instances. Returns `CountResponseType` (`{ Count: number }`).
288
318
 
289
319
  ```typescript
290
- const metrics = await activity.completedMetrics();
320
+ const { Count } = await activity.completedMetrics();
321
+ console.log('Completed count:', Count);
291
322
  ```
292
323
 
293
324
  ### getInstance(instanceId)
@@ -382,6 +413,15 @@ User clicks Complete
382
413
 
383
414
  ---
384
415
 
416
+ ## useActivityTable Hook
417
+
418
+ See the dedicated [useActivityTable documentation](./useActivityTable.md) for the full API reference, type definitions, and examples.
419
+
420
+ `useActivityTable` now wraps the base `useTable` hook, providing the same search, sort, filter, and pagination capabilities as BDO tables. Entity fields are accessed via `row.ADO.FieldName`.
421
+
422
+ ---
423
+
424
+
385
425
  ## Use Case: Employee Creating Leave
386
426
 
387
427
  ### Step 1 — Start the workflow
@@ -465,22 +505,22 @@ function LeaveRequestForm({ activityInstanceId, onComplete }: LeaveRequestFormPr
465
505
 
466
506
  {/* Start Date */}
467
507
  <div>
468
- <label>{activity.StartDate.meta.label}</label>
469
- <input type="date" {...register(activity.StartDate.meta.id)} />
508
+ <label>{activity.StartDate.label}</label>
509
+ <input type="date" {...register(activity.StartDate.id)} />
470
510
  {errors.StartDate && <span>{errors.StartDate.message}</span>}
471
511
  </div>
472
512
 
473
513
  {/* End Date */}
474
514
  <div>
475
- <label>{activity.EndDate.meta.label}</label>
476
- <input type="date" {...register(activity.EndDate.meta.id)} />
515
+ <label>{activity.EndDate.label}</label>
516
+ <input type="date" {...register(activity.EndDate.id)} />
477
517
  {errors.EndDate && <span>{errors.EndDate.message}</span>}
478
518
  </div>
479
519
 
480
520
  {/* Leave Type */}
481
521
  <div>
482
- <label>{activity.LeaveType.meta.label}</label>
483
- <select {...register(activity.LeaveType.meta.id)}>
522
+ <label>{activity.LeaveType.label}</label>
523
+ <select {...register(activity.LeaveType.id)}>
484
524
  <option value="">Select type</option>
485
525
  <option value="PTO">PTO</option>
486
526
  <option value="Sick">Sick</option>
@@ -491,8 +531,8 @@ function LeaveRequestForm({ activityInstanceId, onComplete }: LeaveRequestFormPr
491
531
 
492
532
  {/* Leave Days (readonly — auto-disabled, computed by server) */}
493
533
  <div>
494
- <label>{activity.LeaveDays.meta.label}</label>
495
- <input type="number" {...register(activity.LeaveDays.meta.id)} />
534
+ <label>{activity.LeaveDays.label}</label>
535
+ <input type="number" {...register(activity.LeaveDays.id)} />
496
536
  </div>
497
537
 
498
538
  {/* Actions */}
@@ -544,16 +584,72 @@ function LeaveRequestPage() {
544
584
 
545
585
  ### Step 1 — List in-progress items
546
586
 
547
- ```typescript
548
- import { SimpleLeaveProcess } from "@/bdo/workflows/SimpleLeaveProcess";
587
+ ```tsx
588
+ import { useMemo, useState } from "react";
589
+ import { useActivityTable, ActivityTableStatus } from "@ram_28/kf-ai-sdk/workflow";
590
+ import { SimpleLeaveProcess, ManagerApprovalActivity } from "@/bdo/workflows/SimpleLeaveProcess";
549
591
 
550
592
  const wf = new SimpleLeaveProcess();
551
593
  const activity = wf.managerApprovalActivity();
552
594
 
553
- const result = await activity.getInProgressList();
595
+ const { rows, totalItems, isLoading, error, pagination, refetch } = useActivityTable(activity, {
596
+ status: ActivityTableStatus.InProgress,
597
+ initialState: {
598
+ pagination: { pageNo: 1, pageSize: 10 },
599
+ },
600
+ });
554
601
 
555
- for (const item of result.Data) {
556
- console.log(item._id, item.Status, item.AssignedTo.username);
602
+ if (isLoading) return <div>Loading...</div>;
603
+ if (error) return <div>Error: {error.message}</div>;
604
+
605
+ if (selectedId) {
606
+ return (
607
+ <ApprovalForm
608
+ activityInstanceId={selectedId}
609
+ onComplete={() => {
610
+ setSelectedId(null);
611
+ refetch();
612
+ }}
613
+ />
614
+ );
615
+ }
616
+
617
+ return (
618
+ <div>
619
+ <h2>Pending Approvals ({totalItems})</h2>
620
+ <table>
621
+ <thead>
622
+ <tr>
623
+ <th>ID</th>
624
+ <th>Status</th>
625
+ <th>Assigned To</th>
626
+ <th>Approved</th>
627
+ <th>Reason</th>
628
+ <th>Action</th>
629
+ </tr>
630
+ </thead>
631
+ <tbody>
632
+ {rows.map((row) => (
633
+ <tr key={row._id}>
634
+ <td>{row._id}</td>
635
+ <td>{row.Status}</td>
636
+ <td>{row.AssignedTo.map((u) => u._name).join(", ")}</td>
637
+ <td>{row.ADO.ManagerApproved ? "Yes" : "No"}</td>
638
+ <td>{row.ADO.ManagerReason}</td>
639
+ <td>
640
+ <button onClick={() => setSelectedId(row._id)}>Review</button>
641
+ </td>
642
+ </tr>
643
+ ))}
644
+ </tbody>
645
+ </table>
646
+ <div>
647
+ <button onClick={pagination.goToPrevious} disabled={!pagination.canGoPrevious}>Previous</button>
648
+ <span>Page {pagination.pageNo} of {pagination.totalPages}</span>
649
+ <button onClick={pagination.goToNext} disabled={!pagination.canGoNext}>Next</button>
650
+ </div>
651
+ </div>
652
+ );
557
653
  }
558
654
  ```
559
655
 
@@ -610,14 +706,14 @@ function ApprovalForm({ activityInstanceId, onComplete }: ApprovalFormProps) {
610
706
 
611
707
  <div>
612
708
  <label>
613
- <input type="checkbox" {...register(activity.ManagerApproved.meta.id)} />
614
- {activity.ManagerApproved.meta.label}
709
+ <input type="checkbox" {...register(activity.ManagerApproved.id)} />
710
+ {activity.ManagerApproved.label}
615
711
  </label>
616
712
  </div>
617
713
 
618
714
  <div>
619
- <label>{activity.ManagerReason.meta.label}</label>
620
- <textarea {...register(activity.ManagerReason.meta.id)} rows={4} />
715
+ <label>{activity.ManagerReason.label}</label>
716
+ <textarea {...register(activity.ManagerReason.id)} rows={4} />
621
717
  </div>
622
718
 
623
719
  <button type="button" onClick={handleComplete(onSuccess, onError)}>
@@ -653,7 +749,7 @@ instance.StartDate.set("2026-03-01");
653
749
  instance.EndDate.set("2026-03-05");
654
750
 
655
751
  // Field metadata
656
- console.log(instance.StartDate.meta.label); // "Start Date"
752
+ console.log(instance.StartDate.label); // "Start Date"
657
753
 
658
754
  // Persist changes
659
755
  await instance.update({ StartDate: "2026-03-01", EndDate: "2026-03-05" });
@@ -672,18 +768,31 @@ const progress = await instance.progress();
672
768
 
673
769
  ## Filtering Reference
674
770
 
675
- Status filtering is built into the method names (`getInProgressList` / `getCompletedList`). All filtering (by current user, activity status, and activity ID) and pagination are handled server-side automatically no client-side options are needed.
771
+ Status filtering is built into the method names (`getInProgressList` / `getCompletedList`). Internal filters (ActivityId, Status, AssignedTo) are **always applied** by the backend. Frontend filters passed via `ListOptionsType` are AND-merged with the internal filters.
772
+
773
+ All four list/metric endpoints now use **POST** with an optional `ListOptionsType` body (same shape as BDO list API: `{ Filter, Sort, Page, PageSize }`).
676
774
 
677
775
  ### In-progress items
678
776
 
679
777
  ```typescript
778
+ // No options — returns all (default pagination)
680
779
  const result = await activity.getInProgressList();
780
+
781
+ // With filter + pagination
782
+ const result = await activity.getInProgressList({
783
+ Sort: [{ '_created_at': 'DESC' }],
784
+ Page: 1,
785
+ PageSize: 25,
786
+ });
681
787
  ```
682
788
 
683
789
  ### Completed items
684
790
 
685
791
  ```typescript
686
- const result = await activity.getCompletedList();
792
+ const result = await activity.getCompletedList({
793
+ Page: 1,
794
+ PageSize: 25,
795
+ });
687
796
  ```
688
797
 
689
798
  ### Process progress
@@ -703,7 +812,7 @@ const progressList = await wf.progress(BPInstanceId);
703
812
  |-------|------|-------------|
704
813
  | `_id` | `StringFieldType` | Unique activity instance identifier |
705
814
  | `Status` | `SelectFieldType<"InProgress" \| "Completed">` | Current status |
706
- | `AssignedTo` | `ReferenceFieldType<UserRefType>` | Assigned user (has `._id` and `.username`) |
815
+ | `AssignedTo` | `UserFieldType[]` | Assigned users (each has `._id` and `._name`) |
707
816
  | `CompletedAt` | `DateTimeFieldType` | Completion timestamp (`"YYYY-MM-DDTHH:MM:SS"`) |
708
817
 
709
818
  ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ram_28/kf-ai-sdk",
3
- "version": "2.0.14",
3
+ "version": "2.0.15",
4
4
  "description": "Type-safe, AI-driven SDK for building modern web applications with role-based access control",
5
5
  "author": "Ramprasad",
6
6
  "license": "MIT",
@@ -35,7 +35,7 @@ export class UserField extends BaseField<UserFieldType> {
35
35
  async fetchOptions(instanceId: string): Promise<UserFieldType[]> {
36
36
  if (!this._parentBoId) {
37
37
  throw new Error(
38
- `Field ${this.id} not bound to a BDO. Cannot fetch options.`
38
+ `Field ${this.id} not bound to a BDO. Cannot fetch options.`,
39
39
  );
40
40
  }
41
41
  return api(this._parentBoId).fetchField<UserFieldType>(instanceId, this.id);