@contractspec/lib.presentation-runtime-react 10.0.1 → 12.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/WorkflowStepRenderer.d.ts +14 -30
- package/dist/WorkflowStepRenderer.d.ts.map +1 -1
- package/dist/WorkflowStepRenderer.js +131 -101
- package/dist/WorkflowStepper.d.ts +7 -17
- package/dist/WorkflowStepper.d.ts.map +1 -1
- package/dist/WorkflowStepper.js +48 -35
- package/dist/browser/WorkflowStepRenderer.js +132 -0
- package/dist/browser/WorkflowStepper.js +51 -0
- package/dist/browser/index.js +366 -0
- package/dist/browser/nativewind-env.d.js +0 -0
- package/dist/browser/useWorkflow.js +78 -0
- package/dist/index.d.ts +88 -106
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +363 -126
- package/dist/nativewind-env.d.js +1 -0
- package/dist/useWorkflow.d.ts +15 -24
- package/dist/useWorkflow.d.ts.map +1 -1
- package/dist/useWorkflow.js +77 -77
- package/package.json +50 -22
- package/dist/WorkflowStepRenderer.js.map +0 -1
- package/dist/WorkflowStepper.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/nativewind-env.d.ts +0 -1
- package/dist/useWorkflow.js.map +0 -1
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,130 +1,367 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
|
|
1
|
+
// @bun
|
|
2
|
+
// src/WorkflowStepRenderer.tsx
|
|
3
|
+
import { EmptyState, LoaderBlock } from "@contractspec/lib.design-system";
|
|
4
|
+
import { jsxDEV } from "react/jsx-dev-runtime";
|
|
5
|
+
function WorkflowStepRenderer({
|
|
6
|
+
spec,
|
|
7
|
+
state,
|
|
8
|
+
className,
|
|
9
|
+
renderHumanStep,
|
|
10
|
+
renderAutomationStep,
|
|
11
|
+
renderDecisionStep,
|
|
12
|
+
loadingFallback,
|
|
13
|
+
completedFallback,
|
|
14
|
+
cancelledFallback,
|
|
15
|
+
failedFallback
|
|
16
|
+
}) {
|
|
17
|
+
const steps = spec.definition.steps;
|
|
18
|
+
if (!steps.length) {
|
|
19
|
+
return /* @__PURE__ */ jsxDEV("div", {
|
|
20
|
+
className,
|
|
21
|
+
children: /* @__PURE__ */ jsxDEV(EmptyState, {
|
|
22
|
+
title: "No steps defined",
|
|
23
|
+
description: "Add at least one step to this workflow to render it."
|
|
24
|
+
}, undefined, false, undefined, this)
|
|
25
|
+
}, undefined, false, undefined, this);
|
|
26
|
+
}
|
|
27
|
+
if (!state) {
|
|
28
|
+
return /* @__PURE__ */ jsxDEV("div", {
|
|
29
|
+
className,
|
|
30
|
+
children: loadingFallback ?? /* @__PURE__ */ jsxDEV(LoaderBlock, {
|
|
31
|
+
label: "Loading workflow",
|
|
32
|
+
description: "Fetching workflow state..."
|
|
33
|
+
}, undefined, false, undefined, this)
|
|
34
|
+
}, undefined, false, undefined, this);
|
|
35
|
+
}
|
|
36
|
+
const lastExecution = state.history.at(-1);
|
|
37
|
+
if (state.status === "failed") {
|
|
38
|
+
return /* @__PURE__ */ jsxDEV("div", {
|
|
39
|
+
className,
|
|
40
|
+
children: failedFallback?.(state, lastExecution) ?? /* @__PURE__ */ jsxDEV(EmptyState, {
|
|
41
|
+
title: "Workflow failed",
|
|
42
|
+
description: lastExecution?.error ?? "Fix the underlying issue and retry the step."
|
|
43
|
+
}, undefined, false, undefined, this)
|
|
44
|
+
}, undefined, false, undefined, this);
|
|
45
|
+
}
|
|
46
|
+
if (state.status === "cancelled") {
|
|
47
|
+
return /* @__PURE__ */ jsxDEV("div", {
|
|
48
|
+
className,
|
|
49
|
+
children: cancelledFallback ?? /* @__PURE__ */ jsxDEV(EmptyState, {
|
|
50
|
+
title: "Workflow cancelled",
|
|
51
|
+
description: "This workflow has been cancelled. Restart it to resume."
|
|
52
|
+
}, undefined, false, undefined, this)
|
|
53
|
+
}, undefined, false, undefined, this);
|
|
54
|
+
}
|
|
55
|
+
if (state.status === "completed") {
|
|
56
|
+
return /* @__PURE__ */ jsxDEV("div", {
|
|
57
|
+
className,
|
|
58
|
+
children: completedFallback ?? /* @__PURE__ */ jsxDEV(EmptyState, {
|
|
59
|
+
title: "Workflow complete",
|
|
60
|
+
description: "All steps have been executed successfully."
|
|
61
|
+
}, undefined, false, undefined, this)
|
|
62
|
+
}, undefined, false, undefined, this);
|
|
63
|
+
}
|
|
64
|
+
const activeStep = steps.find((step) => step.id === state.currentStep) ?? steps[0];
|
|
65
|
+
if (!activeStep) {
|
|
66
|
+
return /* @__PURE__ */ jsxDEV("div", {
|
|
67
|
+
className,
|
|
68
|
+
children: /* @__PURE__ */ jsxDEV(EmptyState, {
|
|
69
|
+
title: "No active step",
|
|
70
|
+
description: "This workflow has no active step."
|
|
71
|
+
}, undefined, false, undefined, this)
|
|
72
|
+
}, undefined, false, undefined, this);
|
|
73
|
+
}
|
|
74
|
+
switch (activeStep.type) {
|
|
75
|
+
case "human": {
|
|
76
|
+
const form = activeStep.action?.form;
|
|
77
|
+
if (form && renderHumanStep) {
|
|
78
|
+
return /* @__PURE__ */ jsxDEV("div", {
|
|
79
|
+
className,
|
|
80
|
+
children: renderHumanStep(form, activeStep)
|
|
81
|
+
}, undefined, false, undefined, this);
|
|
82
|
+
}
|
|
83
|
+
return /* @__PURE__ */ jsxDEV("div", {
|
|
84
|
+
className,
|
|
85
|
+
children: /* @__PURE__ */ jsxDEV(EmptyState, {
|
|
86
|
+
title: "Form renderer missing",
|
|
87
|
+
description: "Provide renderHumanStep to render this human step's form."
|
|
88
|
+
}, undefined, false, undefined, this)
|
|
89
|
+
}, undefined, false, undefined, this);
|
|
90
|
+
}
|
|
91
|
+
case "automation": {
|
|
92
|
+
if (renderAutomationStep) {
|
|
93
|
+
return /* @__PURE__ */ jsxDEV("div", {
|
|
94
|
+
className,
|
|
95
|
+
children: renderAutomationStep(activeStep)
|
|
96
|
+
}, undefined, false, undefined, this);
|
|
97
|
+
}
|
|
98
|
+
return /* @__PURE__ */ jsxDEV("div", {
|
|
99
|
+
className,
|
|
100
|
+
children: /* @__PURE__ */ jsxDEV(EmptyState, {
|
|
101
|
+
title: "Automation step in progress",
|
|
102
|
+
description: `Waiting for automation "${activeStep.label}" to finish.`
|
|
103
|
+
}, undefined, false, undefined, this)
|
|
104
|
+
}, undefined, false, undefined, this);
|
|
105
|
+
}
|
|
106
|
+
case "decision": {
|
|
107
|
+
if (renderDecisionStep) {
|
|
108
|
+
return /* @__PURE__ */ jsxDEV("div", {
|
|
109
|
+
className,
|
|
110
|
+
children: renderDecisionStep(activeStep)
|
|
111
|
+
}, undefined, false, undefined, this);
|
|
112
|
+
}
|
|
113
|
+
return /* @__PURE__ */ jsxDEV("div", {
|
|
114
|
+
className,
|
|
115
|
+
children: /* @__PURE__ */ jsxDEV(EmptyState, {
|
|
116
|
+
title: "Decision step awaiting input",
|
|
117
|
+
description: "Provide a custom decision renderer via renderDecisionStep."
|
|
118
|
+
}, undefined, false, undefined, this)
|
|
119
|
+
}, undefined, false, undefined, this);
|
|
120
|
+
}
|
|
121
|
+
default:
|
|
122
|
+
return /* @__PURE__ */ jsxDEV("div", {
|
|
123
|
+
className,
|
|
124
|
+
children: /* @__PURE__ */ jsxDEV(EmptyState, {
|
|
125
|
+
title: "Unknown step type",
|
|
126
|
+
description: `Step "${activeStep.id}" has an unsupported type.`
|
|
127
|
+
}, undefined, false, undefined, this)
|
|
128
|
+
}, undefined, false, undefined, this);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
6
131
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
setData(out.items);
|
|
45
|
-
setTotalItems(out.totalItems);
|
|
46
|
-
setTotalPages(out.totalPages);
|
|
47
|
-
} catch (e) {
|
|
48
|
-
setError(e);
|
|
49
|
-
} finally {
|
|
50
|
-
setLoading(false);
|
|
51
|
-
}
|
|
52
|
-
}, [variables, fetcher]);
|
|
53
|
-
React.useEffect(() => {
|
|
54
|
-
refetch();
|
|
55
|
-
}, [refetch]);
|
|
56
|
-
return {
|
|
57
|
-
form,
|
|
58
|
-
url,
|
|
59
|
-
variables,
|
|
60
|
-
data,
|
|
61
|
-
loading,
|
|
62
|
-
error,
|
|
63
|
-
totalItems,
|
|
64
|
-
totalPages,
|
|
65
|
-
refetch,
|
|
66
|
-
chips: React.useMemo(() => toChips ? toChips(url.state.filters || {}, url.setFilter) : [], [url.state.filters, toChips]),
|
|
67
|
-
setSearch,
|
|
68
|
-
submitFilters,
|
|
69
|
-
clearAll: React.useCallback(() => {
|
|
70
|
-
form.reset(formOpts.defaultValues);
|
|
71
|
-
url.setState({
|
|
72
|
-
filters: {},
|
|
73
|
-
page: 1
|
|
74
|
-
});
|
|
75
|
-
}, [
|
|
76
|
-
form,
|
|
77
|
-
formOpts.defaultValues,
|
|
78
|
-
url
|
|
79
|
-
])
|
|
80
|
-
};
|
|
132
|
+
// src/WorkflowStepper.tsx
|
|
133
|
+
import { Stepper } from "@contractspec/lib.design-system";
|
|
134
|
+
import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
|
|
135
|
+
function WorkflowStepper({
|
|
136
|
+
spec,
|
|
137
|
+
state,
|
|
138
|
+
className,
|
|
139
|
+
showLabels = false
|
|
140
|
+
}) {
|
|
141
|
+
const steps = spec.definition.steps;
|
|
142
|
+
const total = steps.length;
|
|
143
|
+
const current = computeCurrent(steps, state);
|
|
144
|
+
return /* @__PURE__ */ jsxDEV2("div", {
|
|
145
|
+
className: ["flex flex-col gap-2", className].filter(Boolean).join(" "),
|
|
146
|
+
children: [
|
|
147
|
+
/* @__PURE__ */ jsxDEV2(Stepper, {
|
|
148
|
+
current,
|
|
149
|
+
total
|
|
150
|
+
}, undefined, false, undefined, this),
|
|
151
|
+
showLabels && total > 0 && /* @__PURE__ */ jsxDEV2("ol", {
|
|
152
|
+
className: "text-muted-foreground flex flex-wrap gap-2 text-sm",
|
|
153
|
+
children: steps.map((step, index) => {
|
|
154
|
+
const isActive = state?.status === "completed" ? index === total - 1 : step.id === state?.currentStep;
|
|
155
|
+
return /* @__PURE__ */ jsxDEV2("li", {
|
|
156
|
+
className: [
|
|
157
|
+
"rounded border px-2 py-1",
|
|
158
|
+
isActive ? "border-primary text-primary" : "border-border"
|
|
159
|
+
].join(" "),
|
|
160
|
+
children: /* @__PURE__ */ jsxDEV2("span", {
|
|
161
|
+
className: "font-medium",
|
|
162
|
+
children: step.label
|
|
163
|
+
}, undefined, false, undefined, this)
|
|
164
|
+
}, step.id, false, undefined, this);
|
|
165
|
+
})
|
|
166
|
+
}, undefined, false, undefined, this)
|
|
167
|
+
]
|
|
168
|
+
}, undefined, true, undefined, this);
|
|
81
169
|
}
|
|
82
|
-
function
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
React.useEffect(() => {
|
|
92
|
-
form.reset({
|
|
93
|
-
...form.getValues(),
|
|
94
|
-
...url.state.filters
|
|
95
|
-
});
|
|
96
|
-
}, [url.state.filters]);
|
|
97
|
-
const submitFilters = form.handleSubmit((values) => {
|
|
98
|
-
url.setState({
|
|
99
|
-
filters: values,
|
|
100
|
-
page: 1
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
const setSearch = React.useCallback((q) => url.setState({
|
|
104
|
-
q,
|
|
105
|
-
page: 1
|
|
106
|
-
}), [url]);
|
|
107
|
-
return {
|
|
108
|
-
form,
|
|
109
|
-
url,
|
|
110
|
-
variables: React.useMemo(() => toVariables(url.state), [url.state, toVariables]),
|
|
111
|
-
chips: React.useMemo(() => toChips ? toChips(url.state.filters || {}, url.setFilter) : [], [url.state.filters, toChips]),
|
|
112
|
-
setSearch,
|
|
113
|
-
submitFilters,
|
|
114
|
-
clearAll: React.useCallback(() => {
|
|
115
|
-
form.reset(formOpts.defaultValues);
|
|
116
|
-
url.setState({
|
|
117
|
-
filters: {},
|
|
118
|
-
page: 1
|
|
119
|
-
});
|
|
120
|
-
}, [
|
|
121
|
-
form,
|
|
122
|
-
formOpts.defaultValues,
|
|
123
|
-
url
|
|
124
|
-
])
|
|
125
|
-
};
|
|
170
|
+
function computeCurrent(steps, state) {
|
|
171
|
+
if (!steps.length)
|
|
172
|
+
return 0;
|
|
173
|
+
if (!state)
|
|
174
|
+
return 1;
|
|
175
|
+
if (state.status === "completed")
|
|
176
|
+
return steps.length;
|
|
177
|
+
const idx = steps.findIndex((step) => step.id === state.currentStep);
|
|
178
|
+
return idx === -1 ? 1 : idx + 1;
|
|
126
179
|
}
|
|
127
180
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
181
|
+
// src/useWorkflow.ts
|
|
182
|
+
import * as React from "react";
|
|
183
|
+
function useWorkflow({
|
|
184
|
+
workflowId,
|
|
185
|
+
runner,
|
|
186
|
+
autoRefresh = true,
|
|
187
|
+
refreshIntervalMs = 2000
|
|
188
|
+
}) {
|
|
189
|
+
const isMounted = React.useRef(true);
|
|
190
|
+
const [state, setState] = React.useState(null);
|
|
191
|
+
const [isLoading, setIsLoading] = React.useState(true);
|
|
192
|
+
const [error, setError] = React.useState(null);
|
|
193
|
+
const [isExecuting, setIsExecuting] = React.useState(false);
|
|
194
|
+
const refresh = React.useCallback(async () => {
|
|
195
|
+
try {
|
|
196
|
+
setIsLoading(true);
|
|
197
|
+
const next = await runner.getState(workflowId);
|
|
198
|
+
if (!isMounted.current)
|
|
199
|
+
return;
|
|
200
|
+
setState(next);
|
|
201
|
+
setError(null);
|
|
202
|
+
} catch (err) {
|
|
203
|
+
if (!isMounted.current)
|
|
204
|
+
return;
|
|
205
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
206
|
+
} finally {
|
|
207
|
+
if (isMounted.current)
|
|
208
|
+
setIsLoading(false);
|
|
209
|
+
}
|
|
210
|
+
}, [runner, workflowId]);
|
|
211
|
+
const executeStep = React.useCallback(async (input) => {
|
|
212
|
+
setIsExecuting(true);
|
|
213
|
+
try {
|
|
214
|
+
await runner.executeStep(workflowId, input);
|
|
215
|
+
await refresh();
|
|
216
|
+
} catch (err) {
|
|
217
|
+
if (isMounted.current) {
|
|
218
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
219
|
+
}
|
|
220
|
+
throw err;
|
|
221
|
+
} finally {
|
|
222
|
+
if (isMounted.current)
|
|
223
|
+
setIsExecuting(false);
|
|
224
|
+
}
|
|
225
|
+
}, [runner, workflowId, refresh]);
|
|
226
|
+
const cancel = React.useCallback(async () => {
|
|
227
|
+
await runner.cancel(workflowId);
|
|
228
|
+
await refresh();
|
|
229
|
+
}, [runner, workflowId, refresh]);
|
|
230
|
+
React.useEffect(() => {
|
|
231
|
+
isMounted.current = true;
|
|
232
|
+
refresh();
|
|
233
|
+
if (!autoRefresh) {
|
|
234
|
+
return () => {
|
|
235
|
+
isMounted.current = false;
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
const interval = setInterval(() => {
|
|
239
|
+
refresh();
|
|
240
|
+
}, refreshIntervalMs);
|
|
241
|
+
return () => {
|
|
242
|
+
isMounted.current = false;
|
|
243
|
+
clearInterval(interval);
|
|
244
|
+
};
|
|
245
|
+
}, [refresh, autoRefresh, refreshIntervalMs]);
|
|
246
|
+
return {
|
|
247
|
+
state,
|
|
248
|
+
isLoading,
|
|
249
|
+
error,
|
|
250
|
+
isExecuting,
|
|
251
|
+
refresh,
|
|
252
|
+
executeStep,
|
|
253
|
+
cancel
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// src/index.ts
|
|
258
|
+
import * as React2 from "react";
|
|
259
|
+
import { useForm } from "@contractspec/lib.ui-kit-web/ui/form";
|
|
260
|
+
function usePresentationController({
|
|
261
|
+
defaults,
|
|
262
|
+
form: formOpts,
|
|
263
|
+
toVariables,
|
|
264
|
+
fetcher,
|
|
265
|
+
toChips,
|
|
266
|
+
useUrlState,
|
|
267
|
+
replace
|
|
268
|
+
}) {
|
|
269
|
+
const url = useUrlState({ defaults, replace });
|
|
270
|
+
const form = useForm({
|
|
271
|
+
defaultValues: formOpts.defaultValues,
|
|
272
|
+
resolver: formOpts.resolver
|
|
273
|
+
});
|
|
274
|
+
React2.useEffect(() => {
|
|
275
|
+
form.reset({ ...form.getValues(), ...url.state.filters });
|
|
276
|
+
}, [url.state.filters]);
|
|
277
|
+
const submitFilters = form.handleSubmit((values) => {
|
|
278
|
+
url.setState({ filters: values, page: 1 });
|
|
279
|
+
});
|
|
280
|
+
const setSearch = React2.useCallback((q) => url.setState({ q, page: 1 }), [url]);
|
|
281
|
+
const variables = React2.useMemo(() => toVariables(url.state), [url.state, toVariables]);
|
|
282
|
+
const [data, setData] = React2.useState([]);
|
|
283
|
+
const [loading, setLoading] = React2.useState(false);
|
|
284
|
+
const [error, setError] = React2.useState(null);
|
|
285
|
+
const [totalItems, setTotalItems] = React2.useState(undefined);
|
|
286
|
+
const [totalPages, setTotalPages] = React2.useState(undefined);
|
|
287
|
+
const refetch = React2.useCallback(async () => {
|
|
288
|
+
setLoading(true);
|
|
289
|
+
setError(null);
|
|
290
|
+
try {
|
|
291
|
+
const out = await fetcher(variables);
|
|
292
|
+
setData(out.items);
|
|
293
|
+
setTotalItems(out.totalItems);
|
|
294
|
+
setTotalPages(out.totalPages);
|
|
295
|
+
} catch (e) {
|
|
296
|
+
setError(e);
|
|
297
|
+
} finally {
|
|
298
|
+
setLoading(false);
|
|
299
|
+
}
|
|
300
|
+
}, [variables, fetcher]);
|
|
301
|
+
React2.useEffect(() => {
|
|
302
|
+
refetch();
|
|
303
|
+
}, [refetch]);
|
|
304
|
+
const chips = React2.useMemo(() => toChips ? toChips(url.state.filters || {}, url.setFilter) : [], [url.state.filters, toChips]);
|
|
305
|
+
const clearAll = React2.useCallback(() => {
|
|
306
|
+
form.reset(formOpts.defaultValues);
|
|
307
|
+
url.setState({ filters: {}, page: 1 });
|
|
308
|
+
}, [form, formOpts.defaultValues, url]);
|
|
309
|
+
return {
|
|
310
|
+
form,
|
|
311
|
+
url,
|
|
312
|
+
variables,
|
|
313
|
+
data,
|
|
314
|
+
loading,
|
|
315
|
+
error,
|
|
316
|
+
totalItems,
|
|
317
|
+
totalPages,
|
|
318
|
+
refetch,
|
|
319
|
+
chips,
|
|
320
|
+
setSearch,
|
|
321
|
+
submitFilters,
|
|
322
|
+
clearAll
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
function useListCoordinator({
|
|
326
|
+
defaults,
|
|
327
|
+
form: formOpts,
|
|
328
|
+
toVariables,
|
|
329
|
+
toChips,
|
|
330
|
+
useUrlState,
|
|
331
|
+
replace
|
|
332
|
+
}) {
|
|
333
|
+
const url = useUrlState({ defaults, replace });
|
|
334
|
+
const form = useForm({
|
|
335
|
+
defaultValues: formOpts.defaultValues,
|
|
336
|
+
resolver: formOpts.resolver
|
|
337
|
+
});
|
|
338
|
+
React2.useEffect(() => {
|
|
339
|
+
form.reset({ ...form.getValues(), ...url.state.filters });
|
|
340
|
+
}, [url.state.filters]);
|
|
341
|
+
const submitFilters = form.handleSubmit((values) => {
|
|
342
|
+
url.setState({ filters: values, page: 1 });
|
|
343
|
+
});
|
|
344
|
+
const setSearch = React2.useCallback((q) => url.setState({ q, page: 1 }), [url]);
|
|
345
|
+
const variables = React2.useMemo(() => toVariables(url.state), [url.state, toVariables]);
|
|
346
|
+
const chips = React2.useMemo(() => toChips ? toChips(url.state.filters || {}, url.setFilter) : [], [url.state.filters, toChips]);
|
|
347
|
+
const clearAll = React2.useCallback(() => {
|
|
348
|
+
form.reset(formOpts.defaultValues);
|
|
349
|
+
url.setState({ filters: {}, page: 1 });
|
|
350
|
+
}, [form, formOpts.defaultValues, url]);
|
|
351
|
+
return {
|
|
352
|
+
form,
|
|
353
|
+
url,
|
|
354
|
+
variables,
|
|
355
|
+
chips,
|
|
356
|
+
setSearch,
|
|
357
|
+
submitFilters,
|
|
358
|
+
clearAll
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
export {
|
|
362
|
+
useWorkflow,
|
|
363
|
+
usePresentationController,
|
|
364
|
+
useListCoordinator,
|
|
365
|
+
WorkflowStepper,
|
|
366
|
+
WorkflowStepRenderer
|
|
367
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// @bun
|
package/dist/useWorkflow.d.ts
CHANGED
|
@@ -1,27 +1,18 @@
|
|
|
1
|
-
import { WorkflowRunner, WorkflowState } from
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
autoRefresh?: boolean;
|
|
8
|
-
refreshIntervalMs?: number;
|
|
1
|
+
import type { WorkflowRunner, WorkflowState } from '@contractspec/lib.contracts/workflow';
|
|
2
|
+
export interface UseWorkflowOptions {
|
|
3
|
+
workflowId: string;
|
|
4
|
+
runner: WorkflowRunner;
|
|
5
|
+
autoRefresh?: boolean;
|
|
6
|
+
refreshIntervalMs?: number;
|
|
9
7
|
}
|
|
10
|
-
interface UseWorkflowResult {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
8
|
+
export interface UseWorkflowResult {
|
|
9
|
+
state: WorkflowState | null;
|
|
10
|
+
isLoading: boolean;
|
|
11
|
+
error: Error | null;
|
|
12
|
+
isExecuting: boolean;
|
|
13
|
+
refresh: () => Promise<void>;
|
|
14
|
+
executeStep: (input?: unknown) => Promise<void>;
|
|
15
|
+
cancel: () => Promise<void>;
|
|
18
16
|
}
|
|
19
|
-
declare function useWorkflow({
|
|
20
|
-
workflowId,
|
|
21
|
-
runner,
|
|
22
|
-
autoRefresh,
|
|
23
|
-
refreshIntervalMs
|
|
24
|
-
}: UseWorkflowOptions): UseWorkflowResult;
|
|
25
|
-
//#endregion
|
|
26
|
-
export { UseWorkflowOptions, UseWorkflowResult, useWorkflow };
|
|
17
|
+
export declare function useWorkflow({ workflowId, runner, autoRefresh, refreshIntervalMs, }: UseWorkflowOptions): UseWorkflowResult;
|
|
27
18
|
//# sourceMappingURL=useWorkflow.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useWorkflow.d.ts","
|
|
1
|
+
{"version":3,"file":"useWorkflow.d.ts","sourceRoot":"","sources":["../src/useWorkflow.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EACd,MAAM,sCAAsC,CAAC;AAE9C,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,cAAc,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,WAAW,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7B;AAED,wBAAgB,WAAW,CAAC,EAC1B,UAAU,EACV,MAAM,EACN,WAAkB,EAClB,iBAAwB,GACzB,EAAE,kBAAkB,GAAG,iBAAiB,CAuExC"}
|