@ram_28/kf-ai-sdk 1.0.14 → 1.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/dist/components/hooks/useFilter/types.d.ts +25 -22
- package/dist/components/hooks/useFilter/types.d.ts.map +1 -1
- package/dist/components/hooks/useFilter/useFilter.d.ts.map +1 -1
- package/dist/filter.cjs +1 -1
- package/dist/filter.mjs +1 -1
- package/dist/kanban.cjs +1 -1
- package/dist/kanban.mjs +1 -1
- package/dist/table.cjs +1 -1
- package/dist/table.mjs +1 -1
- package/dist/useFilter-Dofowpr_.cjs +1 -0
- package/dist/useFilter-Dv-mr9QW.js +117 -0
- package/package.json +1 -1
- package/sdk/components/hooks/useFilter/types.ts +28 -24
- package/sdk/components/hooks/useFilter/useFilter.llm.txt +199 -331
- package/sdk/components/hooks/useFilter/useFilter.ts +28 -40
- package/dist/useFilter-CXFqEHyI.js +0 -129
- package/dist/useFilter-D-bCDo6Z.cjs +0 -1
|
@@ -5,16 +5,21 @@
|
|
|
5
5
|
The `useFilter` hook is a React hook for managing filter conditions with:
|
|
6
6
|
- Type-safe filter condition management
|
|
7
7
|
- Support for simple conditions and nested logical groups
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
- State import/export
|
|
11
|
-
- Integrated with useTable hook
|
|
8
|
+
- API payload generation (id fields stripped automatically)
|
|
9
|
+
- Integrated with useTable and useKanban hooks
|
|
12
10
|
|
|
13
11
|
## Import
|
|
14
12
|
|
|
15
13
|
```typescript
|
|
16
|
-
import { useFilter } from "kf-ai-sdk";
|
|
17
|
-
|
|
14
|
+
import { useFilter, isCondition, isConditionGroup } from "@ram_28/kf-ai-sdk/filter";
|
|
15
|
+
import type {
|
|
16
|
+
UseFilterOptionsType,
|
|
17
|
+
UseFilterReturnType,
|
|
18
|
+
ConditionType,
|
|
19
|
+
ConditionGroupType,
|
|
20
|
+
ConditionGroupOperatorType,
|
|
21
|
+
FilterType,
|
|
22
|
+
} from "@ram_28/kf-ai-sdk/filter/types";
|
|
18
23
|
```
|
|
19
24
|
|
|
20
25
|
## Basic Usage
|
|
@@ -22,28 +27,27 @@ import { useFilter } from "kf-ai-sdk";
|
|
|
22
27
|
### Standalone Usage
|
|
23
28
|
|
|
24
29
|
```typescript
|
|
25
|
-
const filter = useFilter
|
|
26
|
-
|
|
27
|
-
fieldDefinitions: {
|
|
28
|
-
Price: {
|
|
29
|
-
type: "number",
|
|
30
|
-
allowedOperators: ["EQ", "GT", "LT", "GTE", "LTE", "Between"],
|
|
31
|
-
},
|
|
32
|
-
Category: {
|
|
33
|
-
type: "string",
|
|
34
|
-
allowedOperators: ["EQ", "NE", "Contains"],
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
onValidationError: (errors) => console.log(errors),
|
|
30
|
+
const filter = useFilter({
|
|
31
|
+
initialOperator: "And",
|
|
38
32
|
});
|
|
39
33
|
|
|
40
|
-
// Add a condition
|
|
34
|
+
// Add a condition at root level
|
|
41
35
|
const id = filter.addCondition({
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
36
|
+
Operator: "GT",
|
|
37
|
+
LHSField: "Price",
|
|
38
|
+
RHSValue: 100,
|
|
39
|
+
RHSType: "Constant",
|
|
46
40
|
});
|
|
41
|
+
|
|
42
|
+
// Add a nested group
|
|
43
|
+
const groupId = filter.addConditionGroup("Or");
|
|
44
|
+
|
|
45
|
+
// Add conditions to the group
|
|
46
|
+
filter.addCondition({
|
|
47
|
+
Operator: "EQ",
|
|
48
|
+
LHSField: "Category",
|
|
49
|
+
RHSValue: "Electronics",
|
|
50
|
+
}, groupId);
|
|
47
51
|
```
|
|
48
52
|
|
|
49
53
|
### Through useTable
|
|
@@ -57,125 +61,102 @@ const table = useTable<ProductType>({
|
|
|
57
61
|
|
|
58
62
|
// Use table.filter for all filter operations
|
|
59
63
|
table.filter.addCondition({
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
+
Operator: "EQ",
|
|
65
|
+
LHSField: "Category",
|
|
66
|
+
RHSValue: "Electronics",
|
|
67
|
+
RHSType: "Constant",
|
|
64
68
|
});
|
|
69
|
+
|
|
70
|
+
// Clear all filters
|
|
71
|
+
table.filter.clearAllConditions();
|
|
65
72
|
```
|
|
66
73
|
|
|
67
74
|
## Configuration Options
|
|
68
75
|
|
|
69
|
-
###
|
|
76
|
+
### UseFilterOptionsType
|
|
70
77
|
|
|
71
78
|
| Property | Type | Required | Default | Description |
|
|
72
79
|
|----------|------|----------|---------|-------------|
|
|
73
|
-
| `initialConditions` | `
|
|
74
|
-
| `
|
|
75
|
-
| `fieldDefinitions` | `Record<keyof T, FieldDefinition>` | No | - | Field definitions for validation |
|
|
76
|
-
| `validateOnChange` | `boolean` | No | `true` | Validate conditions on change |
|
|
77
|
-
| `onConditionAdd` | `(condition) => void` | No | - | Callback when condition added |
|
|
78
|
-
| `onConditionUpdate` | `(condition) => void` | No | - | Callback when condition updated |
|
|
79
|
-
| `onConditionRemove` | `(conditionId) => void` | No | - | Callback when condition removed |
|
|
80
|
-
| `onValidationError` | `(errors) => void` | No | - | Callback for validation errors |
|
|
81
|
-
|
|
82
|
-
### FieldDefinition
|
|
83
|
-
|
|
84
|
-
| Property | Type | Description |
|
|
85
|
-
|----------|------|-------------|
|
|
86
|
-
| `type` | `'string' \| 'number' \| 'date' \| 'boolean' \| 'currency' \| 'select'` | Field data type |
|
|
87
|
-
| `allowedOperators` | `FilterOperator[]` | Operators allowed for this field |
|
|
88
|
-
| `validateValue` | `(value, operator) => ValidationResult` | Custom validation function |
|
|
89
|
-
| `transformValue` | `(value) => any` | Value transformation function |
|
|
90
|
-
| `selectOptions` | `Array<{label, value}>` | Options for select fields |
|
|
80
|
+
| `initialConditions` | `Array<ConditionType \| ConditionGroupType>` | No | `[]` | Initial filter conditions |
|
|
81
|
+
| `initialOperator` | `ConditionGroupOperatorType` | No | `"And"` | Initial root operator |
|
|
91
82
|
|
|
92
83
|
## Return Value
|
|
93
84
|
|
|
94
|
-
###
|
|
85
|
+
### UseFilterReturnType
|
|
95
86
|
|
|
96
|
-
####
|
|
87
|
+
#### State (read-only)
|
|
97
88
|
| Property | Type | Description |
|
|
98
89
|
|----------|------|-------------|
|
|
99
|
-
| `
|
|
100
|
-
| `
|
|
101
|
-
| `
|
|
102
|
-
| `
|
|
103
|
-
| `validationErrors` | `ValidationError[]` | Current validation errors |
|
|
90
|
+
| `operator` | `ConditionGroupOperatorType` | Current root operator ("And" \| "Or" \| "Not") |
|
|
91
|
+
| `items` | `Array<ConditionType \| ConditionGroupType>` | Current filter items (with id populated) |
|
|
92
|
+
| `payload` | `FilterType \| undefined` | Ready-to-use API payload (id stripped, undefined if no conditions) |
|
|
93
|
+
| `hasConditions` | `boolean` | Whether any conditions exist |
|
|
104
94
|
|
|
105
|
-
####
|
|
106
|
-
|
|
|
107
|
-
|
|
108
|
-
| `addCondition` | `(condition) => string` | Add condition,
|
|
109
|
-
| `
|
|
110
|
-
| `removeCondition` | `(id) => boolean` | Remove condition |
|
|
111
|
-
| `clearConditions` | `() => void` | Clear all conditions |
|
|
112
|
-
| `getCondition` | `(id) => FilterConditionWithId` | Get specific condition |
|
|
95
|
+
#### Add Operations
|
|
96
|
+
| Method | Type | Description |
|
|
97
|
+
|--------|------|-------------|
|
|
98
|
+
| `addCondition` | `(condition: Omit<ConditionType, "id">, parentId?: string) => string` | Add a leaf condition. If parentId omitted, adds at root level. Returns the id of the created condition. |
|
|
99
|
+
| `addConditionGroup` | `(operator: ConditionGroupOperatorType, parentId?: string) => string` | Add a condition group. If parentId omitted, adds at root level. Returns the id of the created group. |
|
|
113
100
|
|
|
114
|
-
####
|
|
115
|
-
|
|
|
116
|
-
|
|
117
|
-
| `
|
|
101
|
+
#### Update Operations
|
|
102
|
+
| Method | Type | Description |
|
|
103
|
+
|--------|------|-------------|
|
|
104
|
+
| `updateCondition` | `(id: string, updates: Partial<Omit<ConditionType, "id">>) => void` | Update a leaf condition by id |
|
|
105
|
+
| `updateGroupOperator` | `(id: string, operator: ConditionGroupOperatorType) => void` | Update a condition group's operator by id |
|
|
118
106
|
|
|
119
|
-
####
|
|
120
|
-
|
|
|
121
|
-
|
|
122
|
-
| `
|
|
123
|
-
| `
|
|
107
|
+
#### Remove & Access
|
|
108
|
+
| Method | Type | Description |
|
|
109
|
+
|--------|------|-------------|
|
|
110
|
+
| `removeCondition` | `(id: string) => void` | Remove a condition or group by id |
|
|
111
|
+
| `getCondition` | `(id: string) => ConditionType \| ConditionGroupType \| undefined` | Get a condition or group by id |
|
|
124
112
|
|
|
125
|
-
####
|
|
126
|
-
|
|
|
127
|
-
|
|
128
|
-
| `
|
|
129
|
-
| `
|
|
113
|
+
#### Utility
|
|
114
|
+
| Method | Type | Description |
|
|
115
|
+
|--------|------|-------------|
|
|
116
|
+
| `clearAllConditions` | `() => void` | Clear all conditions |
|
|
117
|
+
| `setRootOperator` | `(op: ConditionGroupOperatorType) => void` | Set the root operator for combining conditions |
|
|
130
118
|
|
|
131
|
-
|
|
132
|
-
| Property | Type | Description |
|
|
133
|
-
|----------|------|-------------|
|
|
134
|
-
| `exportState` | `() => FilterState` | Export current state |
|
|
135
|
-
| `importState` | `(state) => void` | Import state |
|
|
136
|
-
| `resetToInitial` | `() => void` | Reset to initial state |
|
|
119
|
+
## Types
|
|
137
120
|
|
|
138
|
-
|
|
139
|
-
| Property | Type | Description |
|
|
140
|
-
|----------|------|-------------|
|
|
141
|
-
| `getConditionCount` | `() => number` | Get number of conditions |
|
|
142
|
-
| `hasConditions` | `boolean` | Whether any conditions exist |
|
|
143
|
-
| `canAddCondition` | `boolean` | Whether more can be added (always true) |
|
|
121
|
+
### ConditionType (Leaf Condition)
|
|
144
122
|
|
|
145
|
-
|
|
123
|
+
```typescript
|
|
124
|
+
interface ConditionType {
|
|
125
|
+
id?: string; // Auto-generated unique identifier
|
|
126
|
+
Operator: ConditionOperatorType;
|
|
127
|
+
LHSField: string; // Field name to filter on
|
|
128
|
+
RHSValue: any; // Value to compare against
|
|
129
|
+
RHSType?: FilterRHSTypeType; // "Constant" | "BOField" | "AppVariable"
|
|
130
|
+
}
|
|
131
|
+
```
|
|
146
132
|
|
|
147
|
-
###
|
|
133
|
+
### ConditionGroupType (Nested Group)
|
|
148
134
|
|
|
149
135
|
```typescript
|
|
150
|
-
interface
|
|
151
|
-
id
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
rhsValue?: any; // Value to compare
|
|
155
|
-
rhsType?: FilterRHSType; // "Constant" | "Field"
|
|
156
|
-
children?: FilterConditionWithId[]; // Nested conditions (for logical operators)
|
|
157
|
-
isValid: boolean; // Validation state
|
|
158
|
-
validationErrors?: string[]; // Specific errors
|
|
136
|
+
interface ConditionGroupType {
|
|
137
|
+
id?: string; // Auto-generated unique identifier
|
|
138
|
+
Operator: ConditionGroupOperatorType; // "And" | "Or" | "Not"
|
|
139
|
+
Condition: Array<ConditionType | ConditionGroupType>; // Nested items
|
|
159
140
|
}
|
|
160
141
|
```
|
|
161
142
|
|
|
162
|
-
###
|
|
163
|
-
|
|
164
|
-
Type-safe input for addCondition:
|
|
143
|
+
### Type Guards
|
|
165
144
|
|
|
166
145
|
```typescript
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
146
|
+
// Check if item is a leaf condition
|
|
147
|
+
if (isCondition(item)) {
|
|
148
|
+
console.log(item.LHSField, item.Operator, item.RHSValue);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Check if item is a condition group
|
|
152
|
+
if (isConditionGroup(item)) {
|
|
153
|
+
console.log(item.Operator, item.Condition.length, "nested items");
|
|
173
154
|
}
|
|
174
155
|
```
|
|
175
156
|
|
|
176
157
|
## Filter Operators
|
|
177
158
|
|
|
178
|
-
### Comparison Operators
|
|
159
|
+
### Comparison Operators (ConditionOperatorType)
|
|
179
160
|
| Operator | Description | Example |
|
|
180
161
|
|----------|-------------|---------|
|
|
181
162
|
| `EQ` | Equal | `Price = 100` |
|
|
@@ -202,8 +183,6 @@ interface TypedFilterConditionInput<T> {
|
|
|
202
183
|
|----------|-------------|
|
|
203
184
|
| `Contains` | Contains substring |
|
|
204
185
|
| `NotContains` | Does not contain substring |
|
|
205
|
-
| `StartsWith` | Starts with string |
|
|
206
|
-
| `EndsWith` | Ends with string |
|
|
207
186
|
|
|
208
187
|
### Null Operators
|
|
209
188
|
| Operator | Description | RHS Required |
|
|
@@ -211,26 +190,26 @@ interface TypedFilterConditionInput<T> {
|
|
|
211
190
|
| `Empty` | Is empty/null | No |
|
|
212
191
|
| `NotEmpty` | Is not empty/null | No |
|
|
213
192
|
|
|
214
|
-
###
|
|
193
|
+
### Group Operators (ConditionGroupOperatorType)
|
|
215
194
|
| Operator | Description |
|
|
216
195
|
|----------|-------------|
|
|
217
|
-
| `And` | All
|
|
218
|
-
| `Or` | Any
|
|
219
|
-
| `Not` | Negate
|
|
196
|
+
| `And` | All conditions must match |
|
|
197
|
+
| `Or` | Any condition must match |
|
|
198
|
+
| `Not` | Negate conditions |
|
|
220
199
|
|
|
221
|
-
##
|
|
200
|
+
## Usage Examples
|
|
222
201
|
|
|
223
|
-
### Category Filter
|
|
202
|
+
### Simple Category Filter
|
|
224
203
|
|
|
225
204
|
```typescript
|
|
226
|
-
const
|
|
227
|
-
table.filter.
|
|
205
|
+
const filterByCategory = (category: string) => {
|
|
206
|
+
table.filter.clearAllConditions();
|
|
228
207
|
if (category !== "all") {
|
|
229
208
|
table.filter.addCondition({
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
209
|
+
Operator: "EQ",
|
|
210
|
+
LHSField: "Category",
|
|
211
|
+
RHSValue: category,
|
|
212
|
+
RHSType: "Constant",
|
|
234
213
|
});
|
|
235
214
|
}
|
|
236
215
|
};
|
|
@@ -239,230 +218,126 @@ const handleCategoryChange = (category: string) => {
|
|
|
239
218
|
### Price Range Filter
|
|
240
219
|
|
|
241
220
|
```typescript
|
|
242
|
-
const
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
rhsType: "Constant",
|
|
260
|
-
});
|
|
261
|
-
} else if (range.min === 0) {
|
|
262
|
-
// "Under $25" - use LT
|
|
263
|
-
table.filter.addCondition({
|
|
264
|
-
lhsField: "Price",
|
|
265
|
-
operator: "LT",
|
|
266
|
-
rhsValue: range.max,
|
|
267
|
-
rhsType: "Constant",
|
|
268
|
-
});
|
|
269
|
-
} else {
|
|
270
|
-
// Range like "$25 to $50" - use Between
|
|
271
|
-
table.filter.addCondition({
|
|
272
|
-
lhsField: "Price",
|
|
273
|
-
operator: "Between",
|
|
274
|
-
rhsValue: [range.min, range.max],
|
|
275
|
-
rhsType: "Constant",
|
|
276
|
-
});
|
|
277
|
-
}
|
|
221
|
+
const handlePriceRange = (min: number, max: number | null) => {
|
|
222
|
+
if (max === null) {
|
|
223
|
+
// Open-ended range: $200 & Above
|
|
224
|
+
table.filter.addCondition({
|
|
225
|
+
Operator: "GTE",
|
|
226
|
+
LHSField: "Price",
|
|
227
|
+
RHSValue: min,
|
|
228
|
+
RHSType: "Constant",
|
|
229
|
+
});
|
|
230
|
+
} else {
|
|
231
|
+
// Closed range: $25 to $50
|
|
232
|
+
table.filter.addCondition({
|
|
233
|
+
Operator: "Between",
|
|
234
|
+
LHSField: "Price",
|
|
235
|
+
RHSValue: [min, max],
|
|
236
|
+
RHSType: "Constant",
|
|
237
|
+
});
|
|
278
238
|
}
|
|
279
239
|
};
|
|
280
240
|
```
|
|
281
241
|
|
|
282
|
-
###
|
|
242
|
+
### Complex Nested Filter
|
|
283
243
|
|
|
284
244
|
```typescript
|
|
285
|
-
//
|
|
286
|
-
const
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
//
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
//
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
}
|
|
245
|
+
// Build: (Category = "Electronics") AND (Price > 100 OR OnSale = true)
|
|
246
|
+
const buildComplexFilter = () => {
|
|
247
|
+
filter.clearAllConditions();
|
|
248
|
+
|
|
249
|
+
// Add root condition
|
|
250
|
+
filter.addCondition({
|
|
251
|
+
Operator: "EQ",
|
|
252
|
+
LHSField: "Category",
|
|
253
|
+
RHSValue: "Electronics",
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
// Create nested OR group
|
|
257
|
+
const groupId = filter.addConditionGroup("Or");
|
|
258
|
+
|
|
259
|
+
// Add conditions to the group
|
|
260
|
+
filter.addCondition({
|
|
261
|
+
Operator: "GT",
|
|
262
|
+
LHSField: "Price",
|
|
263
|
+
RHSValue: 100,
|
|
264
|
+
}, groupId);
|
|
265
|
+
|
|
266
|
+
filter.addCondition({
|
|
267
|
+
Operator: "EQ",
|
|
268
|
+
LHSField: "OnSale",
|
|
269
|
+
RHSValue: true,
|
|
270
|
+
}, groupId);
|
|
311
271
|
};
|
|
312
272
|
```
|
|
313
273
|
|
|
314
|
-
###
|
|
274
|
+
### Toggle Root Operator
|
|
315
275
|
|
|
316
276
|
```typescript
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
setSelectedCategory("all");
|
|
322
|
-
setSelectedPriceRange(null);
|
|
323
|
-
}}
|
|
324
|
-
>
|
|
325
|
-
Clear All Filters
|
|
326
|
-
</Button>
|
|
277
|
+
const toggleFilterLogic = () => {
|
|
278
|
+
const next = filter.operator === "And" ? "Or" : "And";
|
|
279
|
+
filter.setRootOperator(next);
|
|
280
|
+
};
|
|
327
281
|
```
|
|
328
282
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
Support for complex filter expressions:
|
|
283
|
+
### Render Filter Tree
|
|
332
284
|
|
|
333
285
|
```typescript
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
}
|
|
286
|
+
const renderFilterItem = (item: ConditionType | ConditionGroupType) => {
|
|
287
|
+
if (isCondition(item)) {
|
|
288
|
+
return (
|
|
289
|
+
<div key={item.id}>
|
|
290
|
+
{item.LHSField} {item.Operator} {String(item.RHSValue)}
|
|
291
|
+
<button onClick={() => filter.removeCondition(item.id!)}>Remove</button>
|
|
292
|
+
</div>
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if (isConditionGroup(item)) {
|
|
297
|
+
return (
|
|
298
|
+
<div key={item.id}>
|
|
299
|
+
<span>{item.Operator} Group</span>
|
|
300
|
+
<button onClick={() => filter.addCondition({ Operator: "EQ", LHSField: "Field", RHSValue: "" }, item.id!)}>
|
|
301
|
+
+ Condition
|
|
302
|
+
</button>
|
|
303
|
+
<button onClick={() => filter.addConditionGroup("And", item.id!)}>+ Group</button>
|
|
304
|
+
{item.Condition.map((child) => renderFilterItem(child))}
|
|
305
|
+
</div>
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
};
|
|
348
309
|
```
|
|
349
310
|
|
|
350
311
|
## API Payload Format
|
|
351
312
|
|
|
352
|
-
The
|
|
313
|
+
The `payload` property automatically strips id fields for API compatibility:
|
|
353
314
|
|
|
354
315
|
```typescript
|
|
355
|
-
//
|
|
356
|
-
{
|
|
357
|
-
Operator: "And",
|
|
358
|
-
Condition: [
|
|
359
|
-
{
|
|
360
|
-
Operator: "EQ",
|
|
361
|
-
LHSField: "Category",
|
|
362
|
-
RHSValue: "Electronics",
|
|
363
|
-
RHSType: "Constant"
|
|
364
|
-
}
|
|
365
|
-
]
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
// Multiple conditions
|
|
316
|
+
// With conditions
|
|
369
317
|
{
|
|
370
318
|
Operator: "And",
|
|
371
319
|
Condition: [
|
|
372
320
|
{ Operator: "EQ", LHSField: "Category", RHSValue: "Electronics", RHSType: "Constant" },
|
|
373
|
-
{ Operator: "GTE", LHSField: "Price", RHSValue: 50, RHSType: "Constant" }
|
|
374
|
-
]
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
// Nested logical groups
|
|
378
|
-
{
|
|
379
|
-
Operator: "Or",
|
|
380
|
-
Condition: [
|
|
381
321
|
{
|
|
382
|
-
Operator: "
|
|
383
|
-
Condition: [
|
|
384
|
-
|
|
385
|
-
|
|
322
|
+
Operator: "Or",
|
|
323
|
+
Condition: [
|
|
324
|
+
{ Operator: "GT", LHSField: "Price", RHSValue: 100 },
|
|
325
|
+
{ Operator: "EQ", LHSField: "OnSale", RHSValue: true }
|
|
326
|
+
]
|
|
327
|
+
}
|
|
386
328
|
]
|
|
387
329
|
}
|
|
388
|
-
```
|
|
389
|
-
|
|
390
|
-
## Validation
|
|
391
|
-
|
|
392
|
-
### Automatic Validation
|
|
393
330
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
- lhsField is required for condition operators
|
|
397
|
-
- rhsValue format matches operator requirements
|
|
398
|
-
- Field-specific validation if fieldDefinitions provided
|
|
399
|
-
|
|
400
|
-
### Validation Errors
|
|
401
|
-
|
|
402
|
-
```typescript
|
|
403
|
-
interface ValidationError {
|
|
404
|
-
conditionId: string;
|
|
405
|
-
field: string;
|
|
406
|
-
message: string;
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
// Access validation errors
|
|
410
|
-
filter.validationErrors.forEach((error) => {
|
|
411
|
-
console.log(`${error.field}: ${error.message}`);
|
|
412
|
-
});
|
|
331
|
+
// No conditions returns undefined
|
|
332
|
+
filter.payload // undefined when items.length === 0
|
|
413
333
|
```
|
|
414
334
|
|
|
415
|
-
|
|
335
|
+
## Integration with useTable/useKanban
|
|
416
336
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
type: "number",
|
|
422
|
-
allowedOperators: ["EQ", "GT", "LT", "GTE", "LTE", "Between"],
|
|
423
|
-
validateValue: (value, operator) => {
|
|
424
|
-
if (value < 0) {
|
|
425
|
-
return { isValid: false, errors: ["Price cannot be negative"] };
|
|
426
|
-
}
|
|
427
|
-
return { isValid: true, errors: [] };
|
|
428
|
-
},
|
|
429
|
-
},
|
|
430
|
-
},
|
|
431
|
-
});
|
|
432
|
-
```
|
|
433
|
-
|
|
434
|
-
## State Management
|
|
435
|
-
|
|
436
|
-
### Export/Import State
|
|
437
|
-
|
|
438
|
-
```typescript
|
|
439
|
-
// Export current state
|
|
440
|
-
const savedState = filter.exportState();
|
|
441
|
-
localStorage.setItem("filters", JSON.stringify(savedState));
|
|
442
|
-
|
|
443
|
-
// Import saved state
|
|
444
|
-
const savedState = JSON.parse(localStorage.getItem("filters"));
|
|
445
|
-
filter.importState(savedState);
|
|
446
|
-
```
|
|
447
|
-
|
|
448
|
-
### Reset to Initial
|
|
449
|
-
|
|
450
|
-
```typescript
|
|
451
|
-
filter.resetToInitial();
|
|
452
|
-
```
|
|
453
|
-
|
|
454
|
-
## Key Behaviors
|
|
455
|
-
|
|
456
|
-
1. **Auto-validation**: Conditions validated on add/update
|
|
457
|
-
2. **Type-safe lhsField**: Constrained to `keyof T` at compile time
|
|
458
|
-
3. **Only valid in payload**: Only valid conditions included in filterPayload
|
|
459
|
-
4. **UUID generation**: Uses `crypto.randomUUID()` for condition IDs
|
|
460
|
-
5. **Deep copy on export**: Exported state is a deep copy
|
|
461
|
-
6. **Nested group support**: Full support for And/Or/Not logical nesting
|
|
462
|
-
|
|
463
|
-
## Integration with useTable
|
|
464
|
-
|
|
465
|
-
The useFilter hook is automatically integrated into useTable:
|
|
337
|
+
Filter changes automatically:
|
|
338
|
+
- Reset pagination to page 1
|
|
339
|
+
- Trigger data refetch
|
|
340
|
+
- Update count query
|
|
466
341
|
|
|
467
342
|
```typescript
|
|
468
343
|
const table = useTable<Product>({
|
|
@@ -472,26 +347,19 @@ const table = useTable<Product>({
|
|
|
472
347
|
filters: [...],
|
|
473
348
|
filterOperator: "And",
|
|
474
349
|
},
|
|
475
|
-
onFilterError: (errors) => console.log(errors),
|
|
476
350
|
});
|
|
477
351
|
|
|
478
352
|
// Access filter through table.filter
|
|
479
353
|
table.filter.addCondition({...});
|
|
480
|
-
table.filter.
|
|
481
|
-
table.filter.
|
|
482
|
-
table.filter.
|
|
354
|
+
table.filter.clearAllConditions();
|
|
355
|
+
table.filter.hasConditions;
|
|
356
|
+
table.filter.payload;
|
|
483
357
|
```
|
|
484
358
|
|
|
485
|
-
|
|
486
|
-
- Reset pagination to page 1
|
|
487
|
-
- Trigger data refetch
|
|
488
|
-
- Update count query
|
|
489
|
-
|
|
490
|
-
## Architecture Notes
|
|
359
|
+
## Key Behaviors
|
|
491
360
|
|
|
492
|
-
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
- Integrates seamlessly with useTable
|
|
361
|
+
1. **Auto-generated IDs**: All conditions get unique IDs via `generateId()`
|
|
362
|
+
2. **Payload strips IDs**: The `payload` property excludes id fields for API calls
|
|
363
|
+
3. **Recursive operations**: All operations work on nested groups
|
|
364
|
+
4. **Type guards**: Use `isCondition()` and `isConditionGroup()` for type-safe operations
|
|
365
|
+
5. **Optional parentId**: `addCondition` and `addConditionGroup` add to root when parentId is omitted
|