@ram_28/kf-ai-sdk 2.0.19 → 2.0.20-beta.0
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 +8 -16
- package/dist/{FileField-CZjS2uLh.js → FileField-BWrSHNRq.js} +3 -3
- package/dist/{FileField-DU4UWo_t.cjs → FileField-eDeuzln8.cjs} +1 -1
- package/dist/api.cjs +1 -1
- package/dist/api.mjs +1 -1
- package/dist/auth/authConfig.d.ts +1 -1
- package/dist/auth/types.d.ts +1 -1
- package/dist/auth/types.d.ts.map +1 -1
- package/dist/auth.cjs +1 -1
- package/dist/auth.mjs +1 -1
- package/dist/bdo/core/Item.d.ts +4 -0
- package/dist/bdo/core/Item.d.ts.map +1 -1
- package/dist/bdo/fields/ReferenceField.d.ts +1 -1
- package/dist/bdo/fields/ReferenceField.d.ts.map +1 -1
- package/dist/bdo/fields/SelectField.d.ts +1 -1
- package/dist/bdo/fields/SelectField.d.ts.map +1 -1
- package/dist/bdo/fields/UserField.d.ts +1 -1
- package/dist/bdo/fields/UserField.d.ts.map +1 -1
- package/dist/bdo.cjs +1 -1
- package/dist/bdo.mjs +62 -53
- package/dist/components/hooks/useActivityForm/types.d.ts +5 -4
- package/dist/components/hooks/useActivityForm/types.d.ts.map +1 -1
- package/dist/components/hooks/useActivityForm/useActivityForm.d.ts.map +1 -1
- package/dist/components/hooks/useActivityTable/types.d.ts +4 -5
- package/dist/components/hooks/useActivityTable/types.d.ts.map +1 -1
- package/dist/components/hooks/useActivityTable/useActivityTable.d.ts.map +1 -1
- package/dist/components/hooks/useBDOForm/createItemProxy.d.ts +3 -2
- package/dist/components/hooks/useBDOForm/createItemProxy.d.ts.map +1 -1
- package/dist/components/hooks/useBDOTable/types.d.ts +12 -20
- package/dist/components/hooks/useBDOTable/types.d.ts.map +1 -1
- package/dist/components/hooks/useBDOTable/useBDOTable.d.ts +2 -2
- package/dist/components/hooks/useBDOTable/useBDOTable.d.ts.map +1 -1
- package/dist/{constants-Cyi942Yr.js → constants-ConHc1oS.js} +5 -5
- package/dist/constants-QX2RX-wu.cjs +1 -0
- package/dist/filter.cjs +1 -1
- package/dist/filter.mjs +1 -1
- package/dist/form.cjs +1 -1
- package/dist/form.mjs +243 -226
- package/dist/table.cjs +1 -1
- package/dist/table.mjs +16 -15
- package/dist/table.types.d.ts +1 -1
- package/dist/table.types.d.ts.map +1 -1
- package/dist/types/constants.d.ts +1 -1
- package/dist/workflow/Activity.d.ts +5 -8
- package/dist/workflow/Activity.d.ts.map +1 -1
- package/dist/workflow.cjs +1 -1
- package/dist/workflow.mjs +476 -461
- package/docs/api.md +95 -0
- package/docs/bdo.md +224 -0
- package/docs/gaps.md +360 -0
- package/docs/useActivityForm.md +393 -0
- package/docs/useActivityTable.md +418 -0
- package/docs/useBDOForm.md +498 -0
- package/docs/useBDOTable.md +284 -0
- package/docs/useFilter.md +188 -0
- package/docs/workflow.md +560 -0
- package/package.json +14 -15
- package/sdk/auth/authConfig.ts +1 -1
- package/sdk/auth/types.ts +1 -1
- package/sdk/bdo/core/Item.ts +10 -1
- package/sdk/bdo/fields/ReferenceField.ts +1 -1
- package/sdk/bdo/fields/SelectField.ts +1 -1
- package/sdk/bdo/fields/UserField.ts +1 -1
- package/sdk/components/hooks/useActivityForm/types.ts +6 -4
- package/sdk/components/hooks/useActivityForm/useActivityForm.ts +73 -10
- package/sdk/components/hooks/useActivityTable/types.ts +5 -4
- package/sdk/components/hooks/useActivityTable/useActivityTable.ts +8 -10
- package/sdk/components/hooks/useBDOForm/createItemProxy.ts +58 -17
- package/sdk/components/hooks/useBDOTable/types.ts +10 -20
- package/sdk/components/hooks/useBDOTable/useBDOTable.ts +8 -12
- package/sdk/table.types.ts +0 -2
- package/sdk/types/constants.ts +1 -1
- package/sdk/workflow/Activity.ts +7 -39
- package/dist/constants-DEmYwKfC.cjs +0 -1
- package/docs/README.md +0 -57
- package/docs/bdo/README.md +0 -161
- package/docs/bdo/api_reference.md +0 -281
- package/docs/examples/bdo/create-product.md +0 -69
- package/docs/examples/bdo/edit-product-dialog.md +0 -95
- package/docs/examples/bdo/filtered-product-table.md +0 -100
- package/docs/examples/bdo/product-listing.md +0 -73
- package/docs/examples/bdo/supplier-dropdown.md +0 -60
- package/docs/examples/fields/complex-fields.md +0 -248
- package/docs/examples/fields/primitive-fields.md +0 -217
- package/docs/examples/workflow/approve-leave-request.md +0 -76
- package/docs/examples/workflow/filtered-activity-table.md +0 -101
- package/docs/examples/workflow/my-pending-requests.md +0 -90
- package/docs/examples/workflow/start-new-workflow.md +0 -47
- package/docs/examples/workflow/submit-leave-request.md +0 -72
- package/docs/examples/workflow/workflow-progress.md +0 -49
- package/docs/fields/README.md +0 -141
- package/docs/fields/api_reference.md +0 -134
- package/docs/useActivityForm/README.md +0 -244
- package/docs/useActivityForm/api_reference.md +0 -279
- package/docs/useActivityTable/README.md +0 -263
- package/docs/useActivityTable/api_reference.md +0 -294
- package/docs/useBDOForm/README.md +0 -175
- package/docs/useBDOForm/api_reference.md +0 -244
- package/docs/useBDOTable/README.md +0 -242
- package/docs/useBDOTable/api_reference.md +0 -253
- package/docs/useFilter/README.md +0 -323
- package/docs/useFilter/api_reference.md +0 -228
- package/docs/workflow/README.md +0 -158
- package/docs/workflow/api_reference.md +0 -161
- /package/docs/{useAuth/README.md → useAuth.md} +0 -0
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
# useBDOTable
|
|
2
|
+
|
|
3
|
+
Hook for BDO (Business Data Object) tables with search, sort, filter, and pagination. Pass a BDO instance and the hook handles the rest.
|
|
4
|
+
|
|
5
|
+
## Imports
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { useBDOTable } from "@ram_28/kf-ai-sdk/table";
|
|
9
|
+
import { ConditionOperator, RHSType } from "@ram_28/kf-ai-sdk/table";
|
|
10
|
+
import type { UseBDOTableOptionsType, UseBDOTableReturnType } from "@ram_28/kf-ai-sdk/table/types";
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Common Mistakes (READ FIRST)
|
|
16
|
+
|
|
17
|
+
### 1. Passing `source` instead of `bdo`
|
|
18
|
+
|
|
19
|
+
`useBDOTable` takes a `bdo` instance, NOT a `source` string.
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
// ❌ WRONG — source is not a valid property on useBDOTable
|
|
23
|
+
useBDOTable({ source: product.meta._id });
|
|
24
|
+
|
|
25
|
+
// ✅ CORRECT — pass the BDO instance
|
|
26
|
+
useBDOTable({ bdo: product });
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### 2. Passing a raw object instead of a BDO instance
|
|
30
|
+
|
|
31
|
+
The `bdo` property expects an object with a `meta` property containing `_id` and `name`. A plain object or entity type will not work.
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
// ❌ WRONG — plain object without meta
|
|
35
|
+
useBDOTable({ bdo: { _id: 'BO_Product', name: 'Product' } });
|
|
36
|
+
|
|
37
|
+
// ✅ CORRECT — a BDO class instance
|
|
38
|
+
const product = useMemo(() => new BuyerProduct(), []);
|
|
39
|
+
useBDOTable({ bdo: product });
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 3. Recreating the BDO on every render
|
|
43
|
+
|
|
44
|
+
Constructing the BDO inside the component body without `useMemo` creates a new instance on every render, which destabilizes the query key and causes infinite refetching.
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
// ❌ WRONG — new instance every render
|
|
48
|
+
function ProductsTable() {
|
|
49
|
+
const product = new BuyerProduct();
|
|
50
|
+
const table = useBDOTable({ bdo: product }); // infinite refetch loop
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// ✅ CORRECT — memoize the instance
|
|
54
|
+
function ProductsTable() {
|
|
55
|
+
const product = useMemo(() => new BuyerProduct(), []);
|
|
56
|
+
const table = useBDOTable({ bdo: product });
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### 4. Using `columns` with useBDOTable
|
|
61
|
+
|
|
62
|
+
`useBDOTable` does not accept a `columns` property. Column definitions are a UI concern handled in your rendering logic, not in the hook options.
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
// ❌ WRONG — columns is not a hook option
|
|
66
|
+
useBDOTable({
|
|
67
|
+
bdo: product,
|
|
68
|
+
columns: [{ fieldId: 'Title', label: 'Title' }],
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// ✅ CORRECT — define columns separately for rendering
|
|
72
|
+
const columns = [
|
|
73
|
+
{ fieldId: product.Title.id, label: product.Title.label },
|
|
74
|
+
{ fieldId: product.Price.id, label: product.Price.label },
|
|
75
|
+
];
|
|
76
|
+
const table = useBDOTable({ bdo: product });
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 5. Calling `.get()` on table rows
|
|
80
|
+
|
|
81
|
+
Table `rows` are plain objects, NOT `ItemType`. The `.get()` accessor is only available on items returned by `bdo.get()`, `bdo.create()`, or the `useBDOForm` item proxy.
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
// ❌ WRONG — rows are plain objects, not ItemType
|
|
85
|
+
table.rows.map((row) => row.Title.get());
|
|
86
|
+
|
|
87
|
+
// ✅ CORRECT — access properties directly
|
|
88
|
+
table.rows.map((row) => row.Title);
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### 6. Wrong initialState property names
|
|
92
|
+
|
|
93
|
+
This is not react-table. Do not use react-table naming conventions.
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
// ❌ WRONG — sorting and pageIndex are react-table names
|
|
97
|
+
useBDOTable({
|
|
98
|
+
bdo: product,
|
|
99
|
+
initialState: { sorting: [...], pagination: { pageIndex: 0, pageSize: 10 } },
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// ✅ CORRECT — use sort and pageNo (1-indexed)
|
|
103
|
+
useBDOTable({
|
|
104
|
+
bdo: product,
|
|
105
|
+
initialState: {
|
|
106
|
+
sort: [{ [product.Title.id]: 'ASC' }],
|
|
107
|
+
pagination: { pageNo: 1, pageSize: 10 },
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Complete Example
|
|
115
|
+
|
|
116
|
+
A product listing page with search, filter, sort, and pagination.
|
|
117
|
+
|
|
118
|
+
```tsx
|
|
119
|
+
import { useMemo, useState } from "react";
|
|
120
|
+
import { useBDOTable } from "@ram_28/kf-ai-sdk/table";
|
|
121
|
+
import { ConditionOperator, RHSType } from "@ram_28/kf-ai-sdk/table";
|
|
122
|
+
import type { UseBDOTableReturnType } from "@ram_28/kf-ai-sdk/table/types";
|
|
123
|
+
import { BuyerProduct } from "../bdo/buyer/Product";
|
|
124
|
+
import type { BuyerProductFieldType } from "../bdo/buyer/Product";
|
|
125
|
+
|
|
126
|
+
function ProductListPage() {
|
|
127
|
+
const productBdo = useMemo(() => new BuyerProduct(), []);
|
|
128
|
+
const [selectedCategory, setSelectedCategory] = useState("all");
|
|
129
|
+
|
|
130
|
+
const table: UseBDOTableReturnType<BuyerProductFieldType> =
|
|
131
|
+
useBDOTable<BuyerProductFieldType>({
|
|
132
|
+
bdo: productBdo,
|
|
133
|
+
initialState: {
|
|
134
|
+
sort: [{ [productBdo.Title.id]: "ASC" }],
|
|
135
|
+
pagination: { pageNo: 1, pageSize: 10 },
|
|
136
|
+
},
|
|
137
|
+
onError: (error) => {
|
|
138
|
+
console.error("Table fetch failed:", error.message);
|
|
139
|
+
},
|
|
140
|
+
onSuccess: (data) => {
|
|
141
|
+
console.log("Loaded", data.length, "rows");
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
const handleCategoryChange = (category: string) => {
|
|
146
|
+
setSelectedCategory(category);
|
|
147
|
+
table.filter.clearAllConditions();
|
|
148
|
+
if (category !== "all") {
|
|
149
|
+
table.filter.addCondition({
|
|
150
|
+
LHSField: productBdo.Category.id,
|
|
151
|
+
Operator: ConditionOperator.EQ,
|
|
152
|
+
RHSValue: category,
|
|
153
|
+
RHSType: RHSType.Constant,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
if (table.isLoading) return <div>Loading...</div>;
|
|
159
|
+
if (table.error) {
|
|
160
|
+
return (
|
|
161
|
+
<div>
|
|
162
|
+
<p>Error: {table.error.message}</p>
|
|
163
|
+
<button onClick={() => table.refetch()}>Retry</button>
|
|
164
|
+
</div>
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return (
|
|
169
|
+
<div>
|
|
170
|
+
{/* Search */}
|
|
171
|
+
<input
|
|
172
|
+
type="text"
|
|
173
|
+
placeholder="Search products..."
|
|
174
|
+
value={table.search.query}
|
|
175
|
+
onChange={(e) => table.search.set(productBdo.Title.id, e.target.value)}
|
|
176
|
+
/>
|
|
177
|
+
{table.search.query && (
|
|
178
|
+
<button onClick={table.search.clear}>Clear Search</button>
|
|
179
|
+
)}
|
|
180
|
+
|
|
181
|
+
{/* Category Filter */}
|
|
182
|
+
<select
|
|
183
|
+
value={selectedCategory}
|
|
184
|
+
onChange={(e) => handleCategoryChange(e.target.value)}
|
|
185
|
+
>
|
|
186
|
+
<option value="all">All Categories</option>
|
|
187
|
+
<option value="Electronics">Electronics</option>
|
|
188
|
+
<option value="Books">Books</option>
|
|
189
|
+
</select>
|
|
190
|
+
|
|
191
|
+
{/* Sort */}
|
|
192
|
+
<select
|
|
193
|
+
onChange={(e) => {
|
|
194
|
+
const [field, dir] = e.target.value.split(":");
|
|
195
|
+
table.sort.set(field, dir as "ASC" | "DESC");
|
|
196
|
+
}}
|
|
197
|
+
>
|
|
198
|
+
<option value={`${productBdo.Title.id}:ASC`}>Name A-Z</option>
|
|
199
|
+
<option value={`${productBdo.Price.id}:ASC`}>Price: Low to High</option>
|
|
200
|
+
<option value={`${productBdo.Price.id}:DESC`}>Price: High to Low</option>
|
|
201
|
+
</select>
|
|
202
|
+
|
|
203
|
+
{/* Results */}
|
|
204
|
+
<p>{table.totalItems} results</p>
|
|
205
|
+
<div>
|
|
206
|
+
{table.rows.map((row) => (
|
|
207
|
+
<div key={row._id}>
|
|
208
|
+
<h3>{row.Title}</h3>
|
|
209
|
+
<p>${row.Price}</p>
|
|
210
|
+
<p>{row.Category}</p>
|
|
211
|
+
</div>
|
|
212
|
+
))}
|
|
213
|
+
</div>
|
|
214
|
+
|
|
215
|
+
{/* Pagination */}
|
|
216
|
+
<div>
|
|
217
|
+
<button
|
|
218
|
+
onClick={table.pagination.goToPrevious}
|
|
219
|
+
disabled={!table.pagination.canGoPrevious}
|
|
220
|
+
>
|
|
221
|
+
Previous
|
|
222
|
+
</button>
|
|
223
|
+
<span>
|
|
224
|
+
Page {table.pagination.pageNo} of {table.pagination.totalPages}
|
|
225
|
+
</span>
|
|
226
|
+
<button
|
|
227
|
+
onClick={table.pagination.goToNext}
|
|
228
|
+
disabled={!table.pagination.canGoNext}
|
|
229
|
+
>
|
|
230
|
+
Next
|
|
231
|
+
</button>
|
|
232
|
+
</div>
|
|
233
|
+
</div>
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## Type Definitions
|
|
241
|
+
|
|
242
|
+
### UseBDOTableOptionsType
|
|
243
|
+
|
|
244
|
+
```typescript
|
|
245
|
+
export interface UseBDOTableOptionsType<T> {
|
|
246
|
+
/** BDO instance — only meta._id is used (for API routing) */
|
|
247
|
+
bdo: {
|
|
248
|
+
meta: { readonly _id: string; readonly name: string };
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
/** Initial state */
|
|
252
|
+
initialState?: {
|
|
253
|
+
sort?: SortType;
|
|
254
|
+
pagination?: PaginationStateType;
|
|
255
|
+
filter?: UseFilterOptionsType<T>;
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
/** Error callback */
|
|
259
|
+
onError?: (error: Error) => void;
|
|
260
|
+
|
|
261
|
+
/** Success callback — receives rows from current page */
|
|
262
|
+
onSuccess?: (data: T[]) => void;
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### UseBDOTableReturnType
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
export type UseBDOTableReturnType<T> = UseTableReturnType<T>;
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
The return type is identical to `UseTableReturnType<T>`. All properties — `rows`, `totalItems`, `isLoading`, `isFetching`, `error`, `search`, `sort`, `filter`, `pagination`, and `refetch` — behave the same.
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## Search, Sort, Filter, and Pagination
|
|
277
|
+
|
|
278
|
+
`useBDOTable` supports `initialState`, `onError`, and `onSuccess` options.
|
|
279
|
+
|
|
280
|
+
- **Search** — `table.search.set(field, query)`, `table.search.clear()`, 300ms debounce
|
|
281
|
+
- **Sort** — `table.sort.toggle(field)`, `table.sort.set(field, direction)`, `table.sort.clear()`
|
|
282
|
+
- **Filter** — `table.filter.addCondition(...)`, `table.filter.removeCondition(...)`, `table.filter.clearAllConditions()`
|
|
283
|
+
- **Pagination** — `table.pagination.goToNext()`, `table.pagination.goToPrevious()`, `table.pagination.goToPage(n)`, `table.pagination.setPageSize(n)`
|
|
284
|
+
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# Filter SDK API
|
|
2
|
+
|
|
3
|
+
React hook for building filter conditions for tables, forms, and API calls.
|
|
4
|
+
|
|
5
|
+
## Imports
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { useFilter, isCondition, isConditionGroup, ConditionOperator, GroupOperator, FilterValueSource } from "@ram_28/kf-ai-sdk/filter";
|
|
9
|
+
import type { UseFilterOptionsType, UseFilterReturnType, ConditionType, ConditionGroupType, FilterType } from "@ram_28/kf-ai-sdk/filter/types";
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Common Mistakes (READ FIRST)
|
|
15
|
+
|
|
16
|
+
### 1. Importing `RHSType` instead of `FilterValueSource`
|
|
17
|
+
|
|
18
|
+
There is NO named export `RHSType`. Import `FilterValueSource`. The JSON key IS called `RHSType`, but the value comes from `FilterValueSource`.
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
// ❌ WRONG — RHSType is not an importable enum
|
|
22
|
+
import { RHSType } from "@ram_28/kf-ai-sdk/filter";
|
|
23
|
+
|
|
24
|
+
// ✅ CORRECT
|
|
25
|
+
import { FilterValueSource } from "@ram_28/kf-ai-sdk/filter";
|
|
26
|
+
{ RHSType: FilterValueSource.Constant }
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### 2. Wrong field name casing in ConditionType
|
|
30
|
+
|
|
31
|
+
`ConditionType` uses **PascalCase**: `Operator`, `LHSField`, `RHSValue`, `RHSType`. NOT camelCase.
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
// ❌ WRONG — camelCase
|
|
35
|
+
{ operator: "EQ", lhsField: "status", rhsValue: "Active" }
|
|
36
|
+
|
|
37
|
+
// ✅ CORRECT — PascalCase
|
|
38
|
+
{ Operator: ConditionOperator.EQ, LHSField: bdo.status.id, RHSValue: "Active", RHSType: FilterValueSource.Constant }
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### 3. Mixing hook init format with API format
|
|
42
|
+
|
|
43
|
+
Hook init (`UseFilterOptionsType`) uses lowercase `conditions`/`operator`. API format (`FilterType`/`ConditionType`) uses uppercase `Condition`/`Operator`.
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
// Hook initialization — lowercase
|
|
47
|
+
useTable({ initialState: { filter: { conditions: [...], operator: "And" } } });
|
|
48
|
+
|
|
49
|
+
// API calls — uppercase
|
|
50
|
+
bdo.list({ Filter: { Operator: "And", Condition: [...] } });
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 4. Hardcoded operator strings
|
|
54
|
+
|
|
55
|
+
ALWAYS use `ConditionOperator` constants. NEVER write `"Equals"`, `"equals"`, or `"eq"`.
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
// ❌ WRONG
|
|
59
|
+
{ Operator: "Equals" } { Operator: "equals" } { Operator: "eq" }
|
|
60
|
+
|
|
61
|
+
// ✅ CORRECT
|
|
62
|
+
{ Operator: ConditionOperator.EQ } // "EQ"
|
|
63
|
+
{ Operator: ConditionOperator.Contains } // "Contains"
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 5. Accessing `filter.conditions` instead of `filter.items`
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
// ❌ WRONG — conditions does NOT exist
|
|
70
|
+
filter.conditions.length
|
|
71
|
+
|
|
72
|
+
// ✅ CORRECT
|
|
73
|
+
filter.items.length
|
|
74
|
+
filter.hasConditions // boolean shortcut
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 6. Using `as const` on Operator values
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
// ❌ WRONG — causes narrowing errors in arrays
|
|
81
|
+
[{ Operator: ConditionOperator.EQ as const, ... }]
|
|
82
|
+
|
|
83
|
+
// ✅ CORRECT — type the array
|
|
84
|
+
const conditions: Omit<ConditionType, "id">[] = [{ Operator: ConditionOperator.EQ, ... }];
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Constants
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
// Condition operators
|
|
93
|
+
ConditionOperator.EQ ConditionOperator.NE // Equal, Not Equal
|
|
94
|
+
ConditionOperator.GT ConditionOperator.GTE // Greater Than (or Equal)
|
|
95
|
+
ConditionOperator.LT ConditionOperator.LTE // Less Than (or Equal)
|
|
96
|
+
ConditionOperator.Contains ConditionOperator.NotContains // String contains
|
|
97
|
+
ConditionOperator.IN ConditionOperator.NIN // Value in/not-in list
|
|
98
|
+
ConditionOperator.Empty ConditionOperator.NotEmpty // Null/empty check
|
|
99
|
+
ConditionOperator.Between ConditionOperator.NotBetween // Range
|
|
100
|
+
|
|
101
|
+
// Group operators
|
|
102
|
+
GroupOperator.And GroupOperator.Or GroupOperator.Not
|
|
103
|
+
|
|
104
|
+
// RHS value source (KEY is "RHSType", VALUE from FilterValueSource)
|
|
105
|
+
FilterValueSource.Constant // "Constant" — literal value
|
|
106
|
+
FilterValueSource.BDOField // "BDOField" — compare against another field
|
|
107
|
+
FilterValueSource.AppVariable // "AppVariable" — app variable
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Type Definitions
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
interface ConditionType<T = any> {
|
|
116
|
+
id?: string; // Auto-generated
|
|
117
|
+
Operator: ConditionOperatorType; // PascalCase
|
|
118
|
+
LHSField: keyof T | string;
|
|
119
|
+
RHSValue: any;
|
|
120
|
+
RHSType?: "Constant" | "BDOField" | "AppVariable";
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
interface ConditionGroupType<T = any> {
|
|
124
|
+
id?: string;
|
|
125
|
+
Operator: "And" | "Or" | "Not";
|
|
126
|
+
Condition: Array<ConditionType<T> | ConditionGroupType<T>>;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
interface UseFilterOptionsType<T = any> { // lowercase — hook init
|
|
130
|
+
conditions?: Array<ConditionType<T> | ConditionGroupType<T>>;
|
|
131
|
+
operator?: "And" | "Or" | "Not";
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
interface UseFilterReturnType<T = any> {
|
|
135
|
+
operator: "And" | "Or" | "Not";
|
|
136
|
+
items: Array<ConditionType<T> | ConditionGroupType<T>>;
|
|
137
|
+
payload: FilterType<T> | undefined; // API-ready, undefined if empty
|
|
138
|
+
hasConditions: boolean;
|
|
139
|
+
addCondition: (condition: Omit<ConditionType<T>, "id">, parentId?: string) => string;
|
|
140
|
+
addConditionGroup: (operator: "And" | "Or" | "Not", parentId?: string) => string;
|
|
141
|
+
updateCondition: (id: string, updates: Partial<Omit<ConditionType<T>, "id">>) => void;
|
|
142
|
+
removeCondition: (id: string) => void;
|
|
143
|
+
clearAllConditions: () => void;
|
|
144
|
+
setRootOperator: (op: "And" | "Or" | "Not") => void;
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Usage Example
|
|
151
|
+
|
|
152
|
+
```tsx
|
|
153
|
+
import { useFilter, ConditionOperator, GroupOperator, FilterValueSource } from "@ram_28/kf-ai-sdk/filter";
|
|
154
|
+
import type { UseFilterOptionsType } from "@ram_28/kf-ai-sdk/filter/types";
|
|
155
|
+
|
|
156
|
+
// Standalone filter
|
|
157
|
+
const filter = useFilter<AdminProductFieldType>();
|
|
158
|
+
filter.addCondition({ Operator: ConditionOperator.EQ, LHSField: bdo.status.id, RHSValue: "Active", RHSType: FilterValueSource.Constant });
|
|
159
|
+
filter.addCondition({ Operator: ConditionOperator.GT, LHSField: bdo.unit_price.id, RHSValue: 100, RHSType: FilterValueSource.Constant });
|
|
160
|
+
|
|
161
|
+
// With useTable initialState
|
|
162
|
+
const table = useTable<AdminProductFieldType>({
|
|
163
|
+
source: bdo.meta._id,
|
|
164
|
+
columns,
|
|
165
|
+
initialState: {
|
|
166
|
+
filter: {
|
|
167
|
+
conditions: [
|
|
168
|
+
{ Operator: ConditionOperator.EQ, LHSField: "_created_by", RHSValue: user._id, RHSType: FilterValueSource.Constant },
|
|
169
|
+
],
|
|
170
|
+
operator: GroupOperator.And,
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
// Dynamic filter with useEffect
|
|
176
|
+
useEffect(() => {
|
|
177
|
+
table.filter.clearAllConditions();
|
|
178
|
+
if (status !== "all") {
|
|
179
|
+
table.filter.addCondition({ Operator: ConditionOperator.EQ, LHSField: bdo.status.id, RHSValue: status, RHSType: FilterValueSource.Constant });
|
|
180
|
+
}
|
|
181
|
+
}, [status]);
|
|
182
|
+
|
|
183
|
+
// Nested: Category = "Electronics" AND (Price < 100 OR OnSale = true)
|
|
184
|
+
filter.addCondition({ Operator: ConditionOperator.EQ, LHSField: bdo.category.id, RHSValue: "Electronics", RHSType: FilterValueSource.Constant });
|
|
185
|
+
const orGroupId = filter.addConditionGroup(GroupOperator.Or);
|
|
186
|
+
filter.addCondition({ Operator: ConditionOperator.LT, LHSField: bdo.price.id, RHSValue: 100, RHSType: FilterValueSource.Constant }, orGroupId);
|
|
187
|
+
filter.addCondition({ Operator: ConditionOperator.EQ, LHSField: bdo.on_sale.id, RHSValue: true, RHSType: FilterValueSource.Constant }, orGroupId);
|
|
188
|
+
```
|