@ram_28/kf-ai-sdk 2.0.9 → 2.0.11

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 (43) hide show
  1. package/dist/api.cjs +1 -1
  2. package/dist/api.mjs +1 -1
  3. package/dist/auth.cjs +1 -1
  4. package/dist/auth.mjs +1 -1
  5. package/dist/bdo.cjs +1 -1
  6. package/dist/bdo.mjs +1 -1
  7. package/dist/{constants-CYJih7y4.js → constants-ConHc1oS.js} +5 -3
  8. package/dist/constants-QX2RX-wu.cjs +1 -0
  9. package/dist/filter.cjs +1 -1
  10. package/dist/filter.mjs +1 -1
  11. package/dist/form.cjs +1 -1
  12. package/dist/form.mjs +1 -1
  13. package/dist/table.cjs +1 -1
  14. package/dist/table.mjs +1 -1
  15. package/dist/types/constants.d.ts +5 -3
  16. package/dist/types/constants.d.ts.map +1 -1
  17. package/dist/workflow/components/useActivityTable/index.d.ts +4 -0
  18. package/dist/workflow/components/useActivityTable/index.d.ts.map +1 -0
  19. package/dist/workflow/components/useActivityTable/types.d.ts +53 -0
  20. package/dist/workflow/components/useActivityTable/types.d.ts.map +1 -0
  21. package/dist/workflow/components/useActivityTable/useActivityTable.d.ts +4 -0
  22. package/dist/workflow/components/useActivityTable/useActivityTable.d.ts.map +1 -0
  23. package/dist/workflow/types.d.ts +2 -3
  24. package/dist/workflow/types.d.ts.map +1 -1
  25. package/dist/workflow.cjs +1 -1
  26. package/dist/workflow.d.ts +2 -0
  27. package/dist/workflow.d.ts.map +1 -1
  28. package/dist/workflow.mjs +274 -204
  29. package/dist/workflow.types.d.ts +1 -0
  30. package/dist/workflow.types.d.ts.map +1 -1
  31. package/docs/api.md +1 -1
  32. package/docs/useFilter.md +279 -6
  33. package/docs/workflow.md +155 -10
  34. package/package.json +1 -1
  35. package/sdk/components/hooks/useFilter/useFilter.llm.txt +73 -4
  36. package/sdk/types/constants.ts +5 -3
  37. package/sdk/workflow/components/useActivityTable/index.ts +8 -0
  38. package/sdk/workflow/components/useActivityTable/types.ts +67 -0
  39. package/sdk/workflow/components/useActivityTable/useActivityTable.ts +145 -0
  40. package/sdk/workflow/types.ts +2 -3
  41. package/sdk/workflow.ts +7 -0
  42. package/sdk/workflow.types.ts +7 -0
  43. package/dist/constants-D0J69if5.cjs +0 -1
@@ -1,2 +1,3 @@
1
1
  export type { ActivityInstanceFieldsType, ActivityOperations, ActivityProgressType, WorkflowStartResponseType, } from './workflow/types';
2
+ export type { UseActivityTableOptionsType, UseActivityTableReturnType, ActivityTableStatusType, ActivityRowType, } from './workflow/components/useActivityTable/types';
2
3
  //# sourceMappingURL=workflow.types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"workflow.types.d.ts","sourceRoot":"","sources":["../sdk/workflow.types.ts"],"names":[],"mappings":"AAKA,YAAY,EACV,0BAA0B,EAC1B,kBAAkB,EAClB,oBAAoB,EACpB,yBAAyB,GAC1B,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"workflow.types.d.ts","sourceRoot":"","sources":["../sdk/workflow.types.ts"],"names":[],"mappings":"AAKA,YAAY,EACV,0BAA0B,EAC1B,kBAAkB,EAClB,oBAAoB,EACpB,yBAAyB,GAC1B,MAAM,kBAAkB,CAAC;AAE1B,YAAY,EACV,2BAA2B,EAC3B,0BAA0B,EAC1B,uBAAuB,EACvB,eAAe,GAChB,MAAM,8CAA8C,CAAC"}
package/docs/api.md CHANGED
@@ -277,7 +277,7 @@ interface ConditionType {
277
277
  Operator: ConditionOperatorType;
278
278
  LHSField: string;
279
279
  RHSValue: any;
280
- RHSType?: "Constant" | "BOField" | "AppVariable";
280
+ RHSType?: "Constant" | "BDOField" | "AppVariable";
281
281
  }
282
282
  ```
283
283
 
package/docs/useFilter.md CHANGED
@@ -59,7 +59,7 @@ GroupOperator.Not // "Not"
59
59
 
60
60
  // RHS types
61
61
  RHSType.Constant // "Constant"
62
- RHSType.BOField // "BOField"
62
+ RHSType.BDOField // "BDOField"
63
63
  RHSType.AppVariable // "AppVariable"
64
64
  ```
65
65
 
@@ -103,7 +103,7 @@ interface ConditionType<T = any> {
103
103
  RHSValue: any;
104
104
 
105
105
  // Value type (default: "Constant")
106
- RHSType?: "Constant" | "BOField" | "AppVariable";
106
+ RHSType?: "Constant" | "BDOField" | "AppVariable";
107
107
  }
108
108
 
109
109
  // Condition group (can contain conditions or nested groups)
@@ -198,8 +198,9 @@ interface UseFilterReturnType<T = any> {
198
198
  | Between, NotBetween | number, date, currency |
199
199
  | IN, NIN | All types |
200
200
  | Empty, NotEmpty | All types |
201
- | Contains, NotContains | string only |
202
- | MinLength, MaxLength | string only |
201
+ | Contains, NotContains | string, reference/user (with dot notation) |
202
+ | MinLength, MaxLength | string, array |
203
+ | Length | array |
203
204
 
204
205
  ## Basic Example
205
206
 
@@ -621,6 +622,174 @@ function EmptyFilters() {
621
622
 
622
623
  ---
623
624
 
625
+ ## Filtering Reference & User Fields
626
+
627
+ Reference and User fields are stored as JSON objects (`{ _id, _name, ... }`). The backend automatically targets the `_id` sub-field when filtering these fields. User and Reference fields behave identically for filtering.
628
+
629
+ ### Supported Operators
630
+
631
+ | Operator | Supported | Notes |
632
+ | --- | --- | --- |
633
+ | EQ, NE | Yes | Compares against `_id` by default |
634
+ | IN, NIN | Yes | List of IDs |
635
+ | Empty, NotEmpty | Yes | Checks if field is null/unset |
636
+ | Contains, NotContains | Only with dot notation | e.g., `"Vendor._name"` |
637
+ | GT, GTE, LT, LTE, Between | No | Raises backend error |
638
+
639
+ ### Filter by ID (Default)
640
+
641
+ When filtering a Reference or User field, pass the `_id` string directly as `RHSValue`. The backend automatically compares against the `_id` sub-field.
642
+
643
+ ```tsx
644
+ import { useMemo } from "react";
645
+ import { useFilter, ConditionOperator, RHSType } from "@ram_28/kf-ai-sdk/filter";
646
+ import { AdminCartItem } from "../bdo/admin/CartItem";
647
+
648
+ function ReferenceFilter() {
649
+ const cartItem = useMemo(() => new AdminCartItem(), []);
650
+ const filter = useFilter();
651
+
652
+ // Filter cart items by a specific product ID
653
+ const filterByProduct = (productId: string) => {
654
+ filter.addCondition({
655
+ Operator: ConditionOperator.EQ,
656
+ LHSField: cartItem.ProductInfo.id,
657
+ RHSValue: productId,
658
+ RHSType: RHSType.Constant,
659
+ });
660
+ };
661
+
662
+ // Filter by multiple product IDs
663
+ const filterByProducts = (productIds: string[]) => {
664
+ filter.addCondition({
665
+ Operator: ConditionOperator.IN,
666
+ LHSField: cartItem.ProductInfo.id,
667
+ RHSValue: productIds,
668
+ RHSType: RHSType.Constant,
669
+ });
670
+ };
671
+
672
+ // Filter unassigned items (reference is empty)
673
+ const filterUnlinked = () => {
674
+ filter.addCondition({
675
+ Operator: ConditionOperator.Empty,
676
+ LHSField: cartItem.ProductInfo.id,
677
+ RHSValue: null,
678
+ RHSType: RHSType.Constant,
679
+ });
680
+ };
681
+
682
+ return (
683
+ <div>
684
+ <button onClick={() => filterByProduct("PROD_001")}>
685
+ Filter by Product
686
+ </button>
687
+ <button onClick={() => filterByProducts(["PROD_001", "PROD_002"])}>
688
+ Filter by Multiple
689
+ </button>
690
+ <button onClick={filterUnlinked}>Unlinked Items</button>
691
+ </div>
692
+ );
693
+ }
694
+ ```
695
+
696
+ ### Filter by Name (Dot Notation)
697
+
698
+ Use dot notation in `LHSField` to filter on a nested sub-field like `_name`. This skips the default `_id` targeting and compares against the specified path.
699
+
700
+ ```tsx
701
+ import { useMemo } from "react";
702
+ import { useFilter, ConditionOperator, RHSType } from "@ram_28/kf-ai-sdk/filter";
703
+ import { AdminCartItem } from "../bdo/admin/CartItem";
704
+
705
+ function ReferenceNameFilter() {
706
+ const cartItem = useMemo(() => new AdminCartItem(), []);
707
+ const filter = useFilter();
708
+
709
+ // Search product name within the reference field
710
+ const searchProductName = (name: string) => {
711
+ filter.addCondition({
712
+ Operator: ConditionOperator.Contains,
713
+ LHSField: `${cartItem.ProductInfo.id}._name`,
714
+ RHSValue: name,
715
+ RHSType: RHSType.Constant,
716
+ });
717
+ };
718
+
719
+ return (
720
+ <input
721
+ placeholder="Search by product name..."
722
+ onKeyDown={(e) => {
723
+ if (e.key === "Enter") {
724
+ searchProductName((e.target as HTMLInputElement).value);
725
+ }
726
+ }}
727
+ />
728
+ );
729
+ }
730
+ ```
731
+
732
+ ### Filter System User Fields
733
+
734
+ System fields `_created_by` and `_modified_by` are User fields. Filter them the same way.
735
+
736
+ ```tsx
737
+ import { useFilter, ConditionOperator, RHSType } from "@ram_28/kf-ai-sdk/filter";
738
+
739
+ function UserFieldFilter() {
740
+ const filter = useFilter();
741
+
742
+ // Filter by creator (using user's _id)
743
+ const filterByCreator = (userId: string) => {
744
+ filter.addCondition({
745
+ Operator: ConditionOperator.EQ,
746
+ LHSField: "_created_by",
747
+ RHSValue: userId,
748
+ RHSType: RHSType.Constant,
749
+ });
750
+ };
751
+
752
+ // Search by creator name
753
+ const searchByCreatorName = (name: string) => {
754
+ filter.addCondition({
755
+ Operator: ConditionOperator.Contains,
756
+ LHSField: "_created_by._name",
757
+ RHSValue: name,
758
+ RHSType: RHSType.Constant,
759
+ });
760
+ };
761
+
762
+ return (
763
+ <div>
764
+ <button onClick={() => filterByCreator("USR_001")}>My Items</button>
765
+ <input
766
+ placeholder="Search by creator..."
767
+ onKeyDown={(e) => {
768
+ if (e.key === "Enter") {
769
+ searchByCreatorName((e.target as HTMLInputElement).value);
770
+ }
771
+ }}
772
+ />
773
+ </div>
774
+ );
775
+ }
776
+ ```
777
+
778
+ ### RHSValue Formats
779
+
780
+ The backend accepts multiple `RHSValue` formats for Reference/User fields:
781
+
782
+ | Format | Example | When to use |
783
+ | --- | --- | --- |
784
+ | String ID | `"PROD_001"` | Simplest — use when you have the ID |
785
+ | Object with `_id` | `{ _id: "PROD_001", _name: "Widget" }` | Backend extracts `_id` automatically |
786
+ | Array of IDs | `["PROD_001", "PROD_002"]` | With `IN` / `NIN` operators |
787
+ | Array of objects | `[{ _id: "PROD_001" }, { _id: "PROD_002" }]` | With `IN` / `NIN` — backend extracts each `_id` |
788
+
789
+ > **Tip:** Prefer passing the string ID directly. Passing the full object works but adds unnecessary payload size.
790
+
791
+ ---
792
+
624
793
  ## Condition Groups
625
794
 
626
795
  ### AND Logic
@@ -1319,7 +1488,93 @@ Produces:
1319
1488
  }
1320
1489
  ```
1321
1490
 
1322
- > **Note:** The `RHSType` field defaults to `"Constant"` and is automatically added to the payload. Other possible values are `"BOField"` (reference another field) and `"AppVariable"` (reference an application variable).
1491
+ > **Note:** The `RHSType` field defaults to `"Constant"` and is automatically added to the payload. Other possible values are `"BDOField"` (reference another BDO field) and `"AppVariable"` (reference an application variable).
1492
+
1493
+ ### Reference Field (EQ)
1494
+
1495
+ ```tsx
1496
+ import { ConditionOperator, RHSType } from "@ram_28/kf-ai-sdk/filter";
1497
+
1498
+ filter.addCondition({
1499
+ Operator: ConditionOperator.EQ,
1500
+ LHSField: cartItem.ProductInfo.id,
1501
+ RHSValue: "PROD_001",
1502
+ RHSType: RHSType.Constant,
1503
+ });
1504
+ ```
1505
+
1506
+ Produces:
1507
+
1508
+ ```json
1509
+ {
1510
+ "Operator": "And",
1511
+ "Condition": [
1512
+ {
1513
+ "Operator": "EQ",
1514
+ "LHSField": "ProductInfo",
1515
+ "RHSValue": "PROD_001",
1516
+ "RHSType": "Constant"
1517
+ }
1518
+ ]
1519
+ }
1520
+ ```
1521
+
1522
+ ### Reference Field Nested Path (Contains)
1523
+
1524
+ ```tsx
1525
+ filter.addCondition({
1526
+ Operator: ConditionOperator.Contains,
1527
+ LHSField: `${cartItem.ProductInfo.id}._name`,
1528
+ RHSValue: "Widget",
1529
+ RHSType: RHSType.Constant,
1530
+ });
1531
+ ```
1532
+
1533
+ Produces:
1534
+
1535
+ ```json
1536
+ {
1537
+ "Operator": "And",
1538
+ "Condition": [
1539
+ {
1540
+ "Operator": "Contains",
1541
+ "LHSField": "ProductInfo._name",
1542
+ "RHSValue": "Widget",
1543
+ "RHSType": "Constant"
1544
+ }
1545
+ ]
1546
+ }
1547
+ ```
1548
+
1549
+ ### Field-to-Field Comparison (BDOField)
1550
+
1551
+ Use `RHSType.BDOField` to compare one field against another field instead of a constant value.
1552
+
1553
+ ```tsx
1554
+ // Filter where Quantity exceeds Stock (field vs field)
1555
+ filter.addCondition({
1556
+ Operator: ConditionOperator.GT,
1557
+ LHSField: cartItem.Quantity.id,
1558
+ RHSValue: cartItem.Stock.id,
1559
+ RHSType: RHSType.BDOField,
1560
+ });
1561
+ ```
1562
+
1563
+ Produces:
1564
+
1565
+ ```json
1566
+ {
1567
+ "Operator": "And",
1568
+ "Condition": [
1569
+ {
1570
+ "Operator": "GT",
1571
+ "LHSField": "Quantity",
1572
+ "RHSValue": "Stock",
1573
+ "RHSType": "BDOField"
1574
+ }
1575
+ ]
1576
+ }
1577
+ ```
1323
1578
 
1324
1579
  ---
1325
1580
 
@@ -1337,7 +1592,7 @@ Only three RHSType values exist. Any other string causes TS2322.
1337
1592
 
1338
1593
  // ✅ CORRECT — only these three values
1339
1594
  { RHSType: RHSType.Constant } // "Constant"
1340
- { RHSType: RHSType.BOField } // "BOField"
1595
+ { RHSType: RHSType.BDOField } // "BDOField"
1341
1596
  { RHSType: RHSType.AppVariable } // "AppVariable"
1342
1597
  ```
1343
1598
 
@@ -1387,3 +1642,21 @@ const conditions: Omit<ConditionType, "id">[] = [
1387
1642
  { Operator: ConditionOperator.EQ, ... }
1388
1643
  ];
1389
1644
  ```
1645
+
1646
+ ### 5. Filtering Reference/User fields without _id
1647
+
1648
+ The backend automatically targets `_id` when you filter a Reference or User field by name. Do NOT manually append `._id` unless you specifically want to bypass the backend's auto-extraction.
1649
+
1650
+ ```typescript
1651
+ // ❌ WRONG — unnecessary, and disables auto-extraction of _id from objects
1652
+ { LHSField: "ProductInfo._id", Operator: "EQ", RHSValue: { _id: "P1", _name: "Widget" } }
1653
+
1654
+ // ✅ CORRECT — backend auto-targets _id
1655
+ { LHSField: "ProductInfo", Operator: "EQ", RHSValue: "P1" }
1656
+
1657
+ // ✅ CORRECT — backend extracts _id from the object
1658
+ { LHSField: "ProductInfo", Operator: "EQ", RHSValue: { _id: "P1", _name: "Widget" } }
1659
+
1660
+ // ✅ CORRECT — dot notation for filtering by _name
1661
+ { LHSField: "ProductInfo._name", Operator: "Contains", RHSValue: "Widget" }
1662
+ ```
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,9 @@ import type {
20
22
  WorkflowStartResponseType,
21
23
  UseActivityFormOptions,
22
24
  UseActivityFormReturn,
25
+ UseActivityTableOptionsType,
26
+ UseActivityTableReturnType,
27
+ ActivityRowType,
23
28
  } from "@ram_28/kf-ai-sdk/workflow";
24
29
 
25
30
  // Field classes (for defining Activity fields)
@@ -82,11 +87,72 @@ System fields present on every activity instance. Returned alongside activity-sp
82
87
  type ActivityInstanceFieldsType = {
83
88
  _id: StringFieldType;
84
89
  Status: SelectFieldType<"InProgress" | "Completed">;
85
- AssignedTo: ReferenceFieldType<{ _id: StringFieldType; username: StringFieldType }>;
90
+ AssignedTo: UserFieldType;
86
91
  CompletedAt: DateTimeFieldType;
87
92
  };
88
93
  ```
89
94
 
95
+ ### ActivityTableStatus (constant)
96
+
97
+ ```typescript
98
+ const ActivityTableStatus = {
99
+ InProgress: 'inprogress',
100
+ Completed: 'completed',
101
+ } as const;
102
+
103
+ type ActivityTableStatusType =
104
+ (typeof ActivityTableStatus)[keyof typeof ActivityTableStatus];
105
+ ```
106
+
107
+ ### ActivityRowType\<A\>
108
+
109
+ Row type for activity table data. Combines activity instance system fields with entity-specific fields.
110
+
111
+ ```typescript
112
+ type ActivityRowType<A extends Activity<any, any, any>> =
113
+ ActivityInstanceFieldsType & ExtractActivityEntity<A>;
114
+ ```
115
+
116
+ Concrete example — for `ManagerApprovalActivity` with `{ ManagerApproved: boolean, ManagerReason: string }`:
117
+
118
+ ```typescript
119
+ // ActivityRowType<ManagerApprovalActivity> resolves to:
120
+ {
121
+ // System fields (from ActivityInstanceFieldsType)
122
+ _id: string;
123
+ Status: "InProgress" | "Completed";
124
+ AssignedTo: UserFieldType;
125
+ CompletedAt: string;
126
+
127
+ // Entity fields (from ManagerApprovalEntityType)
128
+ ManagerApproved: boolean;
129
+ ManagerReason: string;
130
+ }
131
+ ```
132
+
133
+ ### UseActivityTableOptionsType\<A\>
134
+
135
+ ```typescript
136
+ interface UseActivityTableOptionsType<A extends Activity<any, any, any>> {
137
+ status: ActivityTableStatusType;
138
+ onError?: (error: Error) => void;
139
+ onSuccess?: (data: ActivityRowType<A>[]) => void;
140
+ }
141
+ ```
142
+
143
+ ### UseActivityTableReturnType\<A\>
144
+
145
+ ```typescript
146
+ interface UseActivityTableReturnType<A extends Activity<any, any, any>> {
147
+ rows: ActivityRowType<A>[];
148
+ totalItems: number;
149
+ isLoading: boolean;
150
+ isFetching: boolean;
151
+ error: Error | null;
152
+ refetch: () => Promise<ListResponseType<ActivityRowType<A>>>;
153
+ }
154
+ ```
155
+
90
156
  ### UseActivityFormOptions\<A\>
91
157
 
92
158
  ```typescript
@@ -382,6 +448,40 @@ User clicks Complete
382
448
 
383
449
  ---
384
450
 
451
+ ## useActivityTable Hook
452
+
453
+ React hook for listing workflow activity instances. Fetches data from
454
+ `getInProgressList()` or `getCompletedList()` and the corresponding
455
+ metrics endpoint.
456
+
457
+ ### Signature
458
+
459
+ ```typescript
460
+ useActivityTable(activity: A, options: UseActivityTableOptionsType<A>)
461
+ : UseActivityTableReturnType<A>
462
+ ```
463
+
464
+ ### Options
465
+
466
+ | Property | Type | Default | Description |
467
+ |----------|------|---------|-------------|
468
+ | `status` | `ActivityTableStatusType` | *required* | `ActivityTableStatus.InProgress` or `ActivityTableStatus.Completed` |
469
+ | `onError` | `(error: Error) => void` | — | Error callback |
470
+ | `onSuccess` | `(data: ActivityRowType<A>[]) => void` | — | Success callback |
471
+
472
+ ### Return Value
473
+
474
+ | Property | Type | Description |
475
+ |----------|------|-------------|
476
+ | `rows` | `ActivityRowType<A>[]` | Activity instance records (system + entity fields) |
477
+ | `totalItems` | `number` | Total count (from metrics endpoint) |
478
+ | `isLoading` | `boolean` | Initial load in progress |
479
+ | `isFetching` | `boolean` | Any fetch in progress (including refetch) |
480
+ | `error` | `Error \| null` | Fetch error |
481
+ | `refetch` | `() => Promise<...>` | Refetch both list and metrics |
482
+
483
+ ---
484
+
385
485
  ## Use Case: Employee Creating Leave
386
486
 
387
487
  ### Step 1 — Start the workflow
@@ -542,18 +642,63 @@ function LeaveRequestPage() {
542
642
 
543
643
  ## Use Case: Manager Approving Leave
544
644
 
545
- ### Step 1 — List in-progress items
645
+ ### Step 1 — List in-progress items with useActivityTable
546
646
 
547
- ```typescript
548
- import { SimpleLeaveProcess } from "@/bdo/workflows/SimpleLeaveProcess";
647
+ ```tsx
648
+ import { useMemo, useState } from "react";
649
+ import { useActivityTable, ActivityTableStatus } from "@ram_28/kf-ai-sdk/workflow";
650
+ import { SimpleLeaveProcess, ManagerApprovalActivity } from "@/bdo/workflows/SimpleLeaveProcess";
549
651
 
550
- const wf = new SimpleLeaveProcess();
551
- const activity = wf.managerApprovalActivity();
652
+ function ManagerApprovalPage() {
653
+ const activity = useMemo(() => new SimpleLeaveProcess().managerApprovalActivity(), []);
654
+ const [selectedId, setSelectedId] = useState<string | null>(null);
552
655
 
553
- const result = await activity.getInProgressList();
656
+ const { rows, totalItems, isLoading, error, refetch } = useActivityTable(activity, {
657
+ status: ActivityTableStatus.InProgress,
658
+ });
554
659
 
555
- for (const item of result.Data) {
556
- console.log(item._id, item.Status, item.AssignedTo.username);
660
+ if (isLoading) return <div>Loading...</div>;
661
+ if (error) return <div>Error: {error.message}</div>;
662
+
663
+ if (selectedId) {
664
+ return (
665
+ <ApprovalForm
666
+ activityInstanceId={selectedId}
667
+ onComplete={() => {
668
+ setSelectedId(null);
669
+ refetch();
670
+ }}
671
+ />
672
+ );
673
+ }
674
+
675
+ return (
676
+ <div>
677
+ <h2>Pending Approvals ({totalItems})</h2>
678
+ <table>
679
+ <thead>
680
+ <tr>
681
+ <th>ID</th>
682
+ <th>Status</th>
683
+ <th>Assigned To</th>
684
+ <th>Action</th>
685
+ </tr>
686
+ </thead>
687
+ <tbody>
688
+ {rows.map((row) => (
689
+ <tr key={row._id}>
690
+ <td>{row._id}</td>
691
+ <td>{row.Status}</td>
692
+ <td>{row.AssignedTo._name}</td>
693
+ <td>
694
+ <button onClick={() => setSelectedId(row._id)}>Review</button>
695
+ </td>
696
+ </tr>
697
+ ))}
698
+ </tbody>
699
+ </table>
700
+ </div>
701
+ );
557
702
  }
558
703
  ```
559
704
 
@@ -703,7 +848,7 @@ const progressList = await wf.progress(BPInstanceId);
703
848
  |-------|------|-------------|
704
849
  | `_id` | `StringFieldType` | Unique activity instance identifier |
705
850
  | `Status` | `SelectFieldType<"InProgress" \| "Completed">` | Current status |
706
- | `AssignedTo` | `ReferenceFieldType<UserRefType>` | Assigned user (has `._id` and `.username`) |
851
+ | `AssignedTo` | `UserFieldType` | Assigned user (has `._id` and `._name`) |
707
852
  | `CompletedAt` | `DateTimeFieldType` | Completion timestamp (`"YYYY-MM-DDTHH:MM:SS"`) |
708
853
 
709
854
  ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ram_28/kf-ai-sdk",
3
- "version": "2.0.9",
3
+ "version": "2.0.11",
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",
@@ -28,7 +28,7 @@ import type {
28
28
 
29
29
  ```typescript
30
30
  const filter = useFilter({
31
- initialOperator: "And",
31
+ operator: "And",
32
32
  });
33
33
 
34
34
  // Add a condition at root level
@@ -77,8 +77,8 @@ table.filter.clearAllConditions();
77
77
 
78
78
  | Property | Type | Required | Default | Description |
79
79
  |----------|------|----------|---------|-------------|
80
- | `initialConditions` | `Array<ConditionType \| ConditionGroupType>` | No | `[]` | Initial filter conditions |
81
- | `initialOperator` | `ConditionGroupOperatorType` | No | `"And"` | Initial root operator |
80
+ | `conditions` | `Array<ConditionType \| ConditionGroupType>` | No | `[]` | Filter conditions |
81
+ | `operator` | `ConditionGroupOperatorType` | No | `"And"` | Operator for combining conditions |
82
82
 
83
83
  ## Return Value
84
84
 
@@ -126,7 +126,7 @@ interface ConditionType {
126
126
  Operator: ConditionOperatorType;
127
127
  LHSField: string; // Field name to filter on
128
128
  RHSValue: any; // Value to compare against
129
- RHSType?: FilterRHSTypeType; // "Constant" | "BOField" | "AppVariable"
129
+ RHSType?: FilterRHSTypeType; // "Constant" | "BDOField" | "AppVariable"
130
130
  }
131
131
  ```
132
132
 
@@ -271,6 +271,18 @@ const buildComplexFilter = () => {
271
271
  };
272
272
  ```
273
273
 
274
+ ### Field-to-Field Comparison (BDOField)
275
+
276
+ ```typescript
277
+ // Filter where Quantity exceeds Stock (field vs field)
278
+ filter.addCondition({
279
+ Operator: "GT",
280
+ LHSField: "Quantity",
281
+ RHSValue: "Stock",
282
+ RHSType: "BDOField",
283
+ });
284
+ ```
285
+
274
286
  ### Toggle Root Operator
275
287
 
276
288
  ```typescript
@@ -356,6 +368,63 @@ table.filter.hasConditions;
356
368
  table.filter.payload;
357
369
  ```
358
370
 
371
+ ## Filtering Reference & User Fields
372
+
373
+ Reference and User fields store `{ _id, _name, ... }` objects. Key rules:
374
+
375
+ - **Default targets `_id`**: Pass string ID as `RHSValue`, backend auto-compares against `_id`
376
+ - **Dot notation for nested paths**: Use `"FieldName._name"` in `LHSField` to filter by `_name` or other sub-fields
377
+ - **Supported operators**: `EQ`, `NE`, `IN`, `NIN`, `Empty`, `NotEmpty`
378
+ - **Contains/NotContains**: Only with dot notation (e.g., `"Vendor._name"`)
379
+ - **GT/GTE/LT/LTE/Between**: NOT supported — raises backend error
380
+
381
+ ### Examples
382
+
383
+ ```typescript
384
+ // Filter by reference ID
385
+ filter.addCondition({
386
+ Operator: "EQ",
387
+ LHSField: "ProductInfo", // field name, NOT "ProductInfo._id"
388
+ RHSValue: "PROD_001", // string ID directly
389
+ RHSType: "Constant",
390
+ });
391
+
392
+ // Filter by multiple IDs
393
+ filter.addCondition({
394
+ Operator: "IN",
395
+ LHSField: "ProductInfo",
396
+ RHSValue: ["PROD_001", "PROD_002"],
397
+ RHSType: "Constant",
398
+ });
399
+
400
+ // Search by reference name (dot notation)
401
+ filter.addCondition({
402
+ Operator: "Contains",
403
+ LHSField: "ProductInfo._name", // dot notation for nested path
404
+ RHSValue: "Widget",
405
+ RHSType: "Constant",
406
+ });
407
+
408
+ // Filter system user field
409
+ filter.addCondition({
410
+ Operator: "EQ",
411
+ LHSField: "_created_by",
412
+ RHSValue: "USR_001",
413
+ RHSType: "Constant",
414
+ });
415
+ ```
416
+
417
+ ### RHSValue Formats
418
+
419
+ | Format | Example | When to use |
420
+ |--------|---------|-------------|
421
+ | String ID | `"PROD_001"` | Simplest — use when you have the ID |
422
+ | Object | `{ _id: "PROD_001", _name: "Widget" }` | Backend extracts `_id` automatically |
423
+ | Array of IDs | `["PROD_001", "PROD_002"]` | With IN/NIN operators |
424
+ | Array of objects | `[{ _id: "PROD_001" }]` | With IN/NIN — backend extracts each `_id` |
425
+
426
+ Prefer passing string IDs directly for simplicity.
427
+
359
428
  ## Key Behaviors
360
429
 
361
430
  1. **Auto-generated IDs**: All conditions get unique IDs via `generateId()`