@ram_28/kf-ai-sdk 2.0.16 → 2.0.18
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 +16 -8
- package/dist/{FileField-BWrSHNRq.js → FileField-CZjS2uLh.js} +3 -3
- package/dist/{FileField-eDeuzln8.cjs → FileField-DU4UWo_t.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 +0 -4
- 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 +53 -62
- package/dist/components/hooks/useActivityForm/types.d.ts +4 -5
- 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 +5 -4
- 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 +2 -3
- package/dist/components/hooks/useBDOForm/createItemProxy.d.ts.map +1 -1
- package/dist/components/hooks/useBDOTable/types.d.ts +20 -12
- 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-ConHc1oS.js → constants-Cyi942Yr.js} +5 -5
- package/dist/constants-DEmYwKfC.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 +226 -243
- package/dist/table.cjs +1 -1
- package/dist/table.mjs +15 -16
- 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 +8 -5
- package/dist/workflow/Activity.d.ts.map +1 -1
- package/dist/workflow.cjs +1 -1
- package/dist/workflow.mjs +461 -476
- package/docs/README.md +57 -0
- package/docs/bdo/README.md +161 -0
- package/docs/bdo/api_reference.md +281 -0
- package/docs/examples/bdo/create-product.md +69 -0
- package/docs/examples/bdo/edit-product-dialog.md +95 -0
- package/docs/examples/bdo/filtered-product-table.md +100 -0
- package/docs/examples/bdo/product-listing.md +73 -0
- package/docs/examples/bdo/supplier-dropdown.md +60 -0
- package/docs/examples/fields/complex-fields.md +248 -0
- package/docs/examples/fields/primitive-fields.md +217 -0
- package/docs/examples/workflow/approve-leave-request.md +76 -0
- package/docs/examples/workflow/filtered-activity-table.md +101 -0
- package/docs/examples/workflow/my-pending-requests.md +90 -0
- package/docs/examples/workflow/start-new-workflow.md +47 -0
- package/docs/examples/workflow/submit-leave-request.md +72 -0
- package/docs/examples/workflow/workflow-progress.md +49 -0
- package/docs/fields/README.md +141 -0
- package/docs/fields/api_reference.md +134 -0
- package/docs/useActivityForm/README.md +244 -0
- package/docs/useActivityForm/api_reference.md +279 -0
- package/docs/useActivityTable/README.md +263 -0
- package/docs/useActivityTable/api_reference.md +294 -0
- package/docs/useBDOForm/README.md +175 -0
- package/docs/useBDOForm/api_reference.md +244 -0
- package/docs/useBDOTable/README.md +242 -0
- package/docs/useBDOTable/api_reference.md +253 -0
- package/docs/useFilter/README.md +323 -0
- package/docs/useFilter/api_reference.md +228 -0
- package/docs/workflow/README.md +158 -0
- package/docs/workflow/api_reference.md +161 -0
- package/package.json +1 -1
- package/sdk/auth/authConfig.ts +1 -1
- package/sdk/auth/types.ts +1 -1
- package/sdk/bdo/core/Item.ts +1 -10
- 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 +4 -6
- package/sdk/components/hooks/useActivityForm/useActivityForm.ts +10 -73
- package/sdk/components/hooks/useActivityTable/types.ts +4 -5
- package/sdk/components/hooks/useActivityTable/useActivityTable.ts +10 -8
- package/sdk/components/hooks/useBDOForm/createItemProxy.ts +17 -58
- package/sdk/components/hooks/useBDOTable/types.ts +20 -10
- package/sdk/components/hooks/useBDOTable/useBDOTable.ts +12 -8
- package/sdk/table.types.ts +2 -0
- package/sdk/types/constants.ts +1 -1
- package/sdk/workflow/Activity.ts +39 -7
- package/dist/constants-QX2RX-wu.cjs +0 -1
- package/docs/api.md +0 -95
- package/docs/bdo.md +0 -224
- package/docs/gaps.md +0 -360
- package/docs/useActivityForm.md +0 -393
- package/docs/useActivityTable.md +0 -418
- package/docs/useBDOForm.md +0 -376
- package/docs/useBDOTable.md +0 -284
- package/docs/useFilter.md +0 -188
- package/docs/workflow.md +0 -560
- /package/docs/{useAuth.md → useAuth/README.md} +0 -0
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
# useActivityForm API Reference
|
|
2
|
+
|
|
3
|
+
```tsx
|
|
4
|
+
import { useActivityForm } from "@ram_28/kf-ai-sdk/workflow";
|
|
5
|
+
import type {
|
|
6
|
+
UseActivityFormOptions,
|
|
7
|
+
UseActivityFormReturn,
|
|
8
|
+
} from "@ram_28/kf-ai-sdk/workflow";
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Signature
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
const form: UseActivityFormReturn<EmployeeInputActivity> = useActivityForm(
|
|
15
|
+
activity: EmployeeInputActivity,
|
|
16
|
+
options: UseActivityFormOptions<EmployeeInputActivity>,
|
|
17
|
+
);
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
First argument is the Activity instance (positional). Second argument is the options object.
|
|
21
|
+
|
|
22
|
+
## Options
|
|
23
|
+
|
|
24
|
+
`UseActivityFormOptions<A>`
|
|
25
|
+
|
|
26
|
+
- `activity_instance_id: string`
|
|
27
|
+
- **Required**
|
|
28
|
+
- Activity instance ID. From `workflow.start()` response or `getInProgressList()` rows.
|
|
29
|
+
- `defaultValues?: Partial<ExtractActivityEditable<A>>`
|
|
30
|
+
- **Optional** · Defaults to `{}`
|
|
31
|
+
- Initial form values before server data loads. Server data wins on merge.
|
|
32
|
+
- `mode?: "onBlur" | "onChange" | "onSubmit" | "onTouched" | "all"`
|
|
33
|
+
- **Optional** · Defaults to `"onBlur"`
|
|
34
|
+
- RHF validation mode. Also controls when per-field server sync fires.
|
|
35
|
+
- `enabled?: boolean`
|
|
36
|
+
- **Optional** · Defaults to `true`
|
|
37
|
+
- Set `false` to defer `activity.read()` until the instance ID is available.
|
|
38
|
+
|
|
39
|
+
## Return Value
|
|
40
|
+
|
|
41
|
+
`UseActivityFormReturn<A>`
|
|
42
|
+
|
|
43
|
+
### Instance
|
|
44
|
+
|
|
45
|
+
- `item: FormItemType<TEditable, TReadonly>`
|
|
46
|
+
- The current activity instance. Each field is an accessor with methods to read, write, and validate. See [Instance and Field Accessors](#instance-and-field-accessors).
|
|
47
|
+
- `activity: A`
|
|
48
|
+
- The Activity instance passed to the hook.
|
|
49
|
+
|
|
50
|
+
### Form Methods
|
|
51
|
+
|
|
52
|
+
- `register: FormRegisterType<TEditable, TReadonly>`
|
|
53
|
+
- Registers an input field. Auto-disables readonly fields (`{ disabled: true }`).
|
|
54
|
+
- `handleSubmit: HandleSubmitType<CreateUpdateResponseType>`
|
|
55
|
+
- Validates, updates any remaining dirty fields, then completes the activity. See [handleSubmit](#handlesubmit).
|
|
56
|
+
- `watch: UseFormWatch<AllActivityFields<A>>`
|
|
57
|
+
- Standard RHF `watch`. Typed to all fields (editable + readonly).
|
|
58
|
+
- `setValue: UseFormSetValue<ExtractActivityEditable<A>>`
|
|
59
|
+
- Standard RHF `setValue`. Typed to editable fields only.
|
|
60
|
+
- `getValues: UseFormGetValues<AllActivityFields<A>>`
|
|
61
|
+
- Returns all field values.
|
|
62
|
+
- `reset: UseFormReset<AllActivityFields<A>>`
|
|
63
|
+
- Resets form to given values or defaults.
|
|
64
|
+
- `trigger: UseFormTrigger<AllActivityFields<A>>`
|
|
65
|
+
- Manually triggers validation for specific or all fields.
|
|
66
|
+
- `control: Control<AllActivityFields<A>>`
|
|
67
|
+
- RHF control for `Controller` components.
|
|
68
|
+
|
|
69
|
+
### Form State
|
|
70
|
+
|
|
71
|
+
- `errors: FieldErrors<AllActivityFields<A>>`
|
|
72
|
+
- Validation errors by field name. Each entry has `type` and `message`.
|
|
73
|
+
- `isValid: boolean`
|
|
74
|
+
- `true` if all fields pass validation.
|
|
75
|
+
- `isDirty: boolean`
|
|
76
|
+
- `true` if any field has been modified.
|
|
77
|
+
- `isSubmitting: boolean`
|
|
78
|
+
- `true` during `handleSubmit` (from button click to API response).
|
|
79
|
+
- `isSubmitSuccessful: boolean`
|
|
80
|
+
- `true` after the last submission succeeded.
|
|
81
|
+
|
|
82
|
+
### Loading & Error
|
|
83
|
+
|
|
84
|
+
- `isLoading: boolean`
|
|
85
|
+
- `true` during initial data + metadata loading. Guard form render on this.
|
|
86
|
+
- `isMetadataLoading: boolean`
|
|
87
|
+
- `true` while BP metadata is being fetched.
|
|
88
|
+
- `loadError: Error | null`
|
|
89
|
+
- Error from `activity.read()`.
|
|
90
|
+
- `hasError: boolean`
|
|
91
|
+
- `true` when `loadError` is non-null.
|
|
92
|
+
|
|
93
|
+
### Other
|
|
94
|
+
|
|
95
|
+
- `bpMetadata: Record<string, unknown> | null`
|
|
96
|
+
- Raw BP metadata blob. `null` while loading.
|
|
97
|
+
- `clearErrors: () => void`
|
|
98
|
+
- Clear all form validation errors.
|
|
99
|
+
|
|
100
|
+
## handleSubmit
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
type HandleSubmitType<TRead> = (
|
|
104
|
+
onSuccess?: (data: TRead, e?: React.BaseSyntheticEvent) => void | Promise<void>,
|
|
105
|
+
onError?: (error: FieldErrors | Error, e?: React.BaseSyntheticEvent) => void | Promise<void>,
|
|
106
|
+
) => (e?: React.BaseSyntheticEvent) => Promise<void>;
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Curried function. Pass to an `onClick` handler: `onClick={handleSubmit(onSuccess, onError)}`.
|
|
110
|
+
|
|
111
|
+
**Behavior:**
|
|
112
|
+
1. Validates all fields via the resolver (type + constraint).
|
|
113
|
+
2. Collects dirty, non-readonly fields and sends them via `activity.update()`.
|
|
114
|
+
3. Calls `activity.complete()` to advance the workflow.
|
|
115
|
+
4. Invokes `onSuccess` with the complete response.
|
|
116
|
+
|
|
117
|
+
- `onSuccess(result, e?)`
|
|
118
|
+
- Called with `CreateUpdateResponseType` (`{ _id: string }`) after the activity is completed and the workflow advances.
|
|
119
|
+
- `onError(error, e?)`
|
|
120
|
+
- Called with `FieldErrors` if validation fails, or `Error` if the API call fails.
|
|
121
|
+
|
|
122
|
+
If no dirty fields exist, the update call is skipped but `complete()` is still called.
|
|
123
|
+
|
|
124
|
+
> Per-field sync handles auto-saving on blur/change. `handleSubmit` is for completing the activity, not saving drafts.
|
|
125
|
+
|
|
126
|
+
## Instance and Field Accessors
|
|
127
|
+
|
|
128
|
+
`item` represents the current activity instance. Each field on `item` is an accessor object.
|
|
129
|
+
|
|
130
|
+
### Instance Members (`item`)
|
|
131
|
+
|
|
132
|
+
- `_id: string | undefined`
|
|
133
|
+
- Current activity instance ID.
|
|
134
|
+
- `toJSON(): Partial<TEditable & TReadonly>`
|
|
135
|
+
- All form values as a plain object.
|
|
136
|
+
- `validate(): Promise<boolean>`
|
|
137
|
+
- Triggers validation for all fields. Returns `true` if valid.
|
|
138
|
+
|
|
139
|
+
### Editable Field (`item.FieldName`)
|
|
140
|
+
|
|
141
|
+
- `get(): T | undefined`
|
|
142
|
+
- Current value from form state.
|
|
143
|
+
- `getOrDefault(fallback: T): T`
|
|
144
|
+
- Value or fallback if null/undefined.
|
|
145
|
+
- `set(value: T): void`
|
|
146
|
+
- Sets the field value.
|
|
147
|
+
- `validate(): ValidationResultType`
|
|
148
|
+
- Validates the current value. Returns `{ valid: boolean, errors: string[] }`.
|
|
149
|
+
- `label: string`
|
|
150
|
+
- Display label from field metadata.
|
|
151
|
+
- `required: boolean`
|
|
152
|
+
- Whether the field is required.
|
|
153
|
+
- `readOnly: boolean`
|
|
154
|
+
- Always `false` for editable fields.
|
|
155
|
+
- `defaultValue: unknown`
|
|
156
|
+
- Default value from metadata.
|
|
157
|
+
- `meta: BaseFieldMetaType`
|
|
158
|
+
- Raw field metadata.
|
|
159
|
+
|
|
160
|
+
### Readonly Field (`item.FieldName`)
|
|
161
|
+
|
|
162
|
+
Same as editable except: no `set()` method, `readOnly` is always `true`.
|
|
163
|
+
|
|
164
|
+
## Types
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
// ---- Generic extraction helpers ----
|
|
168
|
+
|
|
169
|
+
type ExtractActivityEntity<A> =
|
|
170
|
+
A extends Activity<infer E, any, any> ? E : never;
|
|
171
|
+
|
|
172
|
+
type ExtractActivityEditable<A> =
|
|
173
|
+
A extends Activity<any, infer E, any> ? E : never;
|
|
174
|
+
|
|
175
|
+
type ExtractActivityReadonly<A> =
|
|
176
|
+
A extends Activity<any, any, infer R> ? R : never;
|
|
177
|
+
|
|
178
|
+
type AllActivityFields<A> =
|
|
179
|
+
ExtractActivityEditable<A> & ExtractActivityReadonly<A>;
|
|
180
|
+
|
|
181
|
+
// ---- Hook options ----
|
|
182
|
+
|
|
183
|
+
interface UseActivityFormOptions<A extends Activity<any, any, any>> {
|
|
184
|
+
activity_instance_id: string;
|
|
185
|
+
defaultValues?: Partial<ExtractActivityEditable<A>>;
|
|
186
|
+
mode?: "onBlur" | "onChange" | "onSubmit" | "onTouched" | "all";
|
|
187
|
+
enabled?: boolean;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// ---- Hook return type ----
|
|
191
|
+
|
|
192
|
+
interface UseActivityFormReturn<A extends Activity<any, any, any>> {
|
|
193
|
+
item: FormItemType<ExtractActivityEditable<A>, ExtractActivityReadonly<A>>;
|
|
194
|
+
activity: A;
|
|
195
|
+
|
|
196
|
+
register: FormRegisterType<ExtractActivityEditable<A>, ExtractActivityReadonly<A>>;
|
|
197
|
+
handleSubmit: HandleSubmitType<CreateUpdateResponseType>;
|
|
198
|
+
watch: UseFormWatch<AllActivityFields<A>>;
|
|
199
|
+
setValue: UseFormSetValue<ExtractActivityEditable<A>>;
|
|
200
|
+
getValues: UseFormGetValues<AllActivityFields<A>>;
|
|
201
|
+
reset: UseFormReset<AllActivityFields<A>>;
|
|
202
|
+
trigger: UseFormTrigger<AllActivityFields<A>>;
|
|
203
|
+
control: Control<AllActivityFields<A>>;
|
|
204
|
+
|
|
205
|
+
errors: FieldErrors<AllActivityFields<A>>;
|
|
206
|
+
isValid: boolean;
|
|
207
|
+
isDirty: boolean;
|
|
208
|
+
isSubmitting: boolean;
|
|
209
|
+
isSubmitSuccessful: boolean;
|
|
210
|
+
|
|
211
|
+
isLoading: boolean;
|
|
212
|
+
isMetadataLoading: boolean;
|
|
213
|
+
loadError: Error | null;
|
|
214
|
+
hasError: boolean;
|
|
215
|
+
|
|
216
|
+
bpMetadata: Record<string, unknown> | null;
|
|
217
|
+
clearErrors: () => void;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// ---- Shared types ----
|
|
221
|
+
|
|
222
|
+
type HandleSubmitType<TRead = unknown> = (
|
|
223
|
+
onSuccess?: (
|
|
224
|
+
data: TRead,
|
|
225
|
+
e?: React.BaseSyntheticEvent,
|
|
226
|
+
) => void | Promise<void>,
|
|
227
|
+
onError?: (
|
|
228
|
+
error: FieldErrors | Error,
|
|
229
|
+
e?: React.BaseSyntheticEvent,
|
|
230
|
+
) => void | Promise<void>,
|
|
231
|
+
) => (e?: React.BaseSyntheticEvent) => Promise<void>;
|
|
232
|
+
|
|
233
|
+
type FormRegisterType<TEditable, TReadonly> = <
|
|
234
|
+
K extends keyof TEditable | keyof TReadonly | string
|
|
235
|
+
>(
|
|
236
|
+
name: K & string,
|
|
237
|
+
options?: RegisterOptions,
|
|
238
|
+
) => K extends keyof TReadonly
|
|
239
|
+
? UseFormRegisterReturn & { disabled: true }
|
|
240
|
+
: UseFormRegisterReturn;
|
|
241
|
+
|
|
242
|
+
type FormItemType<TEditable, TReadonly> = {
|
|
243
|
+
[K in keyof TEditable]: EditableFormFieldAccessorType<TEditable[K]>;
|
|
244
|
+
} & {
|
|
245
|
+
[K in keyof TReadonly]: ReadonlyFormFieldAccessorType<TReadonly[K]>;
|
|
246
|
+
} & {
|
|
247
|
+
readonly _id: string | undefined;
|
|
248
|
+
toJSON(): Partial<TEditable & TReadonly>;
|
|
249
|
+
validate(): Promise<boolean>;
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
interface EditableFormFieldAccessorType<T> {
|
|
253
|
+
readonly label: string;
|
|
254
|
+
readonly required: boolean;
|
|
255
|
+
readonly readOnly: false;
|
|
256
|
+
readonly defaultValue: unknown;
|
|
257
|
+
readonly meta: BaseFieldMetaType;
|
|
258
|
+
get(): T | undefined;
|
|
259
|
+
getOrDefault(fallback: T): T;
|
|
260
|
+
set(value: T): void;
|
|
261
|
+
validate(): ValidationResultType;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
interface ReadonlyFormFieldAccessorType<T> {
|
|
265
|
+
readonly label: string;
|
|
266
|
+
readonly required: boolean;
|
|
267
|
+
readonly readOnly: true;
|
|
268
|
+
readonly defaultValue: unknown;
|
|
269
|
+
readonly meta: BaseFieldMetaType;
|
|
270
|
+
get(): T | undefined;
|
|
271
|
+
getOrDefault(fallback: T): T;
|
|
272
|
+
validate(): ValidationResultType;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
interface ValidationResultType {
|
|
276
|
+
valid: boolean;
|
|
277
|
+
errors: string[];
|
|
278
|
+
}
|
|
279
|
+
```
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# useActivityTable
|
|
2
|
+
|
|
3
|
+
Activity-integrated table hook for listing workflow instances with search, sorting, filtering, and pagination.
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
|
|
7
|
+
**Use `useActivityTable` when:**
|
|
8
|
+
|
|
9
|
+
- Displaying in-progress or completed workflow activity instances
|
|
10
|
+
- You need search, sort, filter, and/or pagination on activity data
|
|
11
|
+
|
|
12
|
+
**Use something else when:**
|
|
13
|
+
|
|
14
|
+
- Displaying BDO records (not workflow) — use [`useBDOTable`](../useBDOTable/README.md) instead
|
|
15
|
+
- Building a form for an activity instance — use [`useActivityForm`](../useActivityForm/README.md) instead
|
|
16
|
+
|
|
17
|
+
## Imports
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
import { useActivityTable, ActivityTableStatus } from "@ram_28/kf-ai-sdk/workflow";
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
import { useMemo } from "react";
|
|
27
|
+
import { useActivityTable, ActivityTableStatus } from "@ram_28/kf-ai-sdk/workflow";
|
|
28
|
+
import { EmployeeInputActivity } from "@/bdo/workflows/SimpleLeaveProcess";
|
|
29
|
+
|
|
30
|
+
function PendingLeaveRequests() {
|
|
31
|
+
const activity = useMemo(() => new EmployeeInputActivity(), []);
|
|
32
|
+
|
|
33
|
+
const table = useActivityTable({
|
|
34
|
+
activity,
|
|
35
|
+
status: ActivityTableStatus.InProgress,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
if (table.isLoading) return <p>Loading...</p>;
|
|
39
|
+
if (table.error) return <p>Error: {table.error.message}</p>;
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<div>
|
|
43
|
+
<ul>
|
|
44
|
+
{table.rows.map((row) => (
|
|
45
|
+
<li key={row._id}>
|
|
46
|
+
{row.LeaveType.get()} — {row.StartDate.get()} to {row.EndDate.get()}
|
|
47
|
+
</li>
|
|
48
|
+
))}
|
|
49
|
+
</ul>
|
|
50
|
+
|
|
51
|
+
<button
|
|
52
|
+
onClick={table.pagination.goToPrevious}
|
|
53
|
+
disabled={!table.pagination.canGoPrevious}
|
|
54
|
+
>
|
|
55
|
+
Previous
|
|
56
|
+
</button>
|
|
57
|
+
<span>
|
|
58
|
+
Page {table.pagination.pageNo} of {table.pagination.totalPages}
|
|
59
|
+
</span>
|
|
60
|
+
<button
|
|
61
|
+
onClick={table.pagination.goToNext}
|
|
62
|
+
disabled={!table.pagination.canGoNext}
|
|
63
|
+
>
|
|
64
|
+
Next
|
|
65
|
+
</button>
|
|
66
|
+
</div>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Usage Guide
|
|
72
|
+
|
|
73
|
+
### Status Filter
|
|
74
|
+
|
|
75
|
+
Every `useActivityTable` call requires a `status` option that determines which items are fetched:
|
|
76
|
+
|
|
77
|
+
```tsx
|
|
78
|
+
const [status, setStatus] = useState(ActivityTableStatus.InProgress);
|
|
79
|
+
|
|
80
|
+
const table = useActivityTable({
|
|
81
|
+
activity,
|
|
82
|
+
status,
|
|
83
|
+
});
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
- **`ActivityTableStatus.InProgress`** — fetches the in-progress items of the current activity
|
|
87
|
+
- **`ActivityTableStatus.Completed`** — fetches the completed items of the current activity
|
|
88
|
+
- Raw values are `'inprogress'` (all lowercase, no underscore) and `'completed'`
|
|
89
|
+
- Always use the `ActivityTableStatus` constants — never raw strings
|
|
90
|
+
- Changing status re-fetches automatically (status is part of the query key)
|
|
91
|
+
|
|
92
|
+
### Accessing Row Data
|
|
93
|
+
|
|
94
|
+
Rows are `ActivityInstanceType` proxies, not plain objects. Access field values through the `.get()` method on each field accessor:
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
table.rows.map((row) => (
|
|
98
|
+
<tr key={row._id}>
|
|
99
|
+
<td>{row.LeaveType.get()}</td>
|
|
100
|
+
<td>{row.StartDate.get()}</td>
|
|
101
|
+
<td>{row.EndDate.get()}</td>
|
|
102
|
+
<td>{row.LeaveDays.get()}</td>
|
|
103
|
+
<td>{row.Status.get()}</td>
|
|
104
|
+
</tr>
|
|
105
|
+
));
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
- `row._id` is a direct string (no `.get()` needed)
|
|
109
|
+
- `row.LeaveType.get()` returns the field's current value
|
|
110
|
+
- Activity system fields: `row.BPInstanceId.get()`, `row.Status.get()`, `row.AssignedTo.get()`, `row.CompletedAt.get()`
|
|
111
|
+
- `row.toJSON()` converts the entire row to a plain object
|
|
112
|
+
- Editable fields also have `.set()`, but this is typically not used in a table context
|
|
113
|
+
- Persistence methods available on each row: `row.update()`, `row.save()`, `row.complete()`, `row.progress()`
|
|
114
|
+
|
|
115
|
+
### Search
|
|
116
|
+
|
|
117
|
+
Search filters results by matching a query string against a specific field. The input value updates immediately for a responsive UI, while the data fetch is debounced.
|
|
118
|
+
|
|
119
|
+
```tsx
|
|
120
|
+
<input
|
|
121
|
+
type="text"
|
|
122
|
+
placeholder={`Search by ${activity.EmployeeName.label}...`}
|
|
123
|
+
value={table.search.query}
|
|
124
|
+
onChange={(e) => table.search.set(activity.EmployeeName.id, e.target.value)}
|
|
125
|
+
/>
|
|
126
|
+
{table.search.query && (
|
|
127
|
+
<button onClick={table.search.clear}>Clear</button>
|
|
128
|
+
)}
|
|
129
|
+
{table.isFetching && <span>Searching...</span>}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
- **`search.set(field, query)`** — set the field and query text. The data fetch is debounced by 300ms. Pagination resets to page 1.
|
|
133
|
+
- **`search.clear()`** — clear the search field and query. Pagination resets to page 1.
|
|
134
|
+
- **`search.query`** — current query string (updates immediately, API call debounced)
|
|
135
|
+
- **`search.field`** — field currently being searched, or `null`
|
|
136
|
+
- Queries longer than 255 characters are silently ignored.
|
|
137
|
+
|
|
138
|
+
### Sorting
|
|
139
|
+
|
|
140
|
+
Sorting is controlled through the `sort` object. Column headers typically use `toggle()` for click-to-sort behavior:
|
|
141
|
+
|
|
142
|
+
```tsx
|
|
143
|
+
<th
|
|
144
|
+
onClick={() => table.sort.toggle(activity.StartDate.id)}
|
|
145
|
+
style={{ cursor: "pointer" }}
|
|
146
|
+
>
|
|
147
|
+
{activity.StartDate.label}
|
|
148
|
+
{table.sort.field === activity.StartDate.id &&
|
|
149
|
+
(table.sort.direction === "ASC" ? " ↑" : " ↓")}
|
|
150
|
+
</th>
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
- **`sort.toggle(field)`** — cycles through ASC, DESC, then cleared. Toggling a different field starts at ASC.
|
|
154
|
+
- **`sort.set(field, direction)`** — set the sort field and direction directly. Pass `null` for both to clear.
|
|
155
|
+
- **`sort.clear()`** — remove sorting entirely.
|
|
156
|
+
- **`sort.field`** / **`sort.direction`** — current sort state, or `null` when no sort is active.
|
|
157
|
+
- **`initialState.sort`** format is an array of single-key objects: `[{ fieldName: "ASC" }]`.
|
|
158
|
+
|
|
159
|
+
### Filtering
|
|
160
|
+
|
|
161
|
+
The table includes an integrated [`useFilter`](../useFilter/README.md) instance at `table.filter`. Use it to build filter conditions that narrow down the table results:
|
|
162
|
+
|
|
163
|
+
```tsx
|
|
164
|
+
import { ConditionOperator } from "@ram_28/kf-ai-sdk/table";
|
|
165
|
+
|
|
166
|
+
// Filter by leave type
|
|
167
|
+
table.filter.addCondition({
|
|
168
|
+
Operator: ConditionOperator.EQ,
|
|
169
|
+
LHSField: activity.LeaveType.id,
|
|
170
|
+
RHSValue: "PTO",
|
|
171
|
+
RHSType: "Constant",
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// Date range filter
|
|
175
|
+
table.filter.addCondition({
|
|
176
|
+
Operator: ConditionOperator.GTE,
|
|
177
|
+
LHSField: activity.StartDate.id,
|
|
178
|
+
RHSValue: "2026-01-01",
|
|
179
|
+
RHSType: "Constant",
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// Clear all filters
|
|
183
|
+
table.filter.clearAllConditions();
|
|
184
|
+
|
|
185
|
+
// Check if any filters are active
|
|
186
|
+
if (table.filter.hasConditions) {
|
|
187
|
+
// ...
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
- **`table.filter.addCondition(condition)`** — add a filter condition
|
|
192
|
+
- **`table.filter.clearAllConditions()`** — remove all filter conditions
|
|
193
|
+
- **`table.filter.hasConditions`** — `true` if any conditions are active
|
|
194
|
+
- Filter changes automatically reset pagination to page 1, preventing empty pages after narrowing results.
|
|
195
|
+
- See the [useFilter documentation](../useFilter/README.md) for the full filter API.
|
|
196
|
+
|
|
197
|
+
### Pagination
|
|
198
|
+
|
|
199
|
+
Pages are 1-indexed (they start at 1, not 0). The default page is 1 and the default page size is 10.
|
|
200
|
+
|
|
201
|
+
```tsx
|
|
202
|
+
<div>
|
|
203
|
+
<button
|
|
204
|
+
onClick={table.pagination.goToPrevious}
|
|
205
|
+
disabled={!table.pagination.canGoPrevious}
|
|
206
|
+
>
|
|
207
|
+
Previous
|
|
208
|
+
</button>
|
|
209
|
+
<span>
|
|
210
|
+
Page {table.pagination.pageNo} of {table.pagination.totalPages}
|
|
211
|
+
{" "}({table.pagination.totalItems} total)
|
|
212
|
+
</span>
|
|
213
|
+
<button
|
|
214
|
+
onClick={table.pagination.goToNext}
|
|
215
|
+
disabled={!table.pagination.canGoNext}
|
|
216
|
+
>
|
|
217
|
+
Next
|
|
218
|
+
</button>
|
|
219
|
+
</div>
|
|
220
|
+
|
|
221
|
+
<select
|
|
222
|
+
value={table.pagination.pageSize}
|
|
223
|
+
onChange={(e) => table.pagination.setPageSize(Number(e.target.value))}
|
|
224
|
+
>
|
|
225
|
+
<option value={10}>10</option>
|
|
226
|
+
<option value={25}>25</option>
|
|
227
|
+
<option value={50}>50</option>
|
|
228
|
+
</select>
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
- **`pagination.goToNext()`** / **`pagination.goToPrevious()`** — navigate forward/backward. No-op at boundaries.
|
|
232
|
+
- **`pagination.goToPage(n)`** — jump to a specific page. Clamped to `[1, totalPages]`.
|
|
233
|
+
- **`pagination.canGoNext`** / **`pagination.canGoPrevious`** — whether navigation is possible.
|
|
234
|
+
- **`pagination.setPageSize(n)`** — change the page size. Resets to page 1.
|
|
235
|
+
- **`pagination.pageNo`** / **`pagination.pageSize`** / **`pagination.totalPages`** / **`pagination.totalItems`** — current pagination state.
|
|
236
|
+
|
|
237
|
+
### Refetching
|
|
238
|
+
|
|
239
|
+
Call `refetch()` to manually refresh the table data. This refetches both the list and the count:
|
|
240
|
+
|
|
241
|
+
```tsx
|
|
242
|
+
const handleComplete = async (row) => {
|
|
243
|
+
await row.complete();
|
|
244
|
+
table.refetch();
|
|
245
|
+
};
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
This is the standard pattern after any mutation (complete, update, save) that should be reflected in the table. Also use `table.refetch()` after closing a form dialog that modifies an activity instance.
|
|
249
|
+
|
|
250
|
+
## Further Reading
|
|
251
|
+
|
|
252
|
+
- [API Reference](./api_reference.md) — All options, return values, and type definitions
|
|
253
|
+
- [My Pending Requests](../examples/workflow/my-pending-requests.md) — In Progress / Completed tabs
|
|
254
|
+
- [Filtered Activity Table](../examples/workflow/filtered-activity-table.md) — Date range filter on activities
|
|
255
|
+
|
|
256
|
+
## Common Mistakes
|
|
257
|
+
|
|
258
|
+
- **Don't forget `useMemo` on the Activity instance.** `new ActivityClass()` must be wrapped in `useMemo(() => ..., [])`. Re-creating the instance on every render causes infinite refetching.
|
|
259
|
+
- **Don't access row fields directly.** `row.LeaveType` is an accessor object, not the value. Use `row.LeaveType.get()` to read the value.
|
|
260
|
+
- **Don't use raw strings for status.** Use `ActivityTableStatus.InProgress` and `ActivityTableStatus.Completed`, not `'inProgress'` or `'in_progress'`.
|
|
261
|
+
- **Don't use 0-indexed pagination.** Pages start at 1. Passing `pageNo: 0` will produce incorrect results.
|
|
262
|
+
- **Don't forget to guard on `isLoading` before rendering rows.** While loading, `rows` is an empty array. Guard with `if (table.isLoading) return <Loading />` to avoid rendering an empty table.
|
|
263
|
+
- **Don't hardcode field names as strings.** Use the activity field IDs (`activity.StartDate.id`) instead of raw strings (`"StartDate"`). This keeps your code type-safe and resilient to field renames.
|