@sanity/workflow-studio-plugin 0.4.0 → 0.5.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.
@@ -1,16 +1,20 @@
1
1
  "use strict";
2
2
 
3
- var jsxRuntime = require("react/jsx-runtime"), ui = require("@sanity/ui"), react = require("react"), router = require("sanity/router"), index = require("./index.cjs"), ChevronDown = require("@sanity/icons/ChevronDown"), ChevronRight = require("@sanity/icons/ChevronRight"), workflowEngine = require("@sanity/workflow-engine"), Checkmark = require("@sanity/icons/Checkmark"), Close = require("@sanity/icons/Close"), Filter = require("@sanity/icons/Filter"), workflowComponents = require("@sanity/workflow-components"), endOfDay = require("date-fns/endOfDay"), sanity = require("sanity"), workflowStudio = require("@sanity/workflow-studio"), ArrowLeft = require("@sanity/icons/ArrowLeft"), workflowDiagram = require("@sanity/workflow-diagram"), Add = require("@sanity/icons/Add"), Search = require("@sanity/icons/Search"), EllipsisHorizontal = require("@sanity/icons/EllipsisHorizontal");
3
+ var jsxRuntime = require("react/jsx-runtime"), ui = require("@sanity/ui"), react = require("react"), router = require("sanity/router"), index = require("./index.cjs"), ArrowLeft = require("@sanity/icons/ArrowLeft"), workflowDiagram = require("@sanity/workflow-diagram"), workflowEngine = require("@sanity/workflow-engine"), Add = require("@sanity/icons/Add"), Search = require("@sanity/icons/Search"), Checkmark = require("@sanity/icons/Checkmark"), Close = require("@sanity/icons/Close"), Filter = require("@sanity/icons/Filter"), workflowComponents = require("@sanity/workflow-components"), endOfDay = require("date-fns/endOfDay"), reactDom = require("react-dom"), sanity = require("sanity"), Calendar = require("@sanity/icons/Calendar"), workflowStudio = require("@sanity/workflow-studio");
4
4
 
5
- function MutedNote({text: text}) {
5
+ function SpinnerSlot({busy: busy}) {
6
6
  /* @__PURE__ */
7
- return jsxRuntime.jsx(ui.Box, {
8
- paddingY: 3,
9
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
10
- muted: !0,
11
- size: 1,
12
- children: text
13
- })
7
+ return jsxRuntime.jsx(ui.Flex, {
8
+ align: "center",
9
+ flex: "none",
10
+ justify: "center",
11
+ style: {
12
+ width: 19,
13
+ height: 19
14
+ },
15
+ children: busy ? /* @__PURE__ */ jsxRuntime.jsx(ui.Spinner, {
16
+ muted: !0
17
+ }) : null
14
18
  });
15
19
  }
16
20
 
@@ -20,70 +24,419 @@ function documentRefsOf(instance) {
20
24
  return [ ...seen.values() ];
21
25
  }
22
26
 
23
- function RefChips({refs: refs, max: max = 2}) {
24
- if (refs.length === 0) return null;
25
- const shown = refs.slice(0, max), overflow = refs.length - shown.length;
27
+ function InstanceTaskLists({entry: entry, onOpenActivity: onOpenActivity}) {
28
+ return index.instanceNotice(entry) || /* @__PURE__ */ jsxRuntime.jsx(index.StaleLock, {
29
+ stale: index.isEvaluationStale(entry),
30
+ children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
31
+ children: [
32
+ /* @__PURE__ */ jsxRuntime.jsx(index.ActivitiesList, {
33
+ entry: entry,
34
+ onOpenActivity: onOpenActivity
35
+ }),
36
+ /* @__PURE__ */ jsxRuntime.jsx(index.TodoItemsList, {
37
+ entry: entry
38
+ }) ]
39
+ })
40
+ });
41
+ }
42
+
43
+ function WorkflowInstanceDetail({instanceId: instanceId, onBack: onBack}) {
44
+ const entry = index.useWorkflowInstanceEntry(instanceId), [graceOver, setGraceOver] = react.useState(!1);
45
+ return react.useEffect(() => {
46
+ const timer = setTimeout(() => setGraceOver(!0), 2500);
47
+ return () => clearTimeout(timer);
48
+ }, [ instanceId ]), entry?.invalid ? /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
49
+ padding: 4,
50
+ children: /* @__PURE__ */ jsxRuntime.jsx(index.InvalidDocNotice, {
51
+ invalid: entry.invalid
52
+ })
53
+ }) : entry ? /* @__PURE__ */ jsxRuntime.jsx(InstanceDetailPanel, {
54
+ entry: entry,
55
+ onBack: onBack
56
+ }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
57
+ padding: 4,
58
+ children: graceOver ? /* @__PURE__ */ jsxRuntime.jsx(NotFound, {
59
+ id: instanceId,
60
+ onBack: onBack
61
+ }) : /* @__PURE__ */ jsxRuntime.jsx(index.LoadingRow, {
62
+ label: "Loading workflow…"
63
+ })
64
+ });
65
+ }
66
+
67
+ function NotFound({id: id, onBack: onBack}) {
26
68
  /* @__PURE__ */
27
- return jsxRuntime.jsxs(ui.Flex, {
28
- align: "center",
29
- gap: 3,
30
- wrap: "wrap",
31
- children: [ shown.map(ref => /* @__PURE__ */ jsxRuntime.jsx(index.DocPreviewLink, {
32
- gdr: ref,
33
- layout: "inline"
34
- }, ref.id)), overflow > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, {
69
+ return jsxRuntime.jsxs(ui.Stack, {
70
+ gap: 4,
71
+ children: [
72
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, {
35
73
  muted: !0,
36
74
  size: 1,
37
- children: [ "+", overflow, " more" ]
75
+ children: [ "No workflow with id “", id, " — it may have been deleted." ]
76
+ }),
77
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
78
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
79
+ fontSize: 1,
80
+ icon: ArrowLeft.ArrowLeftIcon,
81
+ mode: "ghost",
82
+ onClick: onBack,
83
+ padding: 2,
84
+ text: "Back to workflows"
85
+ })
86
+ }) ]
87
+ });
88
+ }
89
+
90
+ function InstanceDetailPanel({entry: entry, onBack: onBack}) {
91
+ const definition = index.useDefinition(entry), [openActivity, setOpenActivity] = react.useState(null), {instance: instance} = entry;
92
+ return react.useEffect(() => {
93
+ openActivity && index.openActivityGone({
94
+ entry: entry,
95
+ target: openActivity
96
+ }) && setOpenActivity(null);
97
+ }, [ entry, openActivity ]), /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
98
+ direction: "column",
99
+ height: "fill",
100
+ overflow: "hidden",
101
+ children: [
102
+ /* @__PURE__ */ jsxRuntime.jsx(DetailHeader, {
103
+ definition: definition,
104
+ entry: entry,
105
+ onBack: onBack
106
+ }),
107
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
108
+ flex: 1,
109
+ overflow: "auto",
110
+ paddingX: 4,
111
+ children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
112
+ gap: 4,
113
+ paddingBottom: 5,
114
+ children: [
115
+ /* @__PURE__ */ jsxRuntime.jsx(StudioDocumentsSection, {
116
+ instance: instance
117
+ }),
118
+ /* @__PURE__ */ jsxRuntime.jsx(StageDiagramSection, {
119
+ definition: definition,
120
+ entry: entry
121
+ }),
122
+ /* @__PURE__ */ jsxRuntime.jsx(index.GroupHeading, {
123
+ title: "All tasks"
124
+ }),
125
+ /* @__PURE__ */ jsxRuntime.jsx(InstanceTaskLists, {
126
+ entry: entry,
127
+ onOpenActivity: name => setOpenActivity({
128
+ stage: instance.currentStage,
129
+ activityName: name
130
+ })
131
+ }) ]
132
+ })
133
+ }), openActivity ? /* @__PURE__ */ jsxRuntime.jsx(index.ActivityDetailDialog, {
134
+ activityName: openActivity.activityName,
135
+ breadcrumb: index.instanceBreadcrumb(instance, definition),
136
+ definition: definition,
137
+ entry: entry,
138
+ onClose: () => setOpenActivity(null)
38
139
  }) : null ]
39
140
  });
40
141
  }
41
142
 
42
- function DocRefChips({instance: instance, max: max = 2}) {
43
- const refs = react.useMemo(() => documentRefsOf(instance), [ instance ]);
143
+ function DetailHeader({entry: entry, definition: definition, onBack: onBack}) {
144
+ const {instance: instance, ready: ready} = entry;
44
145
  /* @__PURE__ */
45
- return jsxRuntime.jsx(RefChips, {
46
- max: max,
47
- refs: refs
146
+ return jsxRuntime.jsx(ui.Card, {
147
+ flex: "none",
148
+ paddingX: 4,
149
+ paddingY: 3,
150
+ children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
151
+ align: "center",
152
+ gap: 3,
153
+ wrap: "wrap",
154
+ children: [
155
+ /* @__PURE__ */ jsxRuntime.jsx(index.HoverHint, {
156
+ text: "Back to workflows",
157
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
158
+ "aria-label": "Back to workflows",
159
+ fontSize: 1,
160
+ icon: ArrowLeft.ArrowLeftIcon,
161
+ mode: "bleed",
162
+ onClick: onBack,
163
+ padding: 2
164
+ })
165
+ }),
166
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
167
+ gap: 2,
168
+ children: [
169
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
170
+ size: 1,
171
+ weight: "semibold",
172
+ children: index.instanceTitle(instance, definition)
173
+ }),
174
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, {
175
+ muted: !0,
176
+ size: 1,
177
+ children: [ "Started ", index.formatDate(instance.startedAt) ]
178
+ }) ]
179
+ }), workflowEngine.terminalState(instance) === "in-flight" ? /* @__PURE__ */ jsxRuntime.jsx(index.StageChip, {
180
+ title: index.stageTitle(definition, instance.currentStage)
181
+ }) : /* @__PURE__ */ jsxRuntime.jsx(index.AbortedBadge, {
182
+ instance: instance
183
+ }),
184
+ /* @__PURE__ */ jsxRuntime.jsx(SpinnerSlot, {
185
+ busy: !ready || index.isEvaluationStale(entry)
186
+ }) ]
187
+ })
48
188
  });
49
189
  }
50
190
 
51
- function datesOf(state) {
52
- return state.filter(entry => entry._type === "date" || entry._type === "datetime").map(entry => entry.value).filter(value => typeof value == "string" && value !== "");
191
+ function StudioDocumentsSection({instance: instance}) {
192
+ const refs = documentRefsOf(instance);
193
+ return refs.length === 0 ? null : /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
194
+ gap: 3,
195
+ marginTop: 3,
196
+ children: [
197
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
198
+ muted: !0,
199
+ size: 1,
200
+ weight: "medium",
201
+ children: refs.length === 1 ? "Studio document" : "Studio documents"
202
+ }),
203
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Stack, {
204
+ gap: 2,
205
+ children: refs.map(ref => /* @__PURE__ */ jsxRuntime.jsx(index.DocPreviewLink, {
206
+ gdr: ref
207
+ }, ref.id))
208
+ }) ]
209
+ });
53
210
  }
54
211
 
55
- function spawnOrigins(instances) {
56
- const origins = /* @__PURE__ */ new Map;
57
- for (const parent of instances) for (const row of parent.subworkflows ?? []) origins.set(workflowEngine.extractDocumentId(row.ref.id), {
58
- parent: parent,
59
- activityName: row.activity,
60
- cohortStage: row.cohortStage
212
+ function StageDiagramSection({entry: entry, definition: definition}) {
213
+ const {instance: instance} = entry;
214
+ return definition ?
215
+ /* @__PURE__ */ jsxRuntime.jsx(workflowDiagram.WorkflowDiagram, {
216
+ currentStage: workflowEngine.terminalState(instance) === "in-flight" ? instance.currentStage : void 0,
217
+ definition: definition,
218
+ evaluation: entry.evaluation,
219
+ explain: !0,
220
+ guardCount: entry.guards?.length,
221
+ height: 340,
222
+ history: instance.history
223
+ }, instance._id) : /* @__PURE__ */ jsxRuntime.jsx(ui.Card, {
224
+ border: !0,
225
+ marginTop: 3,
226
+ padding: 3,
227
+ radius: 2,
228
+ tone: "caution",
229
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
230
+ muted: !0,
231
+ size: 1,
232
+ children: "Couldn’t load this workflow’s full details — the stage diagram is unavailable, and technical names show instead of titles."
233
+ })
61
234
  });
62
- return origins;
63
235
  }
64
236
 
65
- function rootOf(instance, byId) {
66
- const rootRef = instance.ancestors[0];
67
- return rootRef ? byId.get(workflowEngine.extractDocumentId(rootRef.id)) ?? instance : instance;
237
+ function MutedNote({text: text}) {
238
+ /* @__PURE__ */
239
+ return jsxRuntime.jsx(ui.Box, {
240
+ paddingY: 3,
241
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
242
+ muted: !0,
243
+ size: 1,
244
+ children: text
245
+ })
246
+ });
68
247
  }
69
248
 
70
- function taskRowsOf(args) {
71
- const {instance: instance, breadcrumb: breadcrumb, identity: identity} = args, open = workflowEngine.findOpenStageEntry(instance);
72
- if (!open) return [];
73
- const definition = index.definitionSnapshotOf(instance), state = index.stateByActivity(instance), rows = (open.activities ?? []).map(activity => {
74
- const fields = state.get(activity.name) ?? [], declared = index.findActivity({
75
- definition: definition,
76
- stageName: open.name,
77
- activityName: activity.name
78
- });
79
- return {
249
+ function useStartableDefinitions() {
250
+ const {engine: engine} = index.useWorkflowContext(), [definitions, setDefinitions] = react.useState(void 0), [error, setError] = react.useState(void 0);
251
+ return react.useEffect(() => {
252
+ let cancelled = !1;
253
+ return (async () => {
254
+ const rows = await index.readDeployedDefinitions(engine), startable = workflowEngine.latestDeployedDefinitions(rows).filter(row => workflowEngine.isStartableDefinition(row)).map(row => ({
255
+ name: row.name,
256
+ title: row.title ?? row.name,
257
+ description: row.description
258
+ }));
259
+ cancelled || (setDefinitions(startable), setError(void 0));
260
+ })().catch(err => {
261
+ cancelled || setError(index.describeError(err));
262
+ }), () => {
263
+ cancelled = !0;
264
+ };
265
+ }, [ engine ]), {
266
+ definitions: definitions,
267
+ error: error
268
+ };
269
+ }
270
+
271
+ function NewWorkflowButton() {
272
+ const {openStartDialog: openStartDialog} = index.useWorkflowContext(), [open, setOpen] = react.useState(!1);
273
+ /* @__PURE__ */
274
+ return jsxRuntime.jsx(index.DismissablePopover, {
275
+ content: open ? /* @__PURE__ */ jsxRuntime.jsx(DefinitionPickerPanel, {
276
+ onPick: definition => {
277
+ setOpen(!1), openStartDialog({
278
+ definition: definition.name,
279
+ label: definition.title
280
+ });
281
+ }
282
+ }) : null,
283
+ onDismiss: () => setOpen(!1),
284
+ open: open,
285
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
286
+ fontSize: 1,
287
+ gap: 2,
288
+ icon: Add.AddIcon,
289
+ onClick: () => setOpen(v => !v),
290
+ padding: 2,
291
+ selected: open,
292
+ text: "New workflow"
293
+ })
294
+ });
295
+ }
296
+
297
+ function DefinitionPickerPanel({onPick: onPick}) {
298
+ const {definitions: definitions, error: error} = useStartableDefinitions(), [query, setQuery] = react.useState(""), visible = react.useMemo(() => {
299
+ const q = query.trim().toLowerCase();
300
+ return definitions ? q ? definitions.filter(d => `${d.title} ${d.name}`.toLowerCase().includes(q)) : definitions : [];
301
+ }, [ definitions, query ]);
302
+ /* @__PURE__ */
303
+ return jsxRuntime.jsx(ui.Box, {
304
+ padding: 2,
305
+ style: {
306
+ width: 340
307
+ },
308
+ children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
309
+ gap: 2,
310
+ children: [
311
+ /* @__PURE__ */ jsxRuntime.jsx(ui.TextInput, {
312
+ autoFocus: !0,
313
+ fontSize: 1,
314
+ icon: Search.SearchIcon,
315
+ onChange: event => setQuery(event.currentTarget.value),
316
+ placeholder: "Filter workflows…",
317
+ value: query
318
+ }), error ? /* @__PURE__ */ jsxRuntime.jsx(MutedNote, {
319
+ text: `Could not load the deployed workflows: ${error}`
320
+ }) : null, !definitions && !error ? /* @__PURE__ */ jsxRuntime.jsx(index.LoadingRow, {
321
+ label: "Loading workflows…"
322
+ }) : null, definitions && definitions.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(MutedNote, {
323
+ text: "No startable workflows are deployed"
324
+ }) : null, definitions && definitions.length > 0 && visible.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(MutedNote, {
325
+ text: "No workflows match"
326
+ }) : null,
327
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Stack, {
328
+ gap: 1,
329
+ style: {
330
+ maxHeight: 320,
331
+ overflowY: "auto"
332
+ },
333
+ children: visible.map(definition => /* @__PURE__ */ jsxRuntime.jsx(ui.Card, {
334
+ as: "button",
335
+ onClick: () => onPick(definition),
336
+ padding: 3,
337
+ radius: 2,
338
+ style: {
339
+ cursor: "pointer",
340
+ textAlign: "left"
341
+ },
342
+ children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
343
+ gap: 2,
344
+ children: [
345
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
346
+ size: 1,
347
+ weight: "medium",
348
+ children: definition.title
349
+ }), definition.description ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
350
+ muted: !0,
351
+ size: 1,
352
+ textOverflow: "ellipsis",
353
+ children: definition.description
354
+ }) : null ]
355
+ })
356
+ }, definition.name))
357
+ }) ]
358
+ })
359
+ });
360
+ }
361
+
362
+ function ToolActivityDialog({target: target, onClose: onClose}) {
363
+ const entry = index.useWorkflowInstanceEntry(target.instanceId), definition = index.useDefinition(entry), resolvedOnce = react.useRef(!1);
364
+ return entry && (resolvedOnce.current = !0), react.useEffect(() => {
365
+ resolvedOnce.current && index.openActivityGone({
366
+ entry: entry,
367
+ target: target
368
+ }) && onClose();
369
+ }, [ entry, target, onClose ]), entry?.invalid ? /* @__PURE__ */ jsxRuntime.jsx(ui.Dialog, {
370
+ header: "Workflow unavailable",
371
+ id: "workflow-activity-detail",
372
+ onClose: onClose,
373
+ width: 1,
374
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
375
+ padding: 4,
376
+ children: /* @__PURE__ */ jsxRuntime.jsx(index.InvalidDocNotice, {
377
+ invalid: entry.invalid
378
+ })
379
+ })
380
+ }) : entry?.evaluation ? /* @__PURE__ */ jsxRuntime.jsx(index.ActivityDetailDialog, {
381
+ activityName: target.activityName,
382
+ breadcrumb: index.instanceBreadcrumb(entry.instance, definition),
383
+ definition: definition,
384
+ document: documentRefsOf(entry.instance)[0],
385
+ entry: entry,
386
+ onClose: onClose
387
+ }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Dialog, {
388
+ header: "Loading activity…",
389
+ id: "workflow-activity-detail",
390
+ onClose: onClose,
391
+ width: 1,
392
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
393
+ padding: 4,
394
+ children: /* @__PURE__ */ jsxRuntime.jsx(index.LoadingRow, {
395
+ label: "Fetching the live workflow state…"
396
+ })
397
+ })
398
+ });
399
+ }
400
+
401
+ function datesOf(state) {
402
+ return state.filter(entry => entry._type === "date" || entry._type === "datetime").map(entry => entry.value).filter(value => typeof value == "string" && value !== "");
403
+ }
404
+
405
+ function spawnOrigins(instances) {
406
+ const origins = /* @__PURE__ */ new Map;
407
+ for (const parent of instances) for (const row of parent.subworkflows ?? []) origins.set(workflowEngine.extractDocumentId(row.ref.id), {
408
+ parent: parent,
409
+ activityName: row.activity,
410
+ cohortStage: row.cohortStage
411
+ });
412
+ return origins;
413
+ }
414
+
415
+ function rootOf(instance, byId) {
416
+ const rootRef = instance.ancestors[0];
417
+ return rootRef ? byId.get(workflowEngine.extractDocumentId(rootRef.id)) ?? instance : instance;
418
+ }
419
+
420
+ function taskRowsOf(args) {
421
+ const {instance: instance, identity: identity} = args, open = workflowEngine.findOpenStageEntry(instance);
422
+ if (!open) return [];
423
+ const definition = index.definitionSnapshotOf(instance), state = index.stateByActivity(instance), rows = (open.activities ?? []).map(activity => {
424
+ const fields = state.get(activity.name) ?? [], declared = index.findActivityNode({
425
+ definition: definition,
426
+ stageName: open.name,
427
+ activityName: activity.name
428
+ }) ?? {
429
+ name: activity.name
430
+ }, controlArgs = {
431
+ activity: declared,
432
+ status: activity.status,
433
+ editableFields: void 0
434
+ };
435
+ return {
80
436
  instanceId: instance._id,
81
437
  activityName: activity.name,
82
- title: declared.title,
83
- description: declared.description,
84
- breadcrumb: breadcrumb,
438
+ title: declared.title ?? activity.name,
85
439
  stage: open.name,
86
- stageTitle: index.stageTitle(definition, open.name),
87
440
  status: activity.status,
88
441
  open: index.isOpenActivityStatus(activity.status),
89
442
  dates: datesOf(fields),
@@ -91,69 +444,124 @@ function taskRowsOf(args) {
91
444
  assignedToMe: identity !== void 0 && index.isActivityAssignedTo({
92
445
  state: fields,
93
446
  who: identity
94
- })
447
+ }),
448
+ assignControl: index.rowAssignControlState(controlArgs),
449
+ dateControl: index.rowDateControlState(controlArgs)
95
450
  };
96
451
  });
97
452
  return [ ...rows.filter(r => r.open), ...rows.filter(r => !r.open) ];
98
453
  }
99
454
 
100
455
  function deriveTaskGroups(args) {
101
- const {instances: instances, identity: identity} = args, byId = new Map(instances.map(instance => [ instance._id, instance ])), origins = spawnOrigins(instances), groups = /* @__PURE__ */ new Map, ordered = [ ...instances ].sort((a, b) => a.startedAt.localeCompare(b.startedAt));
456
+ const {instances: instances, identity: identity} = args, byId = new Map(instances.map(instance => [ instance._id, instance ])), origins = spawnOrigins(instances), docGroups = /* @__PURE__ */ new Map, withoutDocuments = [], ordered = [ ...instances ].sort((a, b) => a.startedAt.localeCompare(b.startedAt));
102
457
  for (const instance of ordered) {
103
- const origin = origins.get(instance._id), breadcrumb = origin ? index.findActivity({
104
- definition: index.definitionSnapshotOf(origin.parent),
105
- stageName: origin.cohortStage,
106
- activityName: origin.activityName
107
- }).title : void 0, rows = taskRowsOf({
458
+ const rows = taskRowsOf({
108
459
  instance: instance,
109
- breadcrumb: breadcrumb,
110
460
  identity: identity
111
- });
112
- if (rows.length === 0) continue;
113
- const root = rootOf(instance, byId), documents = documentRefsOf(root), document = documents[0], key = document ? `doc:${document.id}` : `def:${root.definition}`, held = groups.get(key);
461
+ }), first = rows[0];
462
+ if (!first) continue;
463
+ const origin = origins.get(instance._id), definition = index.definitionSnapshotOf(instance), entry = {
464
+ instanceId: instance._id,
465
+ workflowName: instance.definition,
466
+ title: index.instanceTitle(instance, definition),
467
+ stageTitle: index.stageTitle(definition, first.stage),
468
+ breadcrumb: origin ? index.findActivity({
469
+ definition: index.definitionSnapshotOf(origin.parent),
470
+ stageName: origin.cohortStage,
471
+ activityName: origin.activityName
472
+ }).title : void 0,
473
+ rows: rows
474
+ }, root = rootOf(instance, byId), documents = documentRefsOf(root), document = documents[0];
475
+ if (!document) {
476
+ withoutDocuments.push(entry);
477
+ continue;
478
+ }
479
+ const key = `doc:${document.id}`, held = docGroups.get(key);
114
480
  if (held) {
115
- held.rows.push(...rows);
481
+ held.instances.push(entry);
116
482
  continue;
117
483
  }
118
- const definition = index.definitionSnapshotOf(root);
119
- groups.set(key, {
484
+ docGroups.set(key, {
120
485
  group: {
121
486
  key: key,
122
487
  document: document,
123
- documents: documents,
124
- instanceId: root._id,
125
- workflowName: root.definition,
126
- workflowTitle: index.instanceTitle(root, definition),
127
- workflowDescription: definition?.description
488
+ documents: documents
128
489
  },
129
- rows: rows
490
+ instances: [ entry ]
130
491
  });
131
492
  }
132
- const assembled = [ ...groups.values() ].map(({group: group, rows: rows}) => ({
133
- ...group,
134
- rows: rows
135
- }));
136
493
  return {
137
- withDocuments: assembled.filter(g => g.document !== void 0),
138
- withoutDocuments: assembled.filter(g => g.document === void 0)
494
+ withDocuments: [ ...docGroups.values() ].map(({group: group, instances: bands}) => ({
495
+ ...group,
496
+ instances: bands
497
+ })),
498
+ withoutDocuments: withoutDocuments
499
+ };
500
+ }
501
+
502
+ function cutTaskGroups(groups, cut) {
503
+ const cutBands = bands => bands.filter(band => cut.keepBand?.(band) ?? !0).map(band => ({
504
+ ...band,
505
+ rows: band.rows.filter(cut.keepRow)
506
+ })).filter(band => band.rows.length > 0);
507
+ return {
508
+ withDocuments: groups.withDocuments.filter(group => cut.keepGroup?.(group) ?? !0).map(group => ({
509
+ ...group,
510
+ instances: cutBands(group.instances)
511
+ })).filter(group => group.instances.length > 0),
512
+ withoutDocuments: cut.dropUngrouped ? [] : cutBands(groups.withoutDocuments)
139
513
  };
140
514
  }
141
515
 
142
516
  function onlyMyTasks(groups) {
143
- const cut = list => list.map(group => ({
144
- ...group,
145
- rows: group.rows.filter(row => row.assignedToMe)
146
- })).filter(group => group.rows.length > 0);
517
+ return cutTaskGroups(groups, {
518
+ keepRow: row => row.assignedToMe
519
+ });
520
+ }
521
+
522
+ function rowActivityEval(entry, row) {
523
+ const evaluation = entry?.evaluation;
524
+ if (!(evaluation === void 0 || evaluation.currentStage.stage.name !== row.stage)) return evaluation.currentStage.activities.find(a => a.activity.name === row.activityName);
525
+ }
526
+
527
+ function taskRowRender(row, entry) {
528
+ const activityEval = rowActivityEval(entry, row);
529
+ if (entry?.evaluation === void 0 || activityEval === void 0) return {
530
+ face: index.committedRowFace(row),
531
+ assignState: row.assignControl,
532
+ assigneeIds: row.assigneeIds,
533
+ dates: row.dates,
534
+ dateState: row.dateControl,
535
+ terminalActions: [],
536
+ stale: !1
537
+ };
538
+ const activityState = index.stateByActivity(entry.instance), {face: face, assignState: assignState, assigneeIds: assigneeIds, terminalActions: terminalActions} = index.activityRowProps({
539
+ activityEval: activityEval,
540
+ activityState: activityState,
541
+ editableFields: entry.evaluation.editableFields
542
+ });
147
543
  return {
148
- withDocuments: cut(groups.withDocuments),
149
- withoutDocuments: cut(groups.withoutDocuments)
544
+ face: face,
545
+ assignState: assignState,
546
+ assigneeIds: assigneeIds,
547
+ dates: datesOf(activityState.get(row.activityName) ?? []),
548
+ dateState: index.rowDateControlState({
549
+ activity: activityEval.activity,
550
+ status: activityEval.status,
551
+ editableFields: entry.evaluation.editableFields
552
+ }),
553
+ terminalActions: terminalActions,
554
+ stale: index.isEvaluationStale(entry)
150
555
  };
151
556
  }
152
557
 
153
558
  function taskFilterOptions(groups) {
154
- const all = [ ...groups.withDocuments, ...groups.withoutDocuments ], workflows = /* @__PURE__ */ new Map, documents = /* @__PURE__ */ new Map;
155
- for (const group of all) workflows.set(group.workflowName, group.workflowTitle),
156
- group.document && documents.set(group.document.id, group.document);
559
+ const workflows = /* @__PURE__ */ new Map, documents = /* @__PURE__ */ new Map;
560
+ for (const group of groups.withDocuments) {
561
+ documents.set(group.document.id, group.document);
562
+ for (const band of group.instances) workflows.set(band.workflowName, band.title);
563
+ }
564
+ for (const band of groups.withoutDocuments) workflows.set(band.workflowName, band.title);
157
565
  return {
158
566
  workflows: [ ...workflows ].map(([name, title]) => ({
159
567
  name: name,
@@ -270,72 +678,18 @@ function rowMatches(args) {
270
678
  }));
271
679
  }
272
680
 
273
- function groupMatches(group, filters) {
274
- const workflows = activeArm(filters.workflows);
275
- if (workflows && !workflows.includes(group.workflowName)) return !1;
276
- const documentIds = activeArm(filters.documentIds);
277
- return !(documentIds && (!group.document || !documentIds.includes(group.document.id)));
278
- }
279
-
280
681
  function applyTaskFilters(args) {
281
- const {groups: groups, filters: filters, now: now} = args, cut = list => list.filter(group => groupMatches(group, filters)).map(group => ({
282
- ...group,
283
- rows: group.rows.filter(row => rowMatches({
682
+ const {groups: groups, filters: filters, now: now} = args, documentIds = activeArm(filters.documentIds), workflows = activeArm(filters.workflows);
683
+ return cutTaskGroups(groups, {
684
+ keepRow: row => rowMatches({
284
685
  row: row,
285
686
  filters: filters,
286
687
  now: now
287
- }))
288
- })).filter(group => group.rows.length > 0);
289
- return {
290
- withDocuments: cut(groups.withDocuments),
291
- withoutDocuments: cut(groups.withoutDocuments)
292
- };
293
- }
294
-
295
- function instanceFilterOptions(rows) {
296
- const workflows = /* @__PURE__ */ new Map, documents = /* @__PURE__ */ new Map;
297
- for (const row of rows) {
298
- workflows.set(row.instance.definition, row.workflowTitle);
299
- for (const doc of row.documents) documents.set(doc.id, doc);
300
- }
301
- return {
302
- workflows: [ ...workflows ].map(([name, title]) => ({
303
- name: name,
304
- title: title
305
- })),
306
- documents: [ ...documents.values() ]
307
- };
308
- }
309
-
310
- function applyInstanceFilters(args) {
311
- const {rows: rows, filters: filters} = args, workflows = activeArm(filters.workflows), documentIds = activeArm(filters.documentIds);
312
- return rows.filter(row => !workflows || workflows.includes(row.instance.definition)).filter(row => !documentIds || row.documents.some(doc => documentIds.includes(doc.id))).map(row => row.instance);
313
- }
314
-
315
- function hasTaskArms(filters) {
316
- return (filters.assigneeIds?.length ?? 0) > 0 || filters.date !== void 0;
317
- }
318
-
319
- function instanceStatusMatches(instance, statuses) {
320
- const arm = activeArm(statuses);
321
- if (!arm) return !0;
322
- const state = workflowEngine.terminalState(instance);
323
- return state === "in-flight" ? arm.includes("open") : state === "completed" && arm.includes("completed");
324
- }
325
-
326
- function instanceIdsMatchingTaskArms(args) {
327
- const {instances: instances, identity: identity, filters: filters, now: now} = args;
328
- if (!hasTaskArms(filters)) return null;
329
- const groups = deriveTaskGroups({
330
- instances: instances,
331
- identity: identity
332
- }), {statuses: _workflowLevel, ...taskArms} = filters, cut = applyTaskFilters({
333
- groups: groups,
334
- filters: taskArms,
335
- now: now
336
- }), ids = /* @__PURE__ */ new Set;
337
- for (const group of [ ...cut.withDocuments, ...cut.withoutDocuments ]) for (const row of group.rows) ids.add(row.instanceId);
338
- return ids;
688
+ }),
689
+ keepBand: band => !workflows || workflows.includes(band.workflowName),
690
+ keepGroup: group => !documentIds || documentIds.includes(group.document.id),
691
+ dropUngrouped: documentIds !== void 0
692
+ });
339
693
  }
340
694
 
341
695
  const NOTHING = {
@@ -843,653 +1197,141 @@ function ActiveFilterChips({filters: filters, options: options, onChange: onChan
843
1197
  });
844
1198
  }
845
1199
 
846
- const INSTANCE_CAP = 200, NEWEST_INSTANCES = {
847
- includeCompleted: !0,
848
- limit: INSTANCE_CAP
849
- };
850
-
851
- function useToolInstances() {
852
- const {engine: engine} = index.useWorkflowContext(), {instances: instances, loading: loading, invalid: invalid} = workflowStudio.useWorkflowInstances({
853
- engine: engine,
854
- filter: NEWEST_INSTANCES
855
- });
856
- return react.useMemo(() => {
857
- const rows = instances ?? [];
858
- return {
859
- inFlight: rows.filter(instance => workflowEngine.terminalState(instance) === "in-flight"),
860
- settled: rows.filter(instance => workflowEngine.terminalState(instance) !== "in-flight"),
861
- truncated: rows.length === INSTANCE_CAP,
862
- loading: loading,
863
- invalid: invalid
864
- };
865
- }, [ instances, loading, invalid ]);
866
- }
867
-
868
- function toFilterRows(instances) {
869
- return instances.map(instance => ({
870
- instance: instance,
871
- workflowTitle: index.instanceTitle(instance, index.definitionSnapshotOf(instance)),
872
- documents: documentRefsOf(instance)
873
- }));
874
- }
875
-
876
- function cutInstances(args) {
877
- const {rows: rows, filters: filters, taskArmIds: taskArmIds} = args, kept = applyInstanceFilters({
878
- rows: rows,
879
- filters: filters
880
- }).filter(instance => instanceStatusMatches(instance, filters.statuses));
881
- return taskArmIds === null ? kept : kept.filter(instance => taskArmIds.has(instance._id));
882
- }
883
-
884
- function WorkflowsDashboard({instances: instances, onOpenInstance: onOpenInstance}) {
885
- const {inFlight: inFlight, settled: settled, truncated: truncated, loading: loading} = instances, [filters, setFilters] = react.useState({}), identity = index.useAssignmentIdentity(), inFlightRows = react.useMemo(() => toFilterRows(inFlight), [ inFlight ]), settledRows = react.useMemo(() => toFilterRows(settled), [ settled ]), options = react.useMemo(() => instanceFilterOptions([ ...inFlightRows, ...settledRows ]), [ inFlightRows, settledRows ]), taskArmIds = react.useMemo(() => instanceIdsMatchingTaskArms({
886
- instances: [ ...inFlight, ...settled ],
887
- identity: identity,
888
- filters: filters,
889
- now: /* @__PURE__ */ new Date
890
- }), [ inFlight, settled, identity, filters ]), visibleInFlight = react.useMemo(() => cutInstances({
891
- rows: inFlightRows,
892
- filters: filters,
893
- taskArmIds: taskArmIds
894
- }), [ inFlightRows, filters, taskArmIds ]), visibleSettled = react.useMemo(() => cutInstances({
895
- rows: settledRows,
896
- filters: filters,
897
- taskArmIds: taskArmIds
898
- }), [ settledRows, filters, taskArmIds ]);
899
- return loading ? /* @__PURE__ */ jsxRuntime.jsx(index.LoadingRow, {
900
- label: "Loading workflows…"
901
- }) : inFlight.length === 0 && settled.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(MutedNote, {
902
- text: "No workflows yet — start one with “New workflow”"
903
- }) : /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
904
- gap: 2,
905
- children: [
906
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
907
- align: "center",
908
- gap: 2,
909
- justify: "flex-end",
910
- children: [
911
- /* @__PURE__ */ jsxRuntime.jsx(ActiveFilterChips, {
912
- filters: filters,
913
- onChange: setFilters,
914
- options: options
915
- }),
916
- /* @__PURE__ */ jsxRuntime.jsx(TaskFilterMenu, {
917
- filters: filters,
918
- onChange: setFilters,
919
- options: options
920
- }) ]
921
- }), visibleInFlight.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(MutedNote, {
922
- text: "No running workflows match"
923
- }) : /* @__PURE__ */ jsxRuntime.jsx(InstanceRows, {
924
- instances: visibleInFlight,
925
- onOpenInstance: onOpenInstance
926
- }),
927
- /* @__PURE__ */ jsxRuntime.jsx(SettledRows, {
928
- defaultShown: filters.statuses?.includes("completed") ?? !1,
929
- instances: visibleSettled,
930
- onOpenInstance: onOpenInstance
931
- }), truncated ? /* @__PURE__ */ jsxRuntime.jsx(MutedNote, {
932
- text: `Showing the latest ${INSTANCE_CAP} workflows.`
933
- }) : null ]
934
- });
935
- }
936
-
937
- function InstanceRows({instances: instances, onOpenInstance: onOpenInstance}) {
938
- /* @__PURE__ */
939
- return jsxRuntime.jsx(jsxRuntime.Fragment, {
940
- children: instances.map(instance => /* @__PURE__ */ jsxRuntime.jsx(InstanceRow, {
941
- instance: instance,
942
- onOpen: () => onOpenInstance(instance)
943
- }, instance._id))
944
- });
945
- }
946
-
947
- function SettledRows({instances: instances, onOpenInstance: onOpenInstance, defaultShown: defaultShown}) {
948
- const [toggled, setToggled] = react.useState(void 0), shown = toggled ?? defaultShown;
949
- return instances.length === 0 ? null : /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
950
- gap: 2,
951
- marginTop: 3,
952
- children: [
953
- /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
954
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
955
- fontSize: 1,
956
- icon: shown ? ChevronDown.ChevronDownIcon : ChevronRight.ChevronRightIcon,
957
- mode: "bleed",
958
- onClick: () => setToggled(!shown),
959
- padding: 2,
960
- text: `${shown ? "Hide" : "Show"} ${instances.length} finished`
961
- })
962
- }), shown ? /* @__PURE__ */ jsxRuntime.jsx(InstanceRows, {
963
- instances: instances,
964
- onOpenInstance: onOpenInstance
965
- }) : null ]
966
- });
967
- }
968
-
969
- function InstanceRow({instance: instance, onOpen: onOpen}) {
970
- const definition = react.useMemo(() => index.definitionSnapshotOf(instance), [ instance ]);
971
- /* @__PURE__ */
972
- return jsxRuntime.jsxs(ui.Flex, {
1200
+ function FilterRowPortal({filters: filters, onChange: onChange, options: options, slot: slot}) {
1201
+ return slot ? reactDom.createPortal(
1202
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
973
1203
  align: "center",
974
1204
  gap: 2,
1205
+ justify: "flex-end",
975
1206
  children: [
976
- /* @__PURE__ */ jsxRuntime.jsx(ui.Card, {
977
- as: "button",
978
- flex: 1,
979
- onClick: onOpen,
980
- padding: 3,
981
- paddingLeft: 4,
982
- radius: 2,
983
- style: {
984
- cursor: "pointer",
985
- textAlign: "left"
986
- },
987
- children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
988
- align: "center",
989
- gap: 3,
990
- children: [
991
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
992
- size: 1,
993
- weight: "medium",
994
- children: index.instanceTitle(instance, definition)
995
- }),
996
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, {
997
- muted: !0,
998
- size: 1,
999
- children: [ "Started ", index.formatDate(instance.startedAt) ]
1000
- }),
1001
- /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
1002
- flex: 1
1003
- }),
1004
- /* @__PURE__ */ jsxRuntime.jsx(index.AbortedBadge, {
1005
- instance: instance
1006
- }) ]
1007
- })
1008
- }),
1009
- /* @__PURE__ */ jsxRuntime.jsx(DocRefChips, {
1010
- instance: instance
1011
- }) ]
1012
- });
1013
- }
1014
-
1015
- function SpinnerSlot({busy: busy}) {
1016
- /* @__PURE__ */
1017
- return jsxRuntime.jsx(ui.Flex, {
1018
- align: "center",
1019
- flex: "none",
1020
- justify: "center",
1021
- style: {
1022
- width: 19,
1023
- height: 19
1024
- },
1025
- children: busy ? /* @__PURE__ */ jsxRuntime.jsx(ui.Spinner, {
1026
- muted: !0
1027
- }) : null
1028
- });
1029
- }
1030
-
1031
- function InstanceTaskLists({entry: entry, onOpenActivity: onOpenActivity}) {
1032
- return index.instanceNotice(entry) || /* @__PURE__ */ jsxRuntime.jsx(index.StaleLock, {
1033
- stale: index.isEvaluationStale(entry),
1034
- children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
1035
- children: [
1036
- /* @__PURE__ */ jsxRuntime.jsx(index.ActivitiesList, {
1037
- entry: entry,
1038
- onOpenActivity: onOpenActivity
1039
- }),
1040
- /* @__PURE__ */ jsxRuntime.jsx(index.TodoItemsList, {
1041
- entry: entry
1042
- }) ]
1043
- })
1044
- });
1045
- }
1046
-
1047
- function WorkflowInstanceDetail({instanceId: instanceId, onBack: onBack}) {
1048
- const entry = index.useWorkflowInstanceEntry(instanceId), [graceOver, setGraceOver] = react.useState(!1);
1049
- return react.useEffect(() => {
1050
- const timer = setTimeout(() => setGraceOver(!0), 2500);
1051
- return () => clearTimeout(timer);
1052
- }, [ instanceId ]), entry?.invalid ? /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
1053
- padding: 4,
1054
- children: /* @__PURE__ */ jsxRuntime.jsx(index.InvalidDocNotice, {
1055
- invalid: entry.invalid
1056
- })
1057
- }) : entry ? /* @__PURE__ */ jsxRuntime.jsx(InstanceDetailPanel, {
1058
- entry: entry,
1059
- onBack: onBack
1060
- }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
1061
- padding: 4,
1062
- children: graceOver ? /* @__PURE__ */ jsxRuntime.jsx(NotFound, {
1063
- id: instanceId,
1064
- onBack: onBack
1065
- }) : /* @__PURE__ */ jsxRuntime.jsx(index.LoadingRow, {
1066
- label: "Loading workflow…"
1067
- })
1068
- });
1069
- }
1070
-
1071
- function NotFound({id: id, onBack: onBack}) {
1072
- /* @__PURE__ */
1073
- return jsxRuntime.jsxs(ui.Stack, {
1074
- gap: 4,
1075
- children: [
1076
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, {
1077
- muted: !0,
1078
- size: 1,
1079
- children: [ "No workflow with id “", id, "” — it may have been deleted." ]
1080
- }),
1081
- /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
1082
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
1083
- fontSize: 1,
1084
- icon: ArrowLeft.ArrowLeftIcon,
1085
- mode: "ghost",
1086
- onClick: onBack,
1087
- padding: 2,
1088
- text: "Back to workflows"
1089
- })
1090
- }) ]
1091
- });
1092
- }
1093
-
1094
- function InstanceDetailPanel({entry: entry, onBack: onBack}) {
1095
- const definition = index.useDefinition(entry), [openActivity, setOpenActivity] = react.useState(null), {instance: instance} = entry;
1096
- return react.useEffect(() => {
1097
- openActivity && index.openActivityGone({
1098
- entry: entry,
1099
- target: openActivity
1100
- }) && setOpenActivity(null);
1101
- }, [ entry, openActivity ]), /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
1102
- direction: "column",
1103
- height: "fill",
1104
- overflow: "hidden",
1105
- children: [
1106
- /* @__PURE__ */ jsxRuntime.jsx(DetailHeader, {
1107
- definition: definition,
1108
- entry: entry,
1109
- onBack: onBack
1110
- }),
1111
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
1112
- flex: 1,
1113
- overflow: "auto",
1114
- paddingX: 4,
1115
- children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
1116
- gap: 4,
1117
- paddingBottom: 5,
1118
- children: [
1119
- /* @__PURE__ */ jsxRuntime.jsx(StudioDocumentsSection, {
1120
- instance: instance
1121
- }),
1122
- /* @__PURE__ */ jsxRuntime.jsx(StageDiagramSection, {
1123
- definition: definition,
1124
- entry: entry
1125
- }),
1126
- /* @__PURE__ */ jsxRuntime.jsx(index.GroupHeading, {
1127
- title: "All tasks"
1128
- }),
1129
- /* @__PURE__ */ jsxRuntime.jsx(InstanceTaskLists, {
1130
- entry: entry,
1131
- onOpenActivity: name => setOpenActivity({
1132
- stage: instance.currentStage,
1133
- activityName: name
1134
- })
1135
- }) ]
1136
- })
1137
- }), openActivity ? /* @__PURE__ */ jsxRuntime.jsx(index.ActivityDetailDialog, {
1138
- activityName: openActivity.activityName,
1139
- breadcrumb: index.instanceBreadcrumb(instance, definition),
1140
- definition: definition,
1141
- entry: entry,
1142
- onClose: () => setOpenActivity(null)
1143
- }) : null ]
1144
- });
1145
- }
1146
-
1147
- function DetailHeader({entry: entry, definition: definition, onBack: onBack}) {
1148
- const {instance: instance, ready: ready} = entry;
1149
- /* @__PURE__ */
1150
- return jsxRuntime.jsx(ui.Card, {
1151
- flex: "none",
1152
- paddingX: 4,
1153
- paddingY: 3,
1154
- children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
1155
- align: "center",
1156
- gap: 3,
1157
- wrap: "wrap",
1158
- children: [
1159
- /* @__PURE__ */ jsxRuntime.jsx(index.HoverHint, {
1160
- text: "Back to workflows",
1161
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
1162
- "aria-label": "Back to workflows",
1163
- fontSize: 1,
1164
- icon: ArrowLeft.ArrowLeftIcon,
1165
- mode: "bleed",
1166
- onClick: onBack,
1167
- padding: 2
1168
- })
1169
- }),
1170
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
1171
- gap: 2,
1172
- children: [
1173
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
1174
- size: 1,
1175
- weight: "semibold",
1176
- children: index.instanceTitle(instance, definition)
1177
- }),
1178
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, {
1179
- muted: !0,
1180
- size: 1,
1181
- children: [ "Started ", index.formatDate(instance.startedAt) ]
1182
- }) ]
1183
- }), workflowEngine.terminalState(instance) === "in-flight" ? /* @__PURE__ */ jsxRuntime.jsx(index.StageChip, {
1184
- title: index.stageTitle(definition, instance.currentStage)
1185
- }) : /* @__PURE__ */ jsxRuntime.jsx(index.AbortedBadge, {
1186
- instance: instance
1187
- }),
1188
- /* @__PURE__ */ jsxRuntime.jsx(SpinnerSlot, {
1189
- busy: !ready || index.isEvaluationStale(entry)
1190
- }) ]
1191
- })
1192
- });
1193
- }
1194
-
1195
- function StudioDocumentsSection({instance: instance}) {
1196
- const refs = documentRefsOf(instance);
1197
- return refs.length === 0 ? null : /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
1198
- gap: 3,
1199
- marginTop: 3,
1200
- children: [
1201
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
1202
- muted: !0,
1203
- size: 1,
1204
- weight: "medium",
1205
- children: refs.length === 1 ? "Studio document" : "Studio documents"
1207
+ /* @__PURE__ */ jsxRuntime.jsx(ActiveFilterChips, {
1208
+ filters: filters,
1209
+ onChange: onChange,
1210
+ options: options
1206
1211
  }),
1207
- /* @__PURE__ */ jsxRuntime.jsx(ui.Stack, {
1208
- gap: 2,
1209
- children: refs.map(ref => /* @__PURE__ */ jsxRuntime.jsx(index.DocPreviewLink, {
1210
- gdr: ref
1211
- }, ref.id))
1212
- }) ]
1213
- });
1214
- }
1215
-
1216
- function StageDiagramSection({entry: entry, definition: definition}) {
1217
- const {instance: instance} = entry;
1218
- return definition ?
1219
- /* @__PURE__ */ jsxRuntime.jsx(workflowDiagram.WorkflowDiagram, {
1220
- currentStage: workflowEngine.terminalState(instance) === "in-flight" ? instance.currentStage : void 0,
1221
- definition: definition,
1222
- evaluation: entry.evaluation,
1223
- explain: !0,
1224
- guardCount: entry.guards?.length,
1225
- height: 340,
1226
- history: instance.history
1227
- }, instance._id) : /* @__PURE__ */ jsxRuntime.jsx(ui.Card, {
1228
- border: !0,
1229
- marginTop: 3,
1230
- padding: 3,
1231
- radius: 2,
1232
- tone: "caution",
1233
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
1234
- muted: !0,
1235
- size: 1,
1236
- children: "Couldn’t load this workflow’s full details — the stage diagram is unavailable, and technical names show instead of titles."
1237
- })
1238
- });
1239
- }
1240
-
1241
- function useStartableDefinitions() {
1242
- const {engine: engine} = index.useWorkflowContext(), [definitions, setDefinitions] = react.useState(void 0), [error, setError] = react.useState(void 0);
1243
- return react.useEffect(() => {
1244
- let cancelled = !1;
1245
- return (async () => {
1246
- const rows = await index.readDeployedDefinitions(engine), startable = workflowEngine.latestDeployedDefinitions(rows).filter(row => workflowEngine.isStartableDefinition(row)).map(row => ({
1247
- name: row.name,
1248
- title: row.title ?? row.name,
1249
- description: row.description
1250
- }));
1251
- cancelled || (setDefinitions(startable), setError(void 0));
1252
- })().catch(err => {
1253
- cancelled || setError(index.describeError(err));
1254
- }), () => {
1255
- cancelled = !0;
1256
- };
1257
- }, [ engine ]), {
1258
- definitions: definitions,
1259
- error: error
1260
- };
1261
- }
1262
-
1263
- function NewWorkflowButton() {
1264
- const {openStartDialog: openStartDialog} = index.useWorkflowContext(), [open, setOpen] = react.useState(!1);
1265
- /* @__PURE__ */
1266
- return jsxRuntime.jsx(index.DismissablePopover, {
1267
- content: open ? /* @__PURE__ */ jsxRuntime.jsx(DefinitionPickerPanel, {
1268
- onPick: definition => {
1269
- setOpen(!1), openStartDialog({
1270
- definition: definition.name,
1271
- label: definition.title
1272
- });
1273
- }
1274
- }) : null,
1275
- onDismiss: () => setOpen(!1),
1276
- open: open,
1277
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
1278
- fontSize: 1,
1279
- icon: Add.AddIcon,
1280
- onClick: () => setOpen(v => !v),
1281
- padding: 2,
1282
- selected: open,
1283
- text: "New workflow",
1284
- tone: "primary"
1285
- })
1286
- });
1287
- }
1288
-
1289
- function DefinitionPickerPanel({onPick: onPick}) {
1290
- const {definitions: definitions, error: error} = useStartableDefinitions(), [query, setQuery] = react.useState(""), visible = react.useMemo(() => {
1291
- const q = query.trim().toLowerCase();
1292
- return definitions ? q ? definitions.filter(d => `${d.title} ${d.name}`.toLowerCase().includes(q)) : definitions : [];
1293
- }, [ definitions, query ]);
1294
- /* @__PURE__ */
1295
- return jsxRuntime.jsx(ui.Box, {
1296
- padding: 2,
1297
- style: {
1298
- width: 340
1299
- },
1300
- children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
1301
- gap: 2,
1302
- children: [
1303
- /* @__PURE__ */ jsxRuntime.jsx(ui.TextInput, {
1304
- autoFocus: !0,
1305
- fontSize: 1,
1306
- icon: Search.SearchIcon,
1307
- onChange: event => setQuery(event.currentTarget.value),
1308
- placeholder: "Filter workflows…",
1309
- value: query
1310
- }), error ? /* @__PURE__ */ jsxRuntime.jsx(MutedNote, {
1311
- text: `Could not load the deployed workflows: ${error}`
1312
- }) : null, !definitions && !error ? /* @__PURE__ */ jsxRuntime.jsx(index.LoadingRow, {
1313
- label: "Loading workflows…"
1314
- }) : null, definitions && definitions.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(MutedNote, {
1315
- text: "No startable workflows are deployed"
1316
- }) : null, definitions && definitions.length > 0 && visible.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(MutedNote, {
1317
- text: "No workflows match"
1318
- }) : null,
1319
- /* @__PURE__ */ jsxRuntime.jsx(ui.Stack, {
1320
- gap: 1,
1321
- style: {
1322
- maxHeight: 320,
1323
- overflowY: "auto"
1324
- },
1325
- children: visible.map(definition => /* @__PURE__ */ jsxRuntime.jsx(ui.Card, {
1326
- as: "button",
1327
- onClick: () => onPick(definition),
1328
- padding: 3,
1329
- radius: 2,
1330
- style: {
1331
- cursor: "pointer",
1332
- textAlign: "left"
1333
- },
1334
- children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
1335
- gap: 2,
1336
- children: [
1337
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
1338
- size: 1,
1339
- weight: "medium",
1340
- children: definition.title
1341
- }), definition.description ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
1342
- muted: !0,
1343
- size: 1,
1344
- textOverflow: "ellipsis",
1345
- children: definition.description
1346
- }) : null ]
1347
- })
1348
- }, definition.name))
1349
- }) ]
1350
- })
1351
- });
1352
- }
1353
-
1354
- function ToolActivityDialog({target: target, onClose: onClose}) {
1355
- const entry = index.useWorkflowInstanceEntry(target.instanceId), definition = index.useDefinition(entry), resolvedOnce = react.useRef(!1);
1356
- return entry && (resolvedOnce.current = !0), react.useEffect(() => {
1357
- resolvedOnce.current && index.openActivityGone({
1358
- entry: entry,
1359
- target: target
1360
- }) && onClose();
1361
- }, [ entry, target, onClose ]), entry?.invalid ? /* @__PURE__ */ jsxRuntime.jsx(ui.Dialog, {
1362
- header: "Workflow unavailable",
1363
- id: "workflow-activity-detail",
1364
- onClose: onClose,
1365
- width: 1,
1366
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
1367
- padding: 4,
1368
- children: /* @__PURE__ */ jsxRuntime.jsx(index.InvalidDocNotice, {
1369
- invalid: entry.invalid
1370
- })
1371
- })
1372
- }) : entry?.evaluation ? /* @__PURE__ */ jsxRuntime.jsx(index.ActivityDetailDialog, {
1373
- activityName: target.activityName,
1374
- breadcrumb: index.instanceBreadcrumb(entry.instance, definition),
1375
- definition: definition,
1376
- document: documentRefsOf(entry.instance)[0],
1377
- entry: entry,
1378
- onClose: onClose
1379
- }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Dialog, {
1380
- header: "Loading activity…",
1381
- id: "workflow-activity-detail",
1382
- onClose: onClose,
1383
- width: 1,
1384
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
1385
- padding: 4,
1386
- children: /* @__PURE__ */ jsxRuntime.jsx(index.LoadingRow, {
1387
- label: "Fetching the live workflow state…"
1388
- })
1389
- })
1390
- });
1212
+ /* @__PURE__ */ jsxRuntime.jsx(TaskFilterMenu, {
1213
+ filters: filters,
1214
+ onChange: onChange,
1215
+ options: options
1216
+ }) ]
1217
+ }), slot) : null;
1391
1218
  }
1392
1219
 
1393
- function TaskGroupList({groups: groups, onOpenTask: onOpenTask, onOpenWorkflow: onOpenWorkflow}) {
1394
- return groups.withDocuments.length === 0 && groups.withoutDocuments.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(MutedNote, {
1395
- text: "No tasks match — adjust the filters, or start a workflow"
1396
- }) : /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
1397
- gap: 2,
1398
- children: [ groups.withDocuments.map(group => /* @__PURE__ */ jsxRuntime.jsx(DocumentTaskGroup, {
1399
- group: group,
1400
- onOpenTask: onOpenTask,
1401
- onOpenWorkflow: onOpenWorkflow
1402
- }, group.key)), groups.withoutDocuments.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(CollapsibleGroup, {
1403
- header: /* @__PURE__ */ jsxRuntime.jsx(GroupTitle, {
1404
- text: "Workflows without Studio documents"
1405
- }),
1406
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.Stack, {
1407
- gap: 2,
1408
- paddingLeft: 2,
1409
- children: groups.withoutDocuments.map(group => /* @__PURE__ */ jsxRuntime.jsx(CollapsibleGroup, {
1410
- header: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
1411
- children: [
1412
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
1413
- muted: !0,
1414
- size: 1,
1415
- children: /* @__PURE__ */ jsxRuntime.jsx(index.StageGlyph, {})
1416
- }),
1417
- /* @__PURE__ */ jsxRuntime.jsx(WorkflowBadgeTitle, {
1418
- group: group
1419
- }),
1420
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
1421
- flex: 1
1422
- }),
1423
- /* @__PURE__ */ jsxRuntime.jsx(GroupMenu, {
1424
- group: group,
1425
- onOpenWorkflow: onOpenWorkflow
1426
- }) ]
1427
- }),
1428
- children: /* @__PURE__ */ jsxRuntime.jsx(TaskRows, {
1429
- onOpenTask: onOpenTask,
1430
- rows: group.rows
1431
- })
1432
- }, group.key))
1220
+ function ActivityDateControl({instanceId: instanceId, state: state, dates: dates}) {
1221
+ const {editFieldFor: editFieldFor} = index.useWorkflowContext(), {save: save} = index.useSaveField(), [open, setOpen] = react.useState(!1), raw = index.dateControlValue({
1222
+ state: state,
1223
+ dates: dates
1224
+ }), display = raw === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
1225
+ muted: !0,
1226
+ size: 1,
1227
+ children: index.formatDate(raw)
1228
+ });
1229
+ if (state.kind === "none") return display;
1230
+ if (state.kind === "closed") return display === null ? null : /* @__PURE__ */ jsxRuntime.jsx(index.HoverHint, {
1231
+ text: state.reason,
1232
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
1233
+ "aria-label": "Date",
1234
+ as: "span",
1235
+ fontSize: 1,
1236
+ mode: "bleed",
1237
+ onClick: index.stopRowClick,
1238
+ onMouseDown: index.stopRowMouseDown,
1239
+ padding: 2,
1240
+ children: display
1241
+ })
1242
+ });
1243
+ const kind = index.dateControlKind(state), commit = (mode, value) => {
1244
+ state.kind === "editable" && save(() => editFieldFor(instanceId, {
1245
+ target: index.editTargetOf(state.field),
1246
+ ...mode === "set" ? {
1247
+ mode: mode,
1248
+ value: value
1249
+ } : {
1250
+ mode: mode
1251
+ }
1252
+ }).then(() => {}));
1253
+ }, handleClick = e => {
1254
+ e.stopPropagation(), setOpen(v => !v);
1255
+ };
1256
+ /* @__PURE__ */
1257
+ return jsxRuntime.jsx(index.DismissablePopover, {
1258
+ content: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
1259
+ onClick: index.stopRowClick,
1260
+ children: state.kind === "loading" || kind === void 0 ? /* @__PURE__ */ jsxRuntime.jsx(index.LoadingRow, {
1261
+ label: "Loading…",
1262
+ padding: 3
1263
+ }) : /* @__PURE__ */ jsxRuntime.jsx(workflowComponents.ClearableDatePicker, {
1264
+ clearLabel: "Clear date",
1265
+ onClear: () => {
1266
+ setOpen(!1), commit("unset");
1267
+ },
1268
+ onPick: next => {
1269
+ kind === "date" && setOpen(!1), commit("set", index.serializeDateFieldValue(next, kind));
1270
+ },
1271
+ selectTime: kind === "datetime",
1272
+ value: index.parseDateFieldValue(state.field.value, kind)
1433
1273
  })
1434
- }) : null ]
1274
+ }),
1275
+ onDismiss: () => setOpen(!1),
1276
+ open: open,
1277
+ children: display ? /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
1278
+ "aria-label": "Change date",
1279
+ as: "span",
1280
+ fontSize: 1,
1281
+ mode: "bleed",
1282
+ onClick: handleClick,
1283
+ onMouseDown: index.stopRowMouseDown,
1284
+ padding: 2,
1285
+ children: display
1286
+ }) : /* @__PURE__ */ jsxRuntime.jsx(index.HoverHint, {
1287
+ disabled: open,
1288
+ text: "Set date",
1289
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
1290
+ "aria-label": "Set date",
1291
+ as: "span",
1292
+ fontSize: 1,
1293
+ icon: Calendar.CalendarIcon,
1294
+ mode: "bleed",
1295
+ onClick: handleClick,
1296
+ onMouseDown: index.stopRowMouseDown,
1297
+ padding: 2
1298
+ })
1299
+ })
1435
1300
  });
1436
1301
  }
1437
1302
 
1438
- function GroupTitle({text: text}) {
1303
+ function RefChips({refs: refs, max: max = 2}) {
1304
+ if (refs.length === 0) return null;
1305
+ const shown = refs.slice(0, max), overflow = refs.length - shown.length;
1439
1306
  /* @__PURE__ */
1440
- return jsxRuntime.jsx(ui.Text, {
1441
- size: 1,
1442
- weight: "semibold",
1443
- children: text
1307
+ return jsxRuntime.jsxs(ui.Flex, {
1308
+ align: "center",
1309
+ gap: 3,
1310
+ wrap: "wrap",
1311
+ children: [ shown.map(ref => /* @__PURE__ */ jsxRuntime.jsx(index.DocPreviewLink, {
1312
+ gdr: ref,
1313
+ layout: "inline"
1314
+ }, ref.id)), overflow > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, {
1315
+ muted: !0,
1316
+ size: 1,
1317
+ children: [ "+", overflow, " more" ]
1318
+ }) : null ]
1444
1319
  });
1445
1320
  }
1446
1321
 
1447
- function WorkflowBadgeTitle({group: group}) {
1448
- const badge = /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, {
1449
- fontSize: 1,
1450
- mode: "outline",
1451
- children: group.workflowTitle
1452
- });
1453
- return group.workflowDescription ? /* @__PURE__ */ jsxRuntime.jsx(index.HoverHint, {
1454
- text: group.workflowDescription,
1455
- children: badge
1456
- }) : badge;
1457
- }
1322
+ const EMPTY_NOTE = "No tasks match — adjust the filters, or start a workflow", UNGROUPED_TITLE = "Workflows without Studio documents";
1458
1323
 
1459
- function CollapsibleGroup({header: header, children: children}) {
1460
- const [open, setOpen] = react.useState(!0);
1461
- /* @__PURE__ */
1462
- return jsxRuntime.jsxs(ui.Stack, {
1324
+ function TaskGroupList({groups: groups, onOpenTask: onOpenTask, onOpenWorkflow: onOpenWorkflow, showTerminalActions: showTerminalActions}) {
1325
+ return groups.withDocuments.length === 0 && groups.withoutDocuments.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(MutedNote, {
1326
+ text: EMPTY_NOTE
1327
+ }) : /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
1463
1328
  gap: 2,
1464
- children: [
1465
- /* @__PURE__ */ jsxRuntime.jsx(ui.Card, {
1466
- paddingX: 2,
1467
- paddingY: 2,
1468
- radius: 2,
1469
- tone: "transparent",
1470
- children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
1329
+ children: [ groups.withDocuments.map(group => /* @__PURE__ */ jsxRuntime.jsx(index.CollapsibleBand, {
1330
+ background: !0,
1331
+ sticky: !0,
1332
+ title: workflowEngine.extractDocumentId(group.document.id),
1333
+ header: /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
1471
1334
  align: "center",
1472
- gap: 2,
1473
- children: [
1474
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
1475
- "aria-label": open ? "Collapse" : "Expand",
1476
- fontSize: 1,
1477
- icon: open ? ChevronDown.ChevronDownIcon : ChevronRight.ChevronRightIcon,
1478
- mode: "bleed",
1479
- onClick: () => setOpen(v => !v),
1480
- padding: 1
1481
- }), header ]
1482
- })
1483
- }), open ? children : null ]
1484
- });
1485
- }
1486
-
1487
- function DocumentTaskGroup({group: group, onOpenTask: onOpenTask, onOpenWorkflow: onOpenWorkflow}) {
1488
- const document = group.document;
1489
- return document ? /* @__PURE__ */ jsxRuntime.jsx(CollapsibleGroup, {
1490
- header: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
1491
- children: [
1492
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
1493
1335
  flex: "none",
1494
1336
  style: {
1495
1337
  maxWidth: "60%"
@@ -1498,323 +1340,333 @@ function DocumentTaskGroup({group: group, onOpenTask: onOpenTask, onOpenWorkflow
1498
1340
  max: 2,
1499
1341
  refs: group.documents
1500
1342
  })
1501
- }),
1502
- /* @__PURE__ */ jsxRuntime.jsx(WorkflowBadgeTitle, {
1503
- group: group
1504
- }),
1505
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
1506
- flex: 1
1507
- }),
1508
- /* @__PURE__ */ jsxRuntime.jsx(GroupMenu, {
1509
- document: document,
1510
- group: group,
1511
- onOpenWorkflow: onOpenWorkflow
1512
- }) ]
1513
- }),
1514
- children: /* @__PURE__ */ jsxRuntime.jsx(TaskRows, {
1343
+ }),
1344
+ children: /* @__PURE__ */ jsxRuntime.jsx(InstanceBands, {
1345
+ instances: group.instances,
1346
+ onOpenTask: onOpenTask,
1347
+ onOpenWorkflow: onOpenWorkflow,
1348
+ showTerminalActions: showTerminalActions
1349
+ })
1350
+ }, group.key)), groups.withoutDocuments.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(index.CollapsibleBand, {
1351
+ background: !0,
1352
+ sticky: !0,
1353
+ title: UNGROUPED_TITLE,
1354
+ header: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
1355
+ size: 1,
1356
+ weight: "semibold",
1357
+ children: UNGROUPED_TITLE
1358
+ }),
1359
+ children: /* @__PURE__ */ jsxRuntime.jsx(InstanceBands, {
1360
+ instances: groups.withoutDocuments,
1361
+ onOpenTask: onOpenTask,
1362
+ onOpenWorkflow: onOpenWorkflow,
1363
+ showTerminalActions: showTerminalActions
1364
+ })
1365
+ }) : null ]
1366
+ });
1367
+ }
1368
+
1369
+ function targetOf(row) {
1370
+ return {
1371
+ instanceId: row.instanceId,
1372
+ stage: row.stage,
1373
+ activityName: row.activityName
1374
+ };
1375
+ }
1376
+
1377
+ function InstanceBands({instances: instances, onOpenTask: onOpenTask, onOpenWorkflow: onOpenWorkflow, showTerminalActions: showTerminalActions}) {
1378
+ /* @__PURE__ */
1379
+ return jsxRuntime.jsx(ui.Stack, {
1380
+ gap: 1,
1381
+ children: instances.map(band => /* @__PURE__ */ jsxRuntime.jsx(InstanceBand, {
1382
+ band: band,
1515
1383
  onOpenTask: onOpenTask,
1516
- rows: group.rows
1517
- })
1518
- }) : null;
1384
+ onOpenWorkflow: onOpenWorkflow,
1385
+ showTerminalActions: showTerminalActions
1386
+ }, band.instanceId))
1387
+ });
1519
1388
  }
1520
1389
 
1521
- function GroupMenu({group: group, document: document, onOpenWorkflow: onOpenWorkflow}) {
1522
- const router$1 = router.useRouter(), state = index.useDocLink(document);
1390
+ function InstanceBand({band: band, onOpenTask: onOpenTask, onOpenWorkflow: onOpenWorkflow, showTerminalActions: showTerminalActions}) {
1391
+ const {resolvePathFromState: resolvePathFromState} = router.useRouter();
1523
1392
  /* @__PURE__ */
1524
- return jsxRuntime.jsx(index.HintedMenuButton, {
1525
- button: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
1526
- "aria-label": "Group actions",
1527
- fontSize: 1,
1528
- icon: EllipsisHorizontal.EllipsisHorizontalIcon,
1529
- mode: "bleed",
1530
- padding: 2
1531
- }),
1532
- hint: "Group actions",
1533
- id: `task-group-menu-${group.key}`,
1534
- menu: /* @__PURE__ */ jsxRuntime.jsxs(ui.Menu, {
1393
+ return jsxRuntime.jsx(index.CollapsibleBand, {
1394
+ title: band.title,
1395
+ header: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
1535
1396
  children: [
1536
- /* @__PURE__ */ jsxRuntime.jsx(ui.MenuItem, {
1537
- onClick: () => onOpenWorkflow(group.instanceId),
1538
- text: "View workflow"
1539
- }), state.kind === "linked" ? /* @__PURE__ */ jsxRuntime.jsx(ui.MenuItem, {
1540
- onClick: () => router$1.navigateIntent("edit", {
1541
- id: state.bareId
1397
+ /* @__PURE__ */ jsxRuntime.jsx(index.LinkChip, {
1398
+ hint: "View workflow",
1399
+ href: resolvePathFromState({
1400
+ instanceId: band.instanceId
1542
1401
  }),
1543
- text: "Open document"
1544
- }) : null ]
1402
+ onClick: event => {
1403
+ event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || (event.preventDefault(),
1404
+ onOpenWorkflow(band.instanceId));
1405
+ },
1406
+ children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
1407
+ align: "center",
1408
+ gap: 2,
1409
+ style: {
1410
+ minWidth: 0
1411
+ },
1412
+ children: [
1413
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
1414
+ size: 1,
1415
+ style: {
1416
+ minWidth: 0
1417
+ },
1418
+ textOverflow: "ellipsis",
1419
+ weight: "medium",
1420
+ children: band.title
1421
+ }), band.breadcrumb === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(index.BreadcrumbTail, {
1422
+ segments: [ band.breadcrumb ]
1423
+ }),
1424
+ /* @__PURE__ */ jsxRuntime.jsx(index.StageFace, {
1425
+ title: band.stageTitle
1426
+ }) ]
1427
+ })
1428
+ }),
1429
+ /* @__PURE__ */ jsxRuntime.jsx(index.TrailingHairline, {}) ]
1545
1430
  }),
1546
- popover: {
1547
- portal: !0
1548
- }
1431
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
1432
+ paddingLeft: 5,
1433
+ children: /* @__PURE__ */ jsxRuntime.jsx(TaskRows, {
1434
+ onOpenTask: onOpenTask,
1435
+ rows: band.rows,
1436
+ showTerminalActions: showTerminalActions
1437
+ })
1438
+ })
1549
1439
  });
1550
1440
  }
1551
1441
 
1552
- function TaskRows({rows: rows, onOpenTask: onOpenTask}) {
1442
+ function TaskRows({rows: rows, onOpenTask: onOpenTask, showTerminalActions: showTerminalActions}) {
1553
1443
  /* @__PURE__ */
1554
1444
  return jsxRuntime.jsx(ui.Stack, {
1555
- children: rows.map(row => /* @__PURE__ */ jsxRuntime.jsx(TaskRowButton, {
1556
- onOpen: () => onOpenTask({
1557
- instanceId: row.instanceId,
1558
- stage: row.stage,
1559
- activityName: row.activityName
1560
- }),
1561
- row: row
1445
+ gap: 1,
1446
+ children: rows.map(row => /* @__PURE__ */ jsxRuntime.jsx(TaskActivityRow, {
1447
+ onOpen: () => onOpenTask(targetOf(row)),
1448
+ row: row,
1449
+ showTerminalActions: showTerminalActions
1562
1450
  }, `${row.instanceId}:${row.activityName}`))
1563
1451
  });
1564
1452
  }
1565
1453
 
1566
- function RowDate({dates: dates}) {
1567
- const first = dates.find(value => index.parseStoredDateValue(value) !== void 0);
1568
- return first === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
1569
- muted: !0,
1570
- size: 1,
1571
- children: index.formatDate(first)
1572
- });
1573
- }
1574
-
1575
- function RowTitle({row: row}) {
1576
- const title = /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
1577
- size: 1,
1578
- style: row.open ? void 0 : {
1579
- opacity: .66
1580
- },
1581
- weight: "medium",
1582
- children: row.title
1454
+ function TaskActivityRow({row: row, onOpen: onOpen, showTerminalActions: showTerminalActions}) {
1455
+ const entry = index.useWorkflowInstanceEntry(row.instanceId), render = taskRowRender(row, entry);
1456
+ /* @__PURE__ */
1457
+ return jsxRuntime.jsx(index.StaleLock, {
1458
+ stale: render.stale,
1459
+ children: /* @__PURE__ */ jsxRuntime.jsx(index.ActivityRow, {
1460
+ assignState: render.assignState,
1461
+ assigneeIds: render.assigneeIds,
1462
+ dateControl: /* @__PURE__ */ jsxRuntime.jsx(ActivityDateControl, {
1463
+ dates: render.dates,
1464
+ instanceId: row.instanceId,
1465
+ state: render.dateState
1466
+ }),
1467
+ face: render.face,
1468
+ instanceId: row.instanceId,
1469
+ onOpen: onOpen,
1470
+ terminalActions: showTerminalActions ? render.terminalActions : []
1471
+ })
1583
1472
  });
1584
- return row.description ? /* @__PURE__ */ jsxRuntime.jsx(index.HoverHint, {
1585
- text: row.description,
1586
- children: title
1587
- }) : title;
1588
1473
  }
1589
1474
 
1590
- function RowBreadcrumb({breadcrumb: breadcrumb}) {
1591
- return breadcrumb ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
1592
- align: "center",
1593
- gap: 2,
1594
- children: [
1595
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
1596
- muted: !0,
1597
- size: 1,
1598
- children: breadcrumb
1599
- }),
1600
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
1601
- muted: !0,
1602
- size: 1,
1603
- children: /* @__PURE__ */ jsxRuntime.jsx(ChevronRight.ChevronRightIcon, {})
1604
- }) ]
1605
- }) : null;
1606
- }
1475
+ const INSTANCE_CAP = 200, NEWEST_INSTANCES = {
1476
+ includeCompleted: !0,
1477
+ limit: INSTANCE_CAP
1478
+ };
1607
1479
 
1608
- function TaskRowButton({row: row, onOpen: onOpen}) {
1609
- /* @__PURE__ */
1610
- return jsxRuntime.jsx(ui.Card, {
1611
- as: "button",
1612
- onClick: onOpen,
1613
- padding: 3,
1614
- paddingLeft: 4,
1615
- radius: 2,
1616
- style: {
1617
- cursor: "pointer",
1618
- textAlign: "left"
1619
- },
1620
- children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
1621
- align: "center",
1622
- gap: 3,
1623
- children: [
1624
- /* @__PURE__ */ jsxRuntime.jsx(index.ActivityStatusIcon, {
1625
- status: row.status
1626
- }),
1627
- /* @__PURE__ */ jsxRuntime.jsx(RowBreadcrumb, {
1628
- breadcrumb: row.breadcrumb
1629
- }),
1630
- /* @__PURE__ */ jsxRuntime.jsx(RowTitle, {
1631
- row: row
1632
- }),
1633
- /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, {
1634
- fontSize: 1,
1635
- mode: "outline",
1636
- tone: "default",
1637
- children: row.stageTitle
1638
- }),
1639
- /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
1640
- flex: 1
1641
- }),
1642
- /* @__PURE__ */ jsxRuntime.jsx(RowDate, {
1643
- dates: row.dates
1644
- }), row.assigneeIds.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(index.UserAvatarGroup, {
1645
- ids: row.assigneeIds
1646
- }) : null ]
1647
- })
1480
+ function useToolInstances() {
1481
+ const {engine: engine} = index.useWorkflowContext(), {instances: instances, loading: loading, unreadable: unreadable} = workflowStudio.useWorkflowInstances({
1482
+ engine: engine,
1483
+ filter: NEWEST_INSTANCES
1648
1484
  });
1485
+ return react.useMemo(() => {
1486
+ const rows = instances ?? [];
1487
+ return {
1488
+ inFlight: rows.filter(instance => workflowEngine.terminalState(instance) === "in-flight"),
1489
+ settled: rows.filter(instance => workflowEngine.terminalState(instance) !== "in-flight"),
1490
+ truncated: rows.length + unreadable.length === INSTANCE_CAP,
1491
+ loading: loading,
1492
+ unreadable: unreadable
1493
+ };
1494
+ }, [ instances, loading, unreadable ]);
1649
1495
  }
1650
1496
 
1651
- function TasksTab({instances: instances, loading: loading, identity: identity, onOpenTask: onOpenTask, onOpenWorkflow: onOpenWorkflow, truncated: truncated}) {
1652
- const [segment, setSegment] = react.useState("mine"), [filters, setFilters] = react.useState({}), groups = react.useMemo(() => deriveTaskGroups({
1497
+ function TasksTab({filterSlot: filterSlot, instances: instances, loading: loading, identity: identity, mineOnly: mineOnly, onOpenTask: onOpenTask, onOpenWorkflow: onOpenWorkflow, truncated: truncated, unreadable: unreadable}) {
1498
+ const [filters, setFilters] = react.useState({}), groups = react.useMemo(() => deriveTaskGroups({
1653
1499
  instances: instances,
1654
1500
  identity: identity
1655
1501
  }), [ instances, identity ]), options = react.useMemo(() => taskFilterOptions(groups), [ groups ]), visible = react.useMemo(() => {
1656
- const segmented = segment === "mine" ? onlyMyTasks(groups) : groups;
1657
- return applyTaskFilters({
1658
- groups: segmented,
1502
+ const filtered = applyTaskFilters({
1503
+ groups: groups,
1659
1504
  filters: filters,
1660
1505
  now: /* @__PURE__ */ new Date
1661
1506
  });
1662
- }, [ groups, segment, filters ]);
1663
- return loading ? /* @__PURE__ */ jsxRuntime.jsx(index.LoadingRow, {
1664
- label: "Loading tasks…"
1507
+ return mineOnly ? onlyMyTasks(filtered) : filtered;
1508
+ }, [ groups, filters, mineOnly ]);
1509
+ return loading ?
1510
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
1511
+ paddingLeft: 2,
1512
+ children: /* @__PURE__ */ jsxRuntime.jsx(index.LoadingRow, {
1513
+ label: "Loading tasks…"
1514
+ })
1665
1515
  }) : /* @__PURE__ */ jsxRuntime.jsxs(ui.Box, {
1666
1516
  children: [
1667
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
1668
- align: "center",
1517
+ /* @__PURE__ */ jsxRuntime.jsx(FilterRowPortal, {
1518
+ filters: filters,
1519
+ onChange: setFilters,
1520
+ options: options,
1521
+ slot: filterSlot
1522
+ }),
1523
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
1669
1524
  gap: 2,
1670
- paddingBottom: 3,
1671
1525
  children: [
1672
- /* @__PURE__ */ jsxRuntime.jsxs(ui.TabList, {
1673
- gap: 1,
1674
- children: [
1675
- /* @__PURE__ */ jsxRuntime.jsx(ui.Tab, {
1676
- "aria-controls": "workflow-tasks-panel",
1677
- fontSize: 1,
1678
- id: "workflow-tasks-mine",
1679
- label: "My tasks",
1680
- onClick: () => setSegment("mine"),
1681
- padding: 2,
1682
- selected: segment === "mine"
1683
- }),
1684
- /* @__PURE__ */ jsxRuntime.jsx(ui.Tab, {
1685
- "aria-controls": "workflow-tasks-panel",
1686
- fontSize: 1,
1687
- id: "workflow-tasks-all",
1688
- label: "All tasks",
1689
- onClick: () => setSegment("all"),
1690
- padding: 2,
1691
- selected: segment === "all"
1692
- }) ]
1693
- }),
1694
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
1695
- flex: 1
1696
- }),
1697
- /* @__PURE__ */ jsxRuntime.jsx(ActiveFilterChips, {
1698
- filters: filters,
1699
- onChange: setFilters,
1700
- options: options
1526
+ /* @__PURE__ */ jsxRuntime.jsx(index.UnreadableDocsNote, {
1527
+ unreadable: unreadable
1701
1528
  }),
1702
- /* @__PURE__ */ jsxRuntime.jsx(TaskFilterMenu, {
1703
- filters: filters,
1704
- onChange: setFilters,
1705
- options: options
1706
- }) ]
1707
- }),
1708
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Box, {
1709
- id: "workflow-tasks-panel",
1710
- children: [
1711
1529
  /* @__PURE__ */ jsxRuntime.jsx(TaskGroupList, {
1712
1530
  groups: visible,
1713
1531
  onOpenTask: onOpenTask,
1714
- onOpenWorkflow: onOpenWorkflow
1715
- }), truncated ? /* @__PURE__ */ jsxRuntime.jsx(MutedNote, {
1716
- text: `Tasks from the latest ${INSTANCE_CAP} workflows — older ones aren't listed.`
1717
- }) : null ]
1718
- }) ]
1532
+ onOpenWorkflow: onOpenWorkflow,
1533
+ showTerminalActions: mineOnly
1534
+ }) ]
1535
+ }), truncated ? /* @__PURE__ */ jsxRuntime.jsx(MutedNote, {
1536
+ text: `Tasks from the latest ${INSTANCE_CAP} workflows — older ones aren't listed.`
1537
+ }) : null ]
1719
1538
  });
1720
1539
  }
1721
1540
 
1541
+ const TOOL_TABS = [ {
1542
+ value: "overview",
1543
+ label: "Overview"
1544
+ }, {
1545
+ value: "for-me",
1546
+ label: "For me"
1547
+ } ], [firstToolTab, ...restToolTabs] = TOOL_TABS, TOOL_TAB_CODEC = index.workflowsTabCodec([ firstToolTab.value, ...restToolTabs.map(tab => tab.value) ]);
1548
+
1549
+ function useToolTab() {
1550
+ const router$1 = router.useRouter(), params = Object.fromEntries(router$1.state._searchParams ?? []);
1551
+ return {
1552
+ tab: TOOL_TAB_CODEC.read(params),
1553
+ setTab: next => router$1.navigate({
1554
+ _searchParams: definedEntries(TOOL_TAB_CODEC.write(params, next))
1555
+ })
1556
+ };
1557
+ }
1558
+
1559
+ function definedEntries(params) {
1560
+ return Object.entries(params).filter(entry => entry[1] !== void 0);
1561
+ }
1562
+
1563
+ function carryingSearchParams(state, searchParams) {
1564
+ return searchParams === void 0 ? state : {
1565
+ ...state,
1566
+ _searchParams: searchParams
1567
+ };
1568
+ }
1569
+
1722
1570
  function WorkflowsToolRoot() {
1723
1571
  const router$1 = router.useRouter(), {seedInstance: seedInstance} = index.useWorkflowContext(), instanceId = typeof router$1.state.instanceId == "string" ? router$1.state.instanceId : void 0;
1724
1572
  return instanceId ? /* @__PURE__ */ jsxRuntime.jsx(WorkflowInstanceDetail, {
1725
1573
  instanceId: instanceId,
1726
- onBack: () => router$1.navigate({})
1574
+ onBack: () => router$1.navigate(carryingSearchParams({}, router$1.state._searchParams))
1727
1575
  }, instanceId) : /* @__PURE__ */ jsxRuntime.jsx(WorkflowsHome, {
1728
1576
  onOpenInstance: instance => {
1729
- typeof instance != "string" && seedInstance(instance), router$1.navigate({
1577
+ typeof instance != "string" && seedInstance(instance), router$1.navigate(carryingSearchParams({
1730
1578
  instanceId: typeof instance == "string" ? instance : instance._id
1731
- });
1579
+ }, router$1.state._searchParams));
1732
1580
  }
1733
1581
  });
1734
1582
  }
1735
1583
 
1736
- function ToolPanel({identity: identity, instances: instances, onOpenInstance: onOpenInstance, onOpenTask: onOpenTask, tab: tab}) {
1737
- return instances.invalid ? /* @__PURE__ */ jsxRuntime.jsx(index.InvalidDocNotice, {
1738
- invalid: instances.invalid
1739
- }) : tab === "tasks" ? /* @__PURE__ */ jsxRuntime.jsx(TasksTab, {
1740
- identity: identity,
1741
- instances: [ ...instances.inFlight, ...instances.settled ],
1742
- loading: instances.loading,
1743
- onOpenTask: onOpenTask,
1744
- onOpenWorkflow: onOpenInstance,
1745
- truncated: instances.truncated
1746
- }) : /* @__PURE__ */ jsxRuntime.jsx(WorkflowsDashboard, {
1747
- instances: instances,
1748
- onOpenInstance: onOpenInstance
1749
- });
1750
- }
1751
-
1752
1584
  function WorkflowsHome({onOpenInstance: onOpenInstance}) {
1753
- const [tab, setTab] = react.useState("tasks"), instances = useToolInstances(), identity = index.useAssignmentIdentity(), [openTask, setOpenTask] = react.useState(null);
1754
- /* @__PURE__ */
1755
- return jsxRuntime.jsxs(ui.Card, {
1585
+ const {tab: tab, setTab: setTab} = useToolTab(), instances = useToolInstances(), identity = index.useAssignmentIdentity(), [openTask, setOpenTask] = react.useState(null), openInstance = target => {
1586
+ if (typeof target != "string") return onOpenInstance(target);
1587
+ const held = [ ...instances.inFlight, ...instances.settled ].find(i => i._id === target);
1588
+ onOpenInstance(held ?? target);
1589
+ }, [filterSlot, setFilterSlot] = react.useState(null), scrollerRef = react.useRef(null);
1590
+ return react.useEffect(() => {
1591
+ scrollerRef.current?.scrollTo({
1592
+ top: 0
1593
+ });
1594
+ }, [ tab ]),
1595
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Card, {
1756
1596
  height: "fill",
1757
- overflow: "auto",
1758
1597
  children: [
1759
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
1760
- padding: 4,
1761
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.Container, {
1762
- width: 2,
1763
- children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
1764
- gap: 4,
1765
- children: [
1766
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
1767
- align: "center",
1598
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
1599
+ direction: "column",
1600
+ height: "fill",
1601
+ overflow: "hidden",
1602
+ children: [
1603
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
1604
+ flex: "none",
1605
+ padding: 3,
1606
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Container, {
1607
+ width: 2,
1608
+ children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
1768
1609
  gap: 3,
1769
1610
  children: [
1770
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
1771
- size: 2,
1772
- weight: "semibold",
1773
- children: "Workflows"
1774
- }),
1775
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
1776
- flex: 1
1611
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
1612
+ align: "center",
1613
+ gap: 3,
1614
+ paddingLeft: 2,
1615
+ children: [
1616
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
1617
+ size: 2,
1618
+ weight: "semibold",
1619
+ children: "Workflows"
1620
+ }),
1621
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
1622
+ flex: 1
1623
+ }),
1624
+ /* @__PURE__ */ jsxRuntime.jsx(NewWorkflowButton, {}) ]
1777
1625
  }),
1778
- /* @__PURE__ */ jsxRuntime.jsx(NewWorkflowButton, {}) ]
1779
- }),
1780
- /* @__PURE__ */ jsxRuntime.jsxs(ui.TabList, {
1781
- gap: 1,
1782
- children: [
1783
- /* @__PURE__ */ jsxRuntime.jsx(ui.Tab, {
1784
- "aria-controls": "workflows-tool-panel",
1785
- fontSize: 1,
1786
- id: "workflows-tool-tab-tasks",
1787
- label: "Tasks",
1788
- onClick: () => setTab("tasks"),
1789
- padding: 2,
1790
- selected: tab === "tasks"
1626
+ /* @__PURE__ */ jsxRuntime.jsx(index.TabSwitch, {
1627
+ ariaControls: "workflows-tool-panel",
1628
+ idPrefix: "workflows-tool-tab",
1629
+ onSelect: setTab,
1630
+ options: TOOL_TABS,
1631
+ selected: tab
1791
1632
  }),
1792
- /* @__PURE__ */ jsxRuntime.jsx(ui.Tab, {
1793
- "aria-controls": "workflows-tool-panel",
1794
- fontSize: 1,
1795
- id: "workflows-tool-tab-workflows",
1796
- label: "All workflows",
1797
- onClick: () => setTab("workflows"),
1798
- padding: 2,
1799
- selected: tab === "workflows"
1633
+ /* @__PURE__ */ jsxRuntime.jsx("div", {
1634
+ ref: setFilterSlot
1800
1635
  }) ]
1801
- }),
1802
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
1636
+ })
1637
+ })
1638
+ }),
1639
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
1640
+ ref: scrollerRef,
1641
+ flex: 1,
1642
+ overflow: "auto",
1643
+ paddingX: 3,
1644
+ style: {
1645
+ scrollbarGutter: "stable"
1646
+ },
1647
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Container, {
1648
+ width: 2,
1649
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.TabPanel, {
1650
+ "aria-labelledby": `workflows-tool-tab-${tab}`,
1803
1651
  id: "workflows-tool-panel",
1804
- children: /* @__PURE__ */ jsxRuntime.jsx(ToolPanel, {
1805
- identity: identity,
1806
- instances: instances,
1807
- onOpenInstance: target => {
1808
- if (typeof target != "string") return onOpenInstance(target);
1809
- const held = [ ...instances.inFlight, ...instances.settled ].find(i => i._id === target);
1810
- onOpenInstance(held ?? target);
1811
- },
1812
- onOpenTask: setOpenTask,
1813
- tab: tab
1652
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
1653
+ paddingBottom: 4,
1654
+ paddingTop: 1,
1655
+ children: /* @__PURE__ */ jsxRuntime.jsx(TasksTab, {
1656
+ filterSlot: filterSlot,
1657
+ identity: identity,
1658
+ instances: [ ...instances.inFlight, ...instances.settled ],
1659
+ loading: instances.loading,
1660
+ mineOnly: tab === "for-me",
1661
+ onOpenTask: setOpenTask,
1662
+ onOpenWorkflow: openInstance,
1663
+ truncated: instances.truncated,
1664
+ unreadable: instances.unreadable
1665
+ })
1814
1666
  })
1815
- }) ]
1667
+ })
1816
1668
  })
1817
- })
1669
+ }) ]
1818
1670
  }), openTask ? /* @__PURE__ */ jsxRuntime.jsx(ToolActivityDialog, {
1819
1671
  onClose: () => setOpenTask(null),
1820
1672
  target: openTask