@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.
- package/README.md +2 -1
- package/dist/FileField-BWrSHNRq.js +296 -0
- package/dist/FileField-eDeuzln8.cjs +1 -0
- package/dist/api.cjs +1 -1
- package/dist/api.mjs +2 -2
- package/dist/auth.cjs +1 -1
- package/dist/auth.mjs +1 -1
- package/dist/bdo.cjs +1 -1
- package/dist/bdo.mjs +228 -472
- package/dist/{client-DnO2KKrw.cjs → client-D5k4SYuw.cjs} +1 -1
- package/dist/{client-iQTqFDNI.js → client-_ayziI1d.js} +33 -32
- package/dist/components/hooks/index.d.ts +9 -3
- package/dist/components/hooks/index.d.ts.map +1 -1
- package/dist/{workflow/components → components/hooks}/useActivityForm/createActivityItemProxy.d.ts +9 -5
- package/dist/components/hooks/useActivityForm/createActivityItemProxy.d.ts.map +1 -0
- package/dist/components/hooks/useActivityForm/createActivityResolver.d.ts +23 -0
- package/dist/components/hooks/useActivityForm/createActivityResolver.d.ts.map +1 -0
- package/dist/components/hooks/useActivityForm/index.d.ts.map +1 -0
- package/dist/{workflow/components → components/hooks}/useActivityForm/types.d.ts +11 -7
- package/dist/components/hooks/useActivityForm/types.d.ts.map +1 -0
- package/dist/{workflow/components → components/hooks}/useActivityForm/useActivityForm.d.ts +2 -2
- package/dist/components/hooks/useActivityForm/useActivityForm.d.ts.map +1 -0
- package/dist/components/hooks/useActivityTable/index.d.ts +4 -0
- package/dist/components/hooks/useActivityTable/index.d.ts.map +1 -0
- package/dist/components/hooks/useActivityTable/types.d.ts +36 -0
- package/dist/components/hooks/useActivityTable/types.d.ts.map +1 -0
- package/dist/components/hooks/useActivityTable/useActivityTable.d.ts +4 -0
- package/dist/components/hooks/useActivityTable/useActivityTable.d.ts.map +1 -0
- package/dist/components/hooks/useBDOTable/index.d.ts +3 -0
- package/dist/components/hooks/useBDOTable/index.d.ts.map +1 -0
- package/dist/components/hooks/useBDOTable/types.d.ts +26 -0
- package/dist/components/hooks/useBDOTable/types.d.ts.map +1 -0
- package/dist/components/hooks/useBDOTable/useBDOTable.d.ts +3 -0
- package/dist/components/hooks/useBDOTable/useBDOTable.d.ts.map +1 -0
- package/dist/components/hooks/useTable/index.d.ts +2 -2
- package/dist/components/hooks/useTable/index.d.ts.map +1 -1
- package/dist/components/hooks/useTable/types.d.ts +11 -10
- package/dist/components/hooks/useTable/types.d.ts.map +1 -1
- package/dist/components/hooks/useTable/useTable.d.ts +1 -1
- package/dist/components/hooks/useTable/useTable.d.ts.map +1 -1
- package/dist/createResolver-AIgUwoS6.cjs +1 -0
- package/dist/createResolver-ZHXQ7QMa.js +1078 -0
- package/dist/form.cjs +1 -1
- package/dist/form.mjs +252 -314
- package/dist/{metadata-DpfI3zRN.js → metadata-Cc1mBcLS.js} +1 -1
- package/dist/{metadata-DgLSJkF5.cjs → metadata-DWXQPDav.cjs} +1 -1
- package/dist/table.cjs +1 -1
- package/dist/table.d.ts +1 -0
- package/dist/table.d.ts.map +1 -1
- package/dist/table.mjs +16 -192
- package/dist/table.types.d.ts +2 -1
- package/dist/table.types.d.ts.map +1 -1
- package/dist/types/base-fields.d.ts +4 -4
- package/dist/types/base-fields.d.ts.map +1 -1
- package/dist/useTable-CeRklbdT.cjs +1 -0
- package/dist/useTable-DS0-WInw.js +203 -0
- package/dist/workflow/Activity.d.ts +9 -9
- package/dist/workflow/Activity.d.ts.map +1 -1
- package/dist/workflow/client.d.ts.map +1 -1
- package/dist/workflow/createFieldFromMeta.d.ts +29 -0
- package/dist/workflow/createFieldFromMeta.d.ts.map +1 -0
- package/dist/workflow/index.d.ts +1 -2
- package/dist/workflow/index.d.ts.map +1 -1
- package/dist/workflow/types.d.ts +12 -12
- package/dist/workflow/types.d.ts.map +1 -1
- package/dist/workflow.cjs +1 -1
- package/dist/workflow.d.ts +5 -2
- package/dist/workflow.d.ts.map +1 -1
- package/dist/workflow.mjs +716 -338
- package/dist/workflow.types.d.ts +1 -0
- package/dist/workflow.types.d.ts.map +1 -1
- package/docs/gaps.md +410 -0
- package/docs/useActivityTable.md +481 -0
- package/docs/useBDOTable.md +317 -0
- package/docs/workflow.md +143 -34
- package/package.json +1 -1
- package/sdk/bdo/fields/UserField.ts +1 -1
- package/sdk/components/hooks/index.ts +28 -5
- package/sdk/components/hooks/useActivityForm/createActivityItemProxy.ts +400 -0
- package/sdk/components/hooks/useActivityForm/createActivityResolver.ts +87 -0
- package/sdk/{workflow/components → components/hooks}/useActivityForm/types.ts +21 -8
- package/sdk/components/hooks/useActivityForm/useActivityForm.ts +628 -0
- package/sdk/components/hooks/useActivityTable/index.ts +8 -0
- package/sdk/components/hooks/useActivityTable/types.ts +45 -0
- package/sdk/components/hooks/useActivityTable/useActivityTable.ts +71 -0
- package/sdk/components/hooks/useBDOTable/index.ts +2 -0
- package/sdk/components/hooks/useBDOTable/types.ts +24 -0
- package/sdk/components/hooks/useBDOTable/useBDOTable.ts +15 -0
- package/sdk/components/hooks/useTable/index.ts +3 -3
- package/sdk/components/hooks/useTable/types.ts +16 -12
- package/sdk/components/hooks/useTable/useTable.ts +56 -49
- package/sdk/table.ts +4 -1
- package/sdk/table.types.ts +7 -4
- package/sdk/types/base-fields.ts +4 -4
- package/sdk/workflow/Activity.ts +14 -13
- package/sdk/workflow/client.ts +21 -8
- package/sdk/workflow/createFieldFromMeta.ts +110 -0
- package/sdk/workflow/index.ts +1 -6
- package/sdk/workflow/types.ts +13 -12
- package/sdk/workflow.ts +11 -2
- package/sdk/workflow.types.ts +7 -0
- package/dist/BaseField-B6da88U7.js +0 -40
- package/dist/BaseField-Drp0-OxL.cjs +0 -1
- package/dist/error-handling-CAoD0Kwb.cjs +0 -1
- package/dist/error-handling-CrhTtD88.js +0 -14
- package/dist/index.esm-Cj63v5ny.js +0 -1014
- package/dist/index.esm-DuwT11sx.cjs +0 -1
- package/dist/workflow/components/useActivityForm/createActivityItemProxy.d.ts.map +0 -1
- package/dist/workflow/components/useActivityForm/createActivityResolver.d.ts +0 -22
- package/dist/workflow/components/useActivityForm/createActivityResolver.d.ts.map +0 -1
- package/dist/workflow/components/useActivityForm/index.d.ts.map +0 -1
- package/dist/workflow/components/useActivityForm/types.d.ts.map +0 -1
- package/dist/workflow/components/useActivityForm/useActivityForm.d.ts.map +0 -1
- package/docs/useTable.md +0 -369
- package/sdk/workflow/components/useActivityForm/createActivityItemProxy.ts +0 -130
- package/sdk/workflow/components/useActivityForm/createActivityResolver.ts +0 -61
- package/sdk/workflow/components/useActivityForm/useActivityForm.ts +0 -386
- /package/dist/{workflow/components → components/hooks}/useActivityForm/index.d.ts +0 -0
- /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
|
|
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
|
|
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:
|
|
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.
|
|
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.
|
|
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
|
|
308
|
+
Get count of in-progress activity instances. Returns `CountResponseType` (`{ Count: number }`).
|
|
280
309
|
|
|
281
310
|
```typescript
|
|
282
|
-
const
|
|
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
|
|
317
|
+
Get count of completed activity instances. Returns `CountResponseType` (`{ Count: number }`).
|
|
288
318
|
|
|
289
319
|
```typescript
|
|
290
|
-
const
|
|
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.
|
|
469
|
-
<input type="date" {...register(activity.StartDate.
|
|
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.
|
|
476
|
-
<input type="date" {...register(activity.EndDate.
|
|
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.
|
|
483
|
-
<select {...register(activity.LeaveType.
|
|
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.
|
|
495
|
-
<input type="number" {...register(activity.LeaveDays.
|
|
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
|
-
```
|
|
548
|
-
import {
|
|
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
|
|
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
|
-
|
|
556
|
-
|
|
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.
|
|
614
|
-
{activity.ManagerApproved.
|
|
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.
|
|
620
|
-
<textarea {...register(activity.ManagerReason.
|
|
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.
|
|
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`).
|
|
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` | `
|
|
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
|
@@ -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);
|