@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.
- package/dist/api.cjs +1 -1
- package/dist/api.mjs +1 -1
- package/dist/auth.cjs +1 -1
- package/dist/auth.mjs +1 -1
- package/dist/bdo.cjs +1 -1
- package/dist/bdo.mjs +1 -1
- package/dist/{constants-CYJih7y4.js → constants-ConHc1oS.js} +5 -3
- 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 +1 -1
- package/dist/table.cjs +1 -1
- package/dist/table.mjs +1 -1
- package/dist/types/constants.d.ts +5 -3
- package/dist/types/constants.d.ts.map +1 -1
- package/dist/workflow/components/useActivityTable/index.d.ts +4 -0
- package/dist/workflow/components/useActivityTable/index.d.ts.map +1 -0
- package/dist/workflow/components/useActivityTable/types.d.ts +53 -0
- package/dist/workflow/components/useActivityTable/types.d.ts.map +1 -0
- package/dist/workflow/components/useActivityTable/useActivityTable.d.ts +4 -0
- package/dist/workflow/components/useActivityTable/useActivityTable.d.ts.map +1 -0
- package/dist/workflow/types.d.ts +2 -3
- package/dist/workflow/types.d.ts.map +1 -1
- package/dist/workflow.cjs +1 -1
- package/dist/workflow.d.ts +2 -0
- package/dist/workflow.d.ts.map +1 -1
- package/dist/workflow.mjs +274 -204
- package/dist/workflow.types.d.ts +1 -0
- package/dist/workflow.types.d.ts.map +1 -1
- package/docs/api.md +1 -1
- package/docs/useFilter.md +279 -6
- package/docs/workflow.md +155 -10
- package/package.json +1 -1
- package/sdk/components/hooks/useFilter/useFilter.llm.txt +73 -4
- package/sdk/types/constants.ts +5 -3
- package/sdk/workflow/components/useActivityTable/index.ts +8 -0
- package/sdk/workflow/components/useActivityTable/types.ts +67 -0
- package/sdk/workflow/components/useActivityTable/useActivityTable.ts +145 -0
- package/sdk/workflow/types.ts +2 -3
- package/sdk/workflow.ts +7 -0
- package/sdk/workflow.types.ts +7 -0
- package/dist/constants-D0J69if5.cjs +0 -1
package/dist/workflow.types.d.ts
CHANGED
|
@@ -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
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.
|
|
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" | "
|
|
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
|
|
202
|
-
| MinLength, MaxLength | string
|
|
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 `"
|
|
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.
|
|
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:
|
|
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
|
-
```
|
|
548
|
-
import {
|
|
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
|
-
|
|
551
|
-
const activity =
|
|
652
|
+
function ManagerApprovalPage() {
|
|
653
|
+
const activity = useMemo(() => new SimpleLeaveProcess().managerApprovalActivity(), []);
|
|
654
|
+
const [selectedId, setSelectedId] = useState<string | null>(null);
|
|
552
655
|
|
|
553
|
-
const
|
|
656
|
+
const { rows, totalItems, isLoading, error, refetch } = useActivityTable(activity, {
|
|
657
|
+
status: ActivityTableStatus.InProgress,
|
|
658
|
+
});
|
|
554
659
|
|
|
555
|
-
|
|
556
|
-
|
|
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` | `
|
|
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
|
@@ -28,7 +28,7 @@ import type {
|
|
|
28
28
|
|
|
29
29
|
```typescript
|
|
30
30
|
const filter = useFilter({
|
|
31
|
-
|
|
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
|
-
| `
|
|
81
|
-
| `
|
|
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" | "
|
|
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()`
|