@sanity/workflow-studio-plugin 0.22.0 → 0.23.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,6 +1,6 @@
1
1
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
2
 
3
- import { Stack, Box, Flex, Text, Button, Card, TextInput, Dialog, Badge, useTheme_v2, Container, TabPanel } from "@sanity/ui";
3
+ import { Box, Text, Flex, Stack, Card, Badge, Menu, MenuItem, Button, useTheme_v2, TextInput, Dialog, TabPanel } from "@sanity/ui";
4
4
 
5
5
  import { useWorkflowTelemetry, editFieldTarget } from "@sanity/workflow-react";
6
6
 
@@ -8,20 +8,32 @@ import { useState, useEffect, useMemo, useRef } from "react";
8
8
 
9
9
  import { useRouter } from "sanity/router";
10
10
 
11
- import { instanceNotice, StaleLock, ActivitiesList, TodoItemsList, isEvaluationStale, useWorkflowInstanceEntry, useLogEventOnMount, WorkflowInstanceDetailViewed, InvalidDocNotice, LoadingRow, useDefinition, openActivityGone, GroupHeading, ActivityDetailDialog, instanceBreadcrumb, HoverHint, instanceTitle, formatDate, StageChip, stageTitle, AbortedBadge, SpinnerSlot, DocPreviewLink, useWorkflowContext, readDeployedDefinitions, describeError, DismissablePopover, definitionSnapshotOf, findActivity, stateByActivity, findActivityNode, rowDateControlState, rowAssignControlState, isActivityAssignedTo, assigneeUserIdsOf, isOpenActivityStatus, committedRowFace, activityRowProps, gdrLocality, CautionNote, WORKFLOW_API_VERSION, useClosableToast, parseStoredDateValue, useUserDisplays, useProjectMembers, WorkflowTaskFiltersApplied, DocRefFace, useSaveField, dateControlValue, stopRowMouseDown, stopRowClick, parseDateFieldValue, serializeDateFieldValue, dateControlKind, CollapsibleBand, LinkChip, BreadcrumbTail, StageFace, TrailingHairline, ActivityRow, UnreadableDocsNote, useAssignmentIdentity, TabSwitch, WorkflowToolOpened, workflowsTabCodec } from "./index.js";
11
+ import { useSpaceToken, DocPreviewLink, SpinnerSlot, useWorkflowContext, readDeployedDefinitions, describeError, useContainerToken, LoadingRow, MetaRow, formatDate, HoverHint, useBadgeCapTrim, stageTitle, useClosableToast, UserAvatar, formatShortAgo, formatDateTime, useAvatarSize, HintedMenuButton, useUserDisplay, useWorkflowInstanceEntry, useLogEventOnMount, WorkflowInstanceDetailViewed, InvalidDocNotice, useDefinition, openActivityGone, instanceTitle, isEvaluationStale, InstanceSnapshotBody, ActivityDetailDialog, instanceBreadcrumb, DismissablePopover, definitionSnapshotOf, findActivity, stateByActivity, findActivityNode, rowDateControlState, rowAssignControlState, isActivityAssignedTo, assigneeUserIdsOf, isOpenActivityStatus, committedRowFace, activityRowProps, gdrLocality, CautionNote, WORKFLOW_API_VERSION, parseStoredDateValue, openableSchemaType, useUserDisplays, useProjectMembers, WorkflowTaskFiltersApplied, DocRefFace, useSaveField, dateControlValue, stopRowMouseDown, stopRowClick, parseDateFieldValue, serializeDateFieldValue, dateControlKind, CollapsibleBand, LinkChip, BreadcrumbTail, StageFace, TrailingHairline, StaleLock, ActivityRow, UnreadableDocsNote, ForMeEmptyState, pathSegmentTab, TabSwitch, WorkflowToolOpened, useAssignmentIdentity } from "./index.js";
12
+
13
+ import { WorkflowDiagram } from "@sanity/workflow-diagram";
14
+
15
+ import { useSchema, useClient, useDocumentPreviewStore, usePerspective } from "sanity";
16
+
17
+ import { startKindOf, isSubjectEntry, isInputSourced, latestDeployedDefinitions, terminalState, entryDocRefs, isStartableDefinition, toBareId, findOpenStageEntry } from "@sanity/workflow-engine";
18
+
19
+ import { InfoOutlineIcon } from "@sanity/icons/InfoOutline";
20
+
21
+ import pluralize from "pluralize-esm";
22
+
23
+ import { useWorkflowInstances } from "@sanity/workflow-studio";
12
24
 
13
25
  import { ArrowLeftIcon } from "@sanity/icons/ArrowLeft";
14
26
 
15
- import { WorkflowDiagram } from "@sanity/workflow-diagram";
27
+ import { ClockIcon } from "@sanity/icons/Clock";
28
+
29
+ import { CogIcon } from "@sanity/icons/Cog";
16
30
 
17
- import { entryDocRefs, terminalState, latestDeployedDefinitions, isStartableDefinition, toBareId, findOpenStageEntry } from "@sanity/workflow-engine";
31
+ import { EllipsisHorizontalIcon } from "@sanity/icons/EllipsisHorizontal";
18
32
 
19
33
  import { AddIcon } from "@sanity/icons/Add";
20
34
 
21
35
  import { SearchIcon } from "@sanity/icons/Search";
22
36
 
23
- import { useClient, useDocumentPreviewStore, useSchema } from "sanity";
24
-
25
37
  import { CheckmarkIcon } from "@sanity/icons/Checkmark";
26
38
 
27
39
  import { CloseIcon } from "@sanity/icons/Close";
@@ -32,11 +44,823 @@ import { MemberAvatar, DatePicker, ClearableDatePicker } from "@sanity/workflow-
32
44
 
33
45
  import { endOfDay } from "date-fns/endOfDay";
34
46
 
35
- import { createPortal } from "react-dom";
47
+ import { createPortal } from "react-dom";
48
+
49
+ import { CalendarIcon } from "@sanity/icons/Calendar";
50
+
51
+ function MutedNote({text: text}) {
52
+ /* @__PURE__ */
53
+ return jsx(Box, {
54
+ paddingY: 3,
55
+ children: /* @__PURE__ */ jsx(Text, {
56
+ muted: !0,
57
+ size: 1,
58
+ children: text
59
+ })
60
+ });
61
+ }
62
+
63
+ function definitionCatalog(args) {
64
+ return args.definitions.map(definition => ({
65
+ name: definition.name,
66
+ title: definition.title ?? definition.name,
67
+ description: definition.description,
68
+ activeCount: args.inFlight.filter(instance => instance.definition === definition.name).length,
69
+ docTypes: [ ...new Set(args.mappings.filter(mapping => mapping.definition === definition.name).map(mapping => mapping.docType)) ]
70
+ })).sort((a, b) => a.title.localeCompare(b.title) || a.name.localeCompare(b.name));
71
+ }
72
+
73
+ function docTypeLabels(docTypes, titleOf) {
74
+ return docTypes.map(name => ({
75
+ name: name,
76
+ title: titleOf(name) ?? name
77
+ })).sort((a, b) => a.title.localeCompare(b.title) || a.name.localeCompare(b.name));
78
+ }
79
+
80
+ function startPhrase(definition) {
81
+ if (definition.lifecycle === "child") return "Spawned by a parent workflow";
82
+ if (startKindOf(definition) === "autonomous") return "Starts automatically";
83
+ const subject = (definition.fields ?? []).find(isSubjectEntry);
84
+ return subject !== void 0 && isInputSourced(subject) ? "Started manually, from a document" : "Started manually";
85
+ }
86
+
87
+ function deployedAtOf(definition) {
88
+ return typeof definition._updatedAt == "string" ? definition._updatedAt : void 0;
89
+ }
90
+
91
+ function DetailTitle({busy: busy = !1, documentGdr: documentGdr, title: title}) {
92
+ const chipPullback = -useSpaceToken(1);
93
+ /* @__PURE__ */
94
+ return jsxs(Flex, {
95
+ align: "center",
96
+ gap: 2,
97
+ paddingLeft: 2,
98
+ children: [
99
+ /* @__PURE__ */ jsx(Box, {
100
+ style: {
101
+ minWidth: 0
102
+ },
103
+ children: /* @__PURE__ */ jsx(Text, {
104
+ size: 1,
105
+ textOverflow: "ellipsis",
106
+ weight: "semibold",
107
+ children: title
108
+ })
109
+ }), documentGdr === void 0 ? null : /* @__PURE__ */ jsxs(Fragment, {
110
+ children: [
111
+ /* @__PURE__ */ jsx(Text, {
112
+ muted: !0,
113
+ size: 1,
114
+ children: "in"
115
+ }),
116
+ /* @__PURE__ */ jsx(Flex, {
117
+ align: "center",
118
+ flex: "none",
119
+ style: {
120
+ height: 0,
121
+ marginLeft: chipPullback
122
+ },
123
+ children: /* @__PURE__ */ jsx(DocPreviewLink, {
124
+ gdr: documentGdr,
125
+ layout: "inline"
126
+ })
127
+ }) ]
128
+ }),
129
+ /* @__PURE__ */ jsx(SpinnerSlot, {
130
+ busy: busy
131
+ }) ]
132
+ });
133
+ }
134
+
135
+ const lastRead = /* @__PURE__ */ new WeakMap, issuedReads = /* @__PURE__ */ new WeakMap;
136
+
137
+ function useDeployedDefinitions() {
138
+ const {engine: engine} = useWorkflowContext(), [definitions, setDefinitions] = useState(() => lastRead.get(engine)?.rows), [error, setError] = useState(void 0);
139
+ return useEffect(() => {
140
+ let cancelled = !1;
141
+ setDefinitions(lastRead.get(engine)?.rows), setError(void 0);
142
+ const seq = (issuedReads.get(engine) ?? 0) + 1;
143
+ return issuedReads.set(engine, seq), (async () => {
144
+ const rows = await readDeployedDefinitions(engine), latest = latestDeployedDefinitions(rows), held = lastRead.get(engine);
145
+ (held === void 0 || seq > held.seq) && lastRead.set(engine, {
146
+ seq: seq,
147
+ rows: latest
148
+ }), cancelled || (setDefinitions(latest), setError(void 0));
149
+ })().catch(err => {
150
+ cancelled || setError(describeError(err));
151
+ }), () => {
152
+ cancelled = !0;
153
+ };
154
+ }, [ engine ]), {
155
+ definitions: definitions,
156
+ error: error
157
+ };
158
+ }
159
+
160
+ function DefinitionDetail({definitionName: definitionName}) {
161
+ const {definitions: definitions, error: error} = useDeployedDefinitions(), snapshotWidth = useContainerToken(2), definition = definitions?.find(row => row.name === definitionName);
162
+ /* @__PURE__ */
163
+ return jsxs(Flex, {
164
+ direction: "column",
165
+ height: "fill",
166
+ overflow: "hidden",
167
+ children: [
168
+ /* @__PURE__ */ jsx(Box, {
169
+ flex: "none",
170
+ paddingBottom: 2,
171
+ paddingTop: 3,
172
+ paddingX: 3,
173
+ children: /* @__PURE__ */ jsx(DetailTitle, {
174
+ busy: definitions === void 0 && error === void 0,
175
+ title: definition?.title ?? definitionName
176
+ })
177
+ }),
178
+ /* @__PURE__ */ jsx(Box, {
179
+ flex: 1,
180
+ overflow: "auto",
181
+ paddingX: 3,
182
+ children: /* @__PURE__ */ jsx(Box, {
183
+ paddingBottom: 5,
184
+ paddingLeft: 2,
185
+ paddingTop: 2,
186
+ style: {
187
+ maxWidth: snapshotWidth
188
+ },
189
+ children: /* @__PURE__ */ jsx(DefinitionBody, {
190
+ definition: definition,
191
+ error: error,
192
+ loaded: definitions !== void 0
193
+ })
194
+ })
195
+ }) ]
196
+ });
197
+ }
198
+
199
+ function DefinitionBody({definition: definition, error: error, loaded: loaded}) {
200
+ return error !== void 0 ? /* @__PURE__ */ jsx(MutedNote, {
201
+ text: `Could not load the deployed workflows: ${error}`
202
+ }) : loaded ? definition === void 0 ? /* @__PURE__ */ jsx(MutedNote, {
203
+ text: "No deployed workflow definition with this name — it may have been retracted."
204
+ }) : /* @__PURE__ */ jsx(DefinitionFacts, {
205
+ definition: definition
206
+ }) : /* @__PURE__ */ jsx(LoadingRow, {
207
+ label: "Loading definition…"
208
+ });
209
+ }
210
+
211
+ function DefinitionFacts({definition: definition}) {
212
+ const {binding: binding, mappings: mappings} = useWorkflowContext(), schema = useSchema(), deployedAt = deployedAtOf(definition), [row] = definitionCatalog({
213
+ definitions: [ definition ],
214
+ mappings: mappings,
215
+ inFlight: []
216
+ }), runsOn = docTypeLabels(row?.docTypes ?? [], name => schema.get(name)?.title).map(docType => docType.title);
217
+ /* @__PURE__ */
218
+ return jsxs(Stack, {
219
+ gap: 4,
220
+ children: [
221
+ /* @__PURE__ */ jsx(MetaRow, {
222
+ label: "Deployed",
223
+ children: /* @__PURE__ */ jsxs(Text, {
224
+ size: 1,
225
+ children: [ deployedAt === void 0 ? `v${definition.version}` : formatDate(deployedAt), " ·", " ", binding.tag ]
226
+ })
227
+ }),
228
+ /* @__PURE__ */ jsx(MetaRow, {
229
+ label: "Trigger",
230
+ children: /* @__PURE__ */ jsx(Text, {
231
+ size: 1,
232
+ children: startPhrase(definition)
233
+ })
234
+ }),
235
+ /* @__PURE__ */ jsx(MetaRow, {
236
+ label: "Document types",
237
+ children: runsOn.length === 0 ? /* @__PURE__ */ jsx(Text, {
238
+ muted: !0,
239
+ size: 1,
240
+ children: "No document types in this Studio"
241
+ }) : /* @__PURE__ */ jsx(Text, {
242
+ size: 1,
243
+ children: runsOn.join(", ")
244
+ })
245
+ }),
246
+ /* @__PURE__ */ jsx(MetaRow, {
247
+ label: "Description",
248
+ children: definition.description === void 0 ? /* @__PURE__ */ jsx(Text, {
249
+ muted: !0,
250
+ size: 1,
251
+ children: /* @__PURE__ */ jsx("em", {
252
+ children: "No description"
253
+ })
254
+ }) : /* @__PURE__ */ jsx(Text, {
255
+ size: 1,
256
+ style: {
257
+ whiteSpace: "pre-wrap"
258
+ },
259
+ children: definition.description
260
+ })
261
+ }),
262
+ /* @__PURE__ */ jsx(WorkflowDiagram, {
263
+ definition: definition,
264
+ explain: !0,
265
+ height: 340
266
+ }) ]
267
+ });
268
+ }
269
+
270
+ function TabStatusRow({children: children}) {
271
+ /* @__PURE__ */
272
+ return jsx(Box, {
273
+ paddingLeft: 2,
274
+ paddingY: 3,
275
+ children: children
276
+ });
277
+ }
278
+
279
+ const INSTANCE_CAP = 200, NEWEST_INSTANCES = {
280
+ includeCompleted: !0,
281
+ limit: INSTANCE_CAP
282
+ };
283
+
284
+ function useToolInstances() {
285
+ const {engine: engine} = useWorkflowContext(), {instances: instances, loading: loading, unreadable: unreadable} = useWorkflowInstances({
286
+ engine: engine,
287
+ filter: NEWEST_INSTANCES
288
+ });
289
+ return useMemo(() => {
290
+ const rows = instances ?? [];
291
+ return {
292
+ inFlight: rows.filter(instance => terminalState(instance) === "in-flight"),
293
+ settled: rows.filter(instance => terminalState(instance) !== "in-flight"),
294
+ truncated: rows.length + unreadable.length === INSTANCE_CAP,
295
+ loading: loading,
296
+ unreadable: unreadable
297
+ };
298
+ }, [ instances, loading, unreadable ]);
299
+ }
300
+
301
+ const MAX_VISIBLE_DOC_TYPES = 4, COLUMNS = {
302
+ definition: 6,
303
+ instances: 2,
304
+ docTypes: 2
305
+ };
306
+
307
+ function Col({flex: flex, children: children}) {
308
+ /* @__PURE__ */
309
+ return jsx(Box, {
310
+ flex: flex,
311
+ paddingRight: 3,
312
+ children: children
313
+ });
314
+ }
315
+
316
+ function DefinitionsTab({onOpenDefinition: onOpenDefinition}) {
317
+ const {definitions: definitions, error: error} = useDeployedDefinitions(), {mappings: mappings} = useWorkflowContext(), instances = useToolInstances();
318
+ if (error !== void 0) /* @__PURE__ */
319
+ return jsx(TabStatusRow, {
320
+ children: /* @__PURE__ */ jsx(Text, {
321
+ muted: !0,
322
+ size: 1,
323
+ children: `Could not load the deployed workflows: ${error}`
324
+ })
325
+ });
326
+ if (definitions === void 0) /* @__PURE__ */
327
+ return jsx(TabStatusRow, {
328
+ children: /* @__PURE__ */ jsx(LoadingRow, {
329
+ label: "Loading definitions…"
330
+ })
331
+ });
332
+ if (definitions.length === 0) /* @__PURE__ */
333
+ return jsx(TabStatusRow, {
334
+ children: /* @__PURE__ */ jsx(Text, {
335
+ muted: !0,
336
+ size: 1,
337
+ children: "No workflow definitions are deployed"
338
+ })
339
+ });
340
+ const rows = definitionCatalog({
341
+ definitions: definitions,
342
+ mappings: mappings,
343
+ inFlight: instances.inFlight
344
+ }), active = rows.reduce((sum, row) => sum + row.activeCount, 0);
345
+ /* @__PURE__ */
346
+ return jsxs(Stack, {
347
+ gap: 3,
348
+ paddingBottom: 4,
349
+ children: [
350
+ /* @__PURE__ */ jsx(Box, {
351
+ paddingTop: 3,
352
+ paddingX: 2,
353
+ children: /* @__PURE__ */ jsxs(Flex, {
354
+ align: "center",
355
+ gap: 2,
356
+ children: [
357
+ /* @__PURE__ */ jsx(Text, {
358
+ size: 1,
359
+ weight: "semibold",
360
+ children: pluralize("definition", rows.length, !0)
361
+ }),
362
+ /* @__PURE__ */ jsx(Text, {
363
+ muted: !0,
364
+ size: 1,
365
+ children: instances.loading ? "counting active instances…" : activeSummary(active)
366
+ }) ]
367
+ })
368
+ }),
369
+ /* @__PURE__ */ jsxs(Stack, {
370
+ gap: 2,
371
+ children: [
372
+ /* @__PURE__ */ jsx(Card, {
373
+ paddingX: 2,
374
+ paddingY: 2,
375
+ style: {
376
+ position: "sticky",
377
+ top: 0,
378
+ zIndex: 1
379
+ },
380
+ children: /* @__PURE__ */ jsxs(Flex, {
381
+ align: "center",
382
+ gap: 4,
383
+ children: [
384
+ /* @__PURE__ */ jsx(Col, {
385
+ flex: COLUMNS.definition,
386
+ children: /* @__PURE__ */ jsx(Text, {
387
+ muted: !0,
388
+ size: 1,
389
+ weight: "medium",
390
+ children: "Definition"
391
+ })
392
+ }),
393
+ /* @__PURE__ */ jsx(Col, {
394
+ flex: COLUMNS.instances,
395
+ children: /* @__PURE__ */ jsxs(Flex, {
396
+ align: "center",
397
+ gap: 2,
398
+ children: [
399
+ /* @__PURE__ */ jsx(Text, {
400
+ muted: !0,
401
+ size: 1,
402
+ weight: "medium",
403
+ children: "Active instances"
404
+ }),
405
+ /* @__PURE__ */ jsx(HoverHint, {
406
+ text: "Counts only active instances — completed and aborted workflows are not included",
407
+ children: /* @__PURE__ */ jsx(Text, {
408
+ muted: !0,
409
+ size: 1,
410
+ style: {
411
+ opacity: .7
412
+ },
413
+ children: /* @__PURE__ */ jsx(InfoOutlineIcon, {})
414
+ })
415
+ }) ]
416
+ })
417
+ }),
418
+ /* @__PURE__ */ jsx(Col, {
419
+ flex: COLUMNS.docTypes,
420
+ children: /* @__PURE__ */ jsx(Text, {
421
+ muted: !0,
422
+ size: 1,
423
+ weight: "medium",
424
+ children: "Document types"
425
+ })
426
+ }) ]
427
+ })
428
+ }),
429
+ /* @__PURE__ */ jsx(Stack, {
430
+ gap: 1,
431
+ children: rows.map(row => /* @__PURE__ */ jsx(DefinitionRow, {
432
+ countPending: instances.loading,
433
+ onOpen: () => onOpenDefinition(row.name),
434
+ row: row
435
+ }, row.name))
436
+ }) ]
437
+ }), instances.truncated ? /* @__PURE__ */ jsx(MutedNote, {
438
+ text: `Counts from the latest ${INSTANCE_CAP} workflows — older ones aren't counted.`
439
+ }) : null ]
440
+ });
441
+ }
442
+
443
+ function activeSummary(active) {
444
+ return `${pluralize("active instance", active, !0)}`;
445
+ }
446
+
447
+ function DefinitionRow({countPending: countPending, onOpen: onOpen, row: row}) {
448
+ /* @__PURE__ */
449
+ return jsx(Card, {
450
+ as: "button",
451
+ onClick: onOpen,
452
+ paddingX: 2,
453
+ paddingY: 3,
454
+ radius: 2,
455
+ style: {
456
+ textAlign: "left"
457
+ },
458
+ children: /* @__PURE__ */ jsxs(Flex, {
459
+ align: "flex-start",
460
+ gap: 4,
461
+ children: [
462
+ /* @__PURE__ */ jsx(Col, {
463
+ flex: COLUMNS.definition,
464
+ children: /* @__PURE__ */ jsxs(Stack, {
465
+ gap: 3,
466
+ style: {
467
+ minWidth: 0
468
+ },
469
+ children: [
470
+ /* @__PURE__ */ jsx(Text, {
471
+ size: 1,
472
+ weight: "semibold",
473
+ children: row.title
474
+ }), row.description === void 0 ? /* @__PURE__ */ jsx(Text, {
475
+ muted: !0,
476
+ size: 1,
477
+ children: /* @__PURE__ */ jsx("em", {
478
+ children: "No description"
479
+ })
480
+ }) : /* @__PURE__ */ jsx(Text, {
481
+ muted: !0,
482
+ size: 1,
483
+ children: row.description
484
+ }) ]
485
+ })
486
+ }),
487
+ /* @__PURE__ */ jsx(Col, {
488
+ flex: COLUMNS.instances,
489
+ children: /* @__PURE__ */ jsx(Text, {
490
+ muted: !0,
491
+ size: 1,
492
+ children: countPending ? "—" : `${row.activeCount} active`
493
+ })
494
+ }),
495
+ /* @__PURE__ */ jsx(Col, {
496
+ flex: COLUMNS.docTypes,
497
+ children: /* @__PURE__ */ jsx(DocTypeChips, {
498
+ docTypes: row.docTypes
499
+ })
500
+ }) ]
501
+ })
502
+ });
503
+ }
504
+
505
+ function DocTypeChips({docTypes: docTypes}) {
506
+ const schema = useSchema(), badgeTrim = useBadgeCapTrim();
507
+ if (docTypes.length === 0) /* @__PURE__ */
508
+ return jsx(Text, {
509
+ muted: !0,
510
+ size: 1,
511
+ children: "—"
512
+ });
513
+ const labels = docTypeLabels(docTypes, name => schema.get(name)?.title), shown = labels.slice(0, MAX_VISIBLE_DOC_TYPES), overflow = labels.length - shown.length;
514
+ /* @__PURE__ */
515
+ return jsxs(Flex, {
516
+ align: "center",
517
+ gap: 2,
518
+ style: badgeTrim,
519
+ wrap: "wrap",
520
+ children: [ shown.map(docType => /* @__PURE__ */ jsx(Badge, {
521
+ fontSize: 1,
522
+ children: docType.title
523
+ }, docType.name)), overflow > 0 ? /* @__PURE__ */ jsxs(Text, {
524
+ muted: !0,
525
+ size: 1,
526
+ children: [ "+", overflow, " more" ]
527
+ }) : null ]
528
+ });
529
+ }
530
+
531
+ function makeTitleResolver(definition) {
532
+ const activities = (definition?.stages ?? []).flatMap(s => s.activities ?? []);
533
+ return {
534
+ action: (activityName, actionName) => activities.find(t => t.name === activityName)?.actions?.find(a => a.name === actionName)?.title ?? actionName,
535
+ activity: name => activities.find(t => t.name === name)?.title ?? name,
536
+ stage: name => stageTitle(definition, name)
537
+ };
538
+ }
539
+
540
+ function attributed(actor, ...parts) {
541
+ if (actor) return {
542
+ actorId: actor.id,
543
+ parts: parts
544
+ };
545
+ const [first, ...rest] = parts;
546
+ return typeof first != "string" ? {
547
+ actorId: void 0,
548
+ parts: parts
549
+ } : {
550
+ actorId: void 0,
551
+ parts: [ first.charAt(0).toUpperCase() + first.slice(1), ...rest ]
552
+ };
553
+ }
554
+
555
+ function standalone(...parts) {
556
+ return {
557
+ actorId: void 0,
558
+ parts: parts
559
+ };
560
+ }
561
+
562
+ const historyLiner = {
563
+ stageEntered: (h, titles) => attributed(h.actor, `entered ${titles.stage(h.stage)}${h.fromStage ? ` from ${titles.stage(h.fromStage)}` : ""}`),
564
+ stageExited: (h, titles) => attributed(h.actor, `left ${titles.stage(h.stage)} for ${titles.stage(h.toStage)}`),
565
+ activityStatusChanged: (h, titles) => attributed(h.actor, `changed ${titles.activity(h.activity)}: ${h.from} → ${h.to}`),
566
+ actionFired: (h, titles) => {
567
+ const phrase = `fired ${titles.action(h.activity, h.action)} on ${titles.activity(h.activity)}`;
568
+ return h.triggered ? standalone(`The workflow ${phrase}`) : attributed(h.actor, phrase);
569
+ },
570
+ transitionFired: (h, titles) => attributed(h.actor, `moved ${titles.stage(h.fromStage)} → ${titles.stage(h.toStage)}`),
571
+ effectQueued: h => standalone("Effect ", {
572
+ code: h.effect
573
+ }, " queued"),
574
+ effectCompleted: h => {
575
+ const detail = h.detail ? ` — ${h.detail}` : "";
576
+ return h.actor ? attributed(h.actor, "resolved effect ", {
577
+ code: h.effect
578
+ }, ` — ${h.status}${detail}`) : standalone("Effect ", {
579
+ code: h.effect
580
+ }, ` ${h.status}${detail}`);
581
+ },
582
+ effectClaimReleased: h => attributed(h.actor, "released a stale claim on effect ", {
583
+ code: h.effect
584
+ }, ` ${h.via === "sweep" ? "via the sweeper" : "via a drain takeover"}`),
585
+ spawned: (h, titles) => attributed(h.actor, `spawned a child workflow from ${titles.activity(h.activity)}`),
586
+ subworkflowAdopted: (h, titles) => standalone(`Re-adopted child workflow into ${titles.activity(h.activity)} on re-entering ${titles.stage(h.stage)}`),
587
+ subworkflowResolved: (h, titles) => standalone(`Child workflow of ${titles.activity(h.activity)} ${h.status === "done" ? "completed" : "was aborted"}`),
588
+ subworkflowOrphaned: h => standalone(`Orphaned child workflow reached terminal — ${h.detail}`),
589
+ aborted: (h, titles) => attributed(h.actor, `aborted the workflow at ${titles.stage(h.stage)}${h.reason ? ` — ${h.reason}` : ""}`),
590
+ opApplied: (h, titles) => h.action ? attributed(h.actor, `changed state via action ${titles.action(h.activity ?? "", h.action)}`) : h.activity ? attributed(h.actor, `changed state via activity ${titles.activity(h.activity)}`) : attributed(h.actor, "changed state via ", {
591
+ code: h.opType
592
+ }),
593
+ fieldQueryDiscarded: h => standalone({
594
+ code: JSON.stringify(h)
595
+ })
596
+ };
597
+
598
+ function historyLine(h, titles) {
599
+ return historyLiner[h._type](h, titles);
600
+ }
601
+
602
+ function PendingEffectRows({instance: instance, now: now}) {
603
+ const {drainEffectsFor: drainEffectsFor, completeEffectFor: completeEffectFor, effectHandlers: effectHandlers} = useWorkflowContext(), toast = useClosableToast(), [busy, setBusy] = useState(!1), pending = instance.pendingEffects ?? [];
604
+ if (pending.length === 0) return null;
605
+ const runRegistered = async () => {
606
+ setBusy(!0);
607
+ try {
608
+ await drainEffectsFor(instance._id), toast.push({
609
+ status: "success",
610
+ title: "Ran registered effect handlers"
611
+ });
612
+ } catch (err) {
613
+ toast.push({
614
+ status: "error",
615
+ title: "Drain failed",
616
+ description: describeError(err)
617
+ });
618
+ } finally {
619
+ setBusy(!1);
620
+ }
621
+ }, resolve = async (effectKey, status) => {
622
+ setBusy(!0);
623
+ try {
624
+ await completeEffectFor(instance._id, {
625
+ effectKey: effectKey,
626
+ status: status,
627
+ detail: "Resolved in Studio"
628
+ }), toast.push({
629
+ status: "success",
630
+ title: `Effect marked ${status}`
631
+ });
632
+ } catch (err) {
633
+ toast.push({
634
+ status: "error",
635
+ title: "Couldn’t resolve effect",
636
+ description: describeError(err)
637
+ });
638
+ } finally {
639
+ setBusy(!1);
640
+ }
641
+ };
642
+ /* @__PURE__ */
643
+ return jsx(Fragment, {
644
+ children: pending.map(fx => /* @__PURE__ */ jsx(PendingEffectRow, {
645
+ busy: busy,
646
+ effect: fx,
647
+ instanceId: instance._id,
648
+ now: now,
649
+ onResolve: status => resolve(fx._key, status),
650
+ onRunHandlers: runRegistered,
651
+ registered: fx.name in effectHandlers
652
+ }, fx._key))
653
+ });
654
+ }
655
+
656
+ function PendingEffectRow({busy: busy, effect: effect, instanceId: instanceId, now: now, onResolve: onResolve, onRunHandlers: onRunHandlers, registered: registered}) {
657
+ const label = effect.title ?? effect.name, avatarSize = useAvatarSize();
658
+ /* @__PURE__ */
659
+ return jsxs(Flex, {
660
+ align: "center",
661
+ gap: 2,
662
+ children: [
663
+ /* @__PURE__ */ jsx(FeedGlyph, {
664
+ hint: "Waiting to run",
665
+ icon: /* @__PURE__ */ jsx(ClockIcon, {})
666
+ }),
667
+ /* @__PURE__ */ jsxs(Flex, {
668
+ align: "center",
669
+ flex: 1,
670
+ gap: 1,
671
+ style: {
672
+ minWidth: 0
673
+ },
674
+ children: [
675
+ /* @__PURE__ */ jsx(Box, {
676
+ style: {
677
+ minWidth: 0
678
+ },
679
+ children: /* @__PURE__ */ jsxs(Text, {
680
+ size: 1,
681
+ textOverflow: "ellipsis",
682
+ children: [ effect.title ?? /* @__PURE__ */ jsx(CodeChip, {
683
+ value: effect.name
684
+ }), registered ? " — ready to run in Studio" : " — waiting for the runtime" ]
685
+ })
686
+ }),
687
+ /* @__PURE__ */ jsx(Text, {
688
+ muted: !0,
689
+ size: 1,
690
+ children: "·"
691
+ }),
692
+ /* @__PURE__ */ jsx(HoverHint, {
693
+ text: formatDateTime(effect.queuedAt),
694
+ children: /* @__PURE__ */ jsx(Text, {
695
+ muted: !0,
696
+ size: 1,
697
+ style: {
698
+ whiteSpace: "nowrap"
699
+ },
700
+ children: formatShortAgo(effect.queuedAt, now)
701
+ })
702
+ }) ]
703
+ }),
704
+ /* @__PURE__ */ jsx(Flex, {
705
+ align: "center",
706
+ flex: "none",
707
+ style: {
708
+ height: avatarSize
709
+ },
710
+ children: /* @__PURE__ */ jsx(HintedMenuButton, {
711
+ button: /* @__PURE__ */ jsx(Button, {
712
+ "aria-label": `Resolve ${label}`,
713
+ disabled: busy,
714
+ fontSize: 1,
715
+ icon: EllipsisHorizontalIcon,
716
+ mode: "bleed",
717
+ padding: 2
718
+ }),
719
+ hint: "Resolve",
720
+ id: `pending-effect-menu-${instanceId}-${effect._key}`,
721
+ menu: /* @__PURE__ */ jsxs(Menu, {
722
+ children: [ registered ? /* @__PURE__ */ jsx(MenuItem, {
723
+ onClick: onRunHandlers,
724
+ text: "Run registered handlers"
725
+ }) : null,
726
+ /* @__PURE__ */ jsx(MenuItem, {
727
+ onClick: () => onResolve("done"),
728
+ text: "Mark done"
729
+ }),
730
+ /* @__PURE__ */ jsx(MenuItem, {
731
+ onClick: () => onResolve("failed"),
732
+ text: "Mark failed",
733
+ tone: "critical"
734
+ }) ]
735
+ }),
736
+ popover: {
737
+ placement: "bottom-end",
738
+ portal: !0
739
+ }
740
+ })
741
+ }) ]
742
+ });
743
+ }
744
+
745
+ function ActivityLog({instance: instance, definition: definition}) {
746
+ const titles = useMemo(() => makeTitleResolver(definition), [ definition ]), entries = useMemo(() => instance.history.toReversed(), [ instance.history ]), [now, setNow] = useState(() => /* @__PURE__ */ new Date);
747
+ return useEffect(() => {
748
+ const timer = setInterval(() => setNow(/* @__PURE__ */ new Date), 6e4);
749
+ return () => clearInterval(timer);
750
+ }, []), entries.length === 0 && (instance.pendingEffects ?? []).length === 0 ? /* @__PURE__ */ jsx(Text, {
751
+ muted: !0,
752
+ size: 1,
753
+ children: "No activity yet"
754
+ }) : /* @__PURE__ */ jsxs(Stack, {
755
+ gap: 3,
756
+ children: [
757
+ /* @__PURE__ */ jsx(PendingEffectRows, {
758
+ instance: instance,
759
+ now: now
760
+ }), entries.map(h => /* @__PURE__ */ jsx(HistoryRow, {
761
+ entry: h,
762
+ now: now,
763
+ titles: titles
764
+ }, h._key)) ]
765
+ });
766
+ }
767
+
768
+ function HistoryRow({entry: entry, now: now, titles: titles}) {
769
+ const line = historyLine(entry, titles);
770
+ /* @__PURE__ */
771
+ return jsxs(Flex, {
772
+ align: "center",
773
+ gap: 2,
774
+ children: [ line.actorId === void 0 ? /* @__PURE__ */ jsx(FeedGlyph, {
775
+ hint: "The workflow",
776
+ icon: /* @__PURE__ */ jsx(CogIcon, {})
777
+ }) : /* @__PURE__ */ jsx(UserAvatar, {
778
+ id: line.actorId
779
+ }),
780
+ /* @__PURE__ */ jsxs(Flex, {
781
+ align: "center",
782
+ flex: 1,
783
+ gap: 1,
784
+ style: {
785
+ minWidth: 0
786
+ },
787
+ children: [
788
+ /* @__PURE__ */ jsx(Box, {
789
+ style: {
790
+ minWidth: 0
791
+ },
792
+ children: /* @__PURE__ */ jsxs(Text, {
793
+ size: 1,
794
+ textOverflow: "ellipsis",
795
+ children: [ line.actorId === void 0 ? null : /* @__PURE__ */ jsxs(Fragment, {
796
+ children: [
797
+ /* @__PURE__ */ jsx(ActorNameSpan, {
798
+ id: line.actorId
799
+ }), " " ]
800
+ }), line.parts.map((part, index) => typeof part == "string" ? part : /* @__PURE__ */ jsx(CodeChip, {
801
+ value: part.code
802
+ }, index)) ]
803
+ })
804
+ }),
805
+ /* @__PURE__ */ jsx(Text, {
806
+ muted: !0,
807
+ size: 1,
808
+ children: "·"
809
+ }),
810
+ /* @__PURE__ */ jsx(HoverHint, {
811
+ text: formatDateTime(entry.at),
812
+ children: /* @__PURE__ */ jsx(Text, {
813
+ muted: !0,
814
+ size: 1,
815
+ style: {
816
+ whiteSpace: "nowrap"
817
+ },
818
+ children: formatShortAgo(entry.at, now)
819
+ })
820
+ }) ]
821
+ }) ]
822
+ });
823
+ }
824
+
825
+ function ActorNameSpan({id: id}) {
826
+ const {name: name} = useUserDisplay(id), {font: font} = useTheme_v2();
827
+ /* @__PURE__ */
828
+ return jsx("span", {
829
+ style: {
830
+ fontWeight: font.text.weights.medium
831
+ },
832
+ children: name
833
+ });
834
+ }
36
835
 
37
- import { CalendarIcon } from "@sanity/icons/Calendar";
836
+ function CodeChip({value: value}) {
837
+ /* @__PURE__ */
838
+ return jsx("code", {
839
+ children: value
840
+ });
841
+ }
38
842
 
39
- import { useWorkflowInstances } from "@sanity/workflow-studio";
843
+ function FeedGlyph({hint: hint, icon: icon}) {
844
+ const size = useAvatarSize();
845
+ /* @__PURE__ */
846
+ return jsx(HoverHint, {
847
+ text: hint,
848
+ children: /* @__PURE__ */ jsx(Flex, {
849
+ align: "center",
850
+ flex: "none",
851
+ justify: "center",
852
+ style: {
853
+ height: size,
854
+ width: size
855
+ },
856
+ children: /* @__PURE__ */ jsx(Text, {
857
+ muted: !0,
858
+ size: 1,
859
+ children: icon
860
+ })
861
+ })
862
+ });
863
+ }
40
864
 
41
865
  function documentRefsOf(instance) {
42
866
  const seen = /* @__PURE__ */ new Map;
@@ -44,23 +868,6 @@ function documentRefsOf(instance) {
44
868
  return [ ...seen.values() ];
45
869
  }
46
870
 
47
- function InstanceTaskLists({entry: entry, onOpenActivity: onOpenActivity}) {
48
- return instanceNotice(entry) || /* @__PURE__ */ jsx(StaleLock, {
49
- stale: isEvaluationStale(entry),
50
- children: /* @__PURE__ */ jsxs(Stack, {
51
- children: [
52
- /* @__PURE__ */ jsx(ActivitiesList, {
53
- entry: entry,
54
- onOpenActivity: onOpenActivity
55
- }),
56
- /* @__PURE__ */ jsx(TodoItemsList, {
57
- entry: entry,
58
- surface: "tool-instance-detail"
59
- }) ]
60
- })
61
- });
62
- }
63
-
64
871
  function WorkflowInstanceDetail({instanceId: instanceId, onBack: onBack}) {
65
872
  const entry = useWorkflowInstanceEntry(instanceId);
66
873
  useLogEventOnMount(WorkflowInstanceDetailViewed, {
@@ -76,15 +883,16 @@ function WorkflowInstanceDetail({instanceId: instanceId, onBack: onBack}) {
76
883
  invalid: entry.invalid
77
884
  })
78
885
  }) : entry ? /* @__PURE__ */ jsx(InstanceDetailPanel, {
79
- entry: entry,
80
- onBack: onBack
886
+ entry: entry
81
887
  }) : /* @__PURE__ */ jsx(Box, {
82
- padding: 4,
83
- children: graceOver ? /* @__PURE__ */ jsx(NotFound, {
84
- id: instanceId,
85
- onBack: onBack
86
- }) : /* @__PURE__ */ jsx(LoadingRow, {
87
- label: "Loading workflow…"
888
+ paddingX: 3,
889
+ children: /* @__PURE__ */ jsx(TabStatusRow, {
890
+ children: graceOver ? /* @__PURE__ */ jsx(NotFound, {
891
+ id: instanceId,
892
+ onBack: onBack
893
+ }) : /* @__PURE__ */ jsx(LoadingRow, {
894
+ label: "Loading workflow…"
895
+ })
88
896
  })
89
897
  });
90
898
  }
@@ -112,8 +920,8 @@ function NotFound({id: id, onBack: onBack}) {
112
920
  });
113
921
  }
114
922
 
115
- function InstanceDetailPanel({entry: entry, onBack: onBack}) {
116
- const definition = useDefinition(entry), [openActivity, setOpenActivity] = useState(null), {instance: instance} = entry;
923
+ function InstanceDetailPanel({entry: entry}) {
924
+ const definition = useDefinition(entry), snapshotWidth = useContainerToken(2), [openActivity, setOpenActivity] = useState(null), {instance: instance, ready: ready} = entry;
117
925
  return useEffect(() => {
118
926
  openActivity && openActivityGone({
119
927
  entry: entry,
@@ -124,36 +932,52 @@ function InstanceDetailPanel({entry: entry, onBack: onBack}) {
124
932
  height: "fill",
125
933
  overflow: "hidden",
126
934
  children: [
127
- /* @__PURE__ */ jsx(DetailHeader, {
128
- definition: definition,
129
- entry: entry,
130
- onBack: onBack
935
+ /* @__PURE__ */ jsx(Box, {
936
+ flex: "none",
937
+ paddingBottom: 2,
938
+ paddingTop: 3,
939
+ paddingX: 3,
940
+ children: /* @__PURE__ */ jsx(DetailTitle, {
941
+ busy: !ready || isEvaluationStale(entry),
942
+ documentGdr: documentRefsOf(instance)[0],
943
+ title: instanceTitle(instance, definition)
944
+ })
131
945
  }),
132
946
  /* @__PURE__ */ jsx(Box, {
133
947
  flex: 1,
134
948
  overflow: "auto",
135
- paddingX: 4,
136
- children: /* @__PURE__ */ jsxs(Stack, {
137
- gap: 4,
949
+ paddingX: 3,
950
+ children: /* @__PURE__ */ jsx(Box, {
138
951
  paddingBottom: 5,
139
- children: [
140
- /* @__PURE__ */ jsx(StudioDocumentsSection, {
141
- instance: instance
142
- }),
143
- /* @__PURE__ */ jsx(StageDiagramSection, {
144
- definition: definition,
145
- entry: entry
146
- }),
147
- /* @__PURE__ */ jsx(GroupHeading, {
148
- title: "All tasks"
149
- }),
150
- /* @__PURE__ */ jsx(InstanceTaskLists, {
151
- entry: entry,
152
- onOpenActivity: name => setOpenActivity({
153
- stage: instance.currentStage,
154
- activityName: name
155
- })
156
- }) ]
952
+ paddingLeft: 2,
953
+ paddingTop: 2,
954
+ style: {
955
+ maxWidth: snapshotWidth
956
+ },
957
+ children: /* @__PURE__ */ jsxs(Stack, {
958
+ gap: 6,
959
+ children: [
960
+ /* @__PURE__ */ jsx(InstanceSnapshotBody, {
961
+ entry: entry,
962
+ onOpenActivity: name => setOpenActivity({
963
+ stage: instance.currentStage,
964
+ activityName: name
965
+ })
966
+ }),
967
+ /* @__PURE__ */ jsxs(Stack, {
968
+ gap: 4,
969
+ children: [
970
+ /* @__PURE__ */ jsx(Text, {
971
+ size: 1,
972
+ weight: "semibold",
973
+ children: "History"
974
+ }),
975
+ /* @__PURE__ */ jsx(ActivityLog, {
976
+ definition: definition,
977
+ instance: instance
978
+ }) ]
979
+ }) ]
980
+ })
157
981
  })
158
982
  }), openActivity ? /* @__PURE__ */ jsx(ActivityDetailDialog, {
159
983
  activityName: openActivity.activityName,
@@ -166,130 +990,14 @@ function InstanceDetailPanel({entry: entry, onBack: onBack}) {
166
990
  });
167
991
  }
168
992
 
169
- function DetailHeader({entry: entry, definition: definition, onBack: onBack}) {
170
- const {instance: instance, ready: ready} = entry;
171
- /* @__PURE__ */
172
- return jsx(Card, {
173
- flex: "none",
174
- paddingX: 4,
175
- paddingY: 3,
176
- children: /* @__PURE__ */ jsxs(Flex, {
177
- align: "center",
178
- gap: 3,
179
- wrap: "wrap",
180
- children: [
181
- /* @__PURE__ */ jsx(HoverHint, {
182
- text: "Back to workflows",
183
- children: /* @__PURE__ */ jsx(Button, {
184
- "aria-label": "Back to workflows",
185
- fontSize: 1,
186
- icon: ArrowLeftIcon,
187
- mode: "bleed",
188
- onClick: onBack,
189
- padding: 2
190
- })
191
- }),
192
- /* @__PURE__ */ jsxs(Stack, {
193
- gap: 2,
194
- children: [
195
- /* @__PURE__ */ jsx(Text, {
196
- size: 1,
197
- weight: "semibold",
198
- children: instanceTitle(instance, definition)
199
- }),
200
- /* @__PURE__ */ jsxs(Text, {
201
- muted: !0,
202
- size: 1,
203
- children: [ "Started ", formatDate(instance.startedAt) ]
204
- }) ]
205
- }), terminalState(instance) === "in-flight" ? /* @__PURE__ */ jsx(StageChip, {
206
- title: stageTitle(definition, instance.currentStage)
207
- }) : /* @__PURE__ */ jsx(AbortedBadge, {
208
- instance: instance
209
- }),
210
- /* @__PURE__ */ jsx(SpinnerSlot, {
211
- busy: !ready || isEvaluationStale(entry)
212
- }) ]
213
- })
214
- });
215
- }
216
-
217
- function StudioDocumentsSection({instance: instance}) {
218
- const refs = documentRefsOf(instance);
219
- return refs.length === 0 ? null : /* @__PURE__ */ jsxs(Stack, {
220
- gap: 3,
221
- marginTop: 3,
222
- children: [
223
- /* @__PURE__ */ jsx(Text, {
224
- muted: !0,
225
- size: 1,
226
- weight: "medium",
227
- children: refs.length === 1 ? "Studio document" : "Studio documents"
228
- }),
229
- /* @__PURE__ */ jsx(Stack, {
230
- gap: 2,
231
- children: refs.map(ref => /* @__PURE__ */ jsx(DocPreviewLink, {
232
- gdr: ref
233
- }, ref.id))
234
- }) ]
235
- });
236
- }
237
-
238
- function StageDiagramSection({entry: entry, definition: definition}) {
239
- const {instance: instance} = entry;
240
- return definition ?
241
- /* @__PURE__ */ jsx(WorkflowDiagram, {
242
- currentStage: terminalState(instance) === "in-flight" ? instance.currentStage : void 0,
243
- definition: definition,
244
- evaluation: entry.evaluation,
245
- explain: !0,
246
- guardCount: entry.guards?.length,
247
- height: 340,
248
- history: instance.history
249
- }, instance._id) : /* @__PURE__ */ jsx(Card, {
250
- border: !0,
251
- marginTop: 3,
252
- padding: 3,
253
- radius: 2,
254
- tone: "caution",
255
- children: /* @__PURE__ */ jsx(Text, {
256
- muted: !0,
257
- size: 1,
258
- children: "Couldn’t load this workflow’s full details — the stage diagram is unavailable, and technical names show instead of titles."
259
- })
260
- });
261
- }
262
-
263
- function MutedNote({text: text}) {
264
- /* @__PURE__ */
265
- return jsx(Box, {
266
- paddingY: 3,
267
- children: /* @__PURE__ */ jsx(Text, {
268
- muted: !0,
269
- size: 1,
270
- children: text
271
- })
272
- });
273
- }
274
-
275
993
  function useStartableDefinitions() {
276
- const {engine: engine} = useWorkflowContext(), [definitions, setDefinitions] = useState(void 0), [error, setError] = useState(void 0);
277
- return useEffect(() => {
278
- let cancelled = !1;
279
- return (async () => {
280
- const rows = await readDeployedDefinitions(engine), startable = latestDeployedDefinitions(rows).filter(row => isStartableDefinition(row)).map(row => ({
281
- name: row.name,
282
- title: row.title ?? row.name,
283
- description: row.description
284
- }));
285
- cancelled || (setDefinitions(startable), setError(void 0));
286
- })().catch(err => {
287
- cancelled || setError(describeError(err));
288
- }), () => {
289
- cancelled = !0;
290
- };
291
- }, [ engine ]), {
292
- definitions: definitions,
994
+ const {definitions: definitions, error: error} = useDeployedDefinitions();
995
+ return {
996
+ definitions: useMemo(() => definitions?.filter(row => isStartableDefinition(row)).map(row => ({
997
+ name: row.name,
998
+ title: row.title ?? row.name,
999
+ description: row.description
1000
+ })), [ definitions ]),
293
1001
  error: error
294
1002
  };
295
1003
  }
@@ -668,6 +1376,17 @@ function deriveTaskGroups(args) {
668
1376
  };
669
1377
  }
670
1378
 
1379
+ function orderGroupsByPreviewTitle(groups, titles) {
1380
+ const withDocuments = [ ...groups.withDocuments ].sort((a, b) => {
1381
+ const aTitle = titles.get(a.document.id), bTitle = titles.get(b.document.id);
1382
+ return aTitle !== void 0 && bTitle !== void 0 ? aTitle.localeCompare(bTitle) || a.key.localeCompare(b.key) : aTitle !== void 0 ? -1 : bTitle !== void 0 ? 1 : a.key.localeCompare(b.key);
1383
+ });
1384
+ return {
1385
+ ...groups,
1386
+ withDocuments: withDocuments
1387
+ };
1388
+ }
1389
+
671
1390
  function cutTaskGroups(groups, cut) {
672
1391
  const cutBands = bands => bands.filter(band => cut.keepBand?.(band) ?? !0).map(band => ({
673
1392
  ...band,
@@ -1109,30 +1828,64 @@ const NOTHING = {
1109
1828
  };
1110
1829
 
1111
1830
  function useDocPreviewTitles(documents) {
1112
- const previewStore = useDocumentPreviewStore(), schema = useSchema(), {binding: binding} = useWorkflowContext(), [state, setState] = useState(NOTHING), key = documents.map(doc => doc.id).join("|");
1831
+ const previewStore = useDocumentPreviewStore(), schema = useSchema(), {perspectiveStack: perspectiveStack} = usePerspective(), {actualTypes: actualTypes, binding: binding} = useWorkflowContext(), [state, setState] = useState(NOTHING), key = documents.map(doc => doc.id).join("|");
1113
1832
  return useEffect(() => {
1114
- const titles = /* @__PURE__ */ new Map, resolved = /* @__PURE__ */ new Set, publish = () => setState({
1833
+ const titles = /* @__PURE__ */ new Map, resolved = /* @__PURE__ */ new Set, previews = /* @__PURE__ */ new Map, publish = () => setState({
1115
1834
  titles: new Map(titles),
1116
1835
  resolved: new Set(resolved)
1117
- }), subscriptions = documents.flatMap(doc => {
1118
- const {parsed: parsedRef, local: local} = gdrLocality(doc.id, binding.contentResource), schemaType = schema.get(doc.type);
1119
- return !parsedRef || !local || !schemaType ? (resolved.add(doc.id), []) : [ previewStore.observeForPreview({
1120
- _type: "reference",
1121
- _ref: parsedRef.documentId
1122
- }, schemaType).subscribe({
1836
+ }), localDocs = documents.flatMap(doc => {
1837
+ const {parsed: parsed, local: local} = gdrLocality(doc.id, binding.contentResource);
1838
+ return !parsed || !local ? (resolved.add(doc.id), []) : [ {
1839
+ doc: doc,
1840
+ bareId: parsed.documentId
1841
+ } ];
1842
+ }), untracks = localDocs.map(({bareId: bareId}) => actualTypes.track(bareId)), dropPreview = docId => {
1843
+ previews.get(docId)?.unsubscribe(), previews.delete(docId), titles.delete(docId);
1844
+ }, observe = ({docId: docId, bareId: bareId, typeName: typeName}) => {
1845
+ const schemaType = openableSchemaType(schema, typeName);
1846
+ if (!schemaType) return !1;
1847
+ if (previews.get(docId)?.typeName === typeName) return !0;
1848
+ dropPreview(docId), resolved.delete(docId);
1849
+ const subscription = previewStore.observeForPreview({
1850
+ _id: bareId,
1851
+ _type: schemaType.name
1852
+ }, schemaType, {
1853
+ perspective: perspectiveStack
1854
+ }).subscribe({
1123
1855
  next: event => {
1124
- resolved.add(doc.id);
1856
+ resolved.add(docId);
1125
1857
  const title = event.snapshot?.title;
1126
- typeof title == "string" && titles.set(doc.id, title), publish();
1858
+ typeof title == "string" ? titles.set(docId, title) : titles.delete(docId), publish();
1127
1859
  },
1128
1860
  error: err => {
1129
- console.error(`[workflow-studio-plugin] preview for "${doc.id}" failed:`, err),
1130
- resolved.add(doc.id), publish();
1861
+ console.error(`[workflow-studio-plugin] preview for "${docId}" failed:`, err), resolved.add(docId),
1862
+ publish();
1131
1863
  }
1132
- }) ];
1133
- });
1134
- return publish(), () => subscriptions.forEach(sub => sub.unsubscribe());
1135
- }, [ key, previewStore, schema, binding.contentResource.id ]), state;
1864
+ });
1865
+ return previews.set(docId, {
1866
+ typeName: typeName,
1867
+ unsubscribe: () => subscription.unsubscribe()
1868
+ }), !0;
1869
+ }, evaluate = () => {
1870
+ for (const {doc: doc, bareId: bareId} of localDocs) {
1871
+ const probe = actualTypes.read(bareId);
1872
+ if (probe === null) {
1873
+ dropPreview(doc.id), resolved.add(doc.id);
1874
+ continue;
1875
+ }
1876
+ !observe({
1877
+ docId: doc.id,
1878
+ bareId: bareId,
1879
+ typeName: probe ?? doc.type
1880
+ }) && typeof probe == "string" && (dropPreview(doc.id), resolved.add(doc.id));
1881
+ }
1882
+ publish();
1883
+ }, unsubscribeProbes = actualTypes.subscribe(evaluate);
1884
+ return evaluate(), () => {
1885
+ unsubscribeProbes(), untracks.forEach(untrack => untrack()), previews.forEach(preview => preview.unsubscribe());
1886
+ };
1887
+ }, [ key, previewStore, schema, actualTypes, binding.contentResource.id, perspectiveStack.join("|") ]),
1888
+ state;
1136
1889
  }
1137
1890
 
1138
1891
  const HITS_CAP = 6;
@@ -1757,13 +2510,12 @@ function RefChips({refs: refs, max: max = 2}) {
1757
2510
  });
1758
2511
  }
1759
2512
 
1760
- const EMPTY_NOTE = "No tasks match — adjust the filters, or start a workflow", UNGROUPED_TITLE = "Workflows without Studio documents";
2513
+ const UNGROUPED_TITLE = "Workflows without Studio documents";
1761
2514
 
1762
2515
  function TaskGroupList({bands: bands, groups: groups, instanceDefaultOpen: instanceDefaultOpen, onOpenTask: onOpenTask, onOpenWorkflow: onOpenWorkflow, showTerminalActions: showTerminalActions}) {
1763
- return groups.withDocuments.length === 0 && groups.withoutDocuments.length === 0 ? /* @__PURE__ */ jsx(MutedNote, {
1764
- text: EMPTY_NOTE
1765
- }) : /* @__PURE__ */ jsxs(Stack, {
1766
- gap: 2,
2516
+ /* @__PURE__ */
2517
+ return jsxs(Stack, {
2518
+ gap: 1,
1767
2519
  children: [ groups.withDocuments.map(group => /* @__PURE__ */ jsx(CollapsibleBand, {
1768
2520
  background: !0,
1769
2521
  onToggle: () => bands.toggle(group.key, GROUP_DEFAULT_OPEN),
@@ -1982,28 +2734,6 @@ function useOrphanedWorkflows(groups) {
1982
2734
  }), [ groups, contentResource, missing ]);
1983
2735
  }
1984
2736
 
1985
- const INSTANCE_CAP = 200, NEWEST_INSTANCES = {
1986
- includeCompleted: !0,
1987
- limit: INSTANCE_CAP
1988
- };
1989
-
1990
- function useToolInstances() {
1991
- const {engine: engine} = useWorkflowContext(), {instances: instances, loading: loading, unreadable: unreadable} = useWorkflowInstances({
1992
- engine: engine,
1993
- filter: NEWEST_INSTANCES
1994
- });
1995
- return useMemo(() => {
1996
- const rows = instances ?? [];
1997
- return {
1998
- inFlight: rows.filter(instance => terminalState(instance) === "in-flight"),
1999
- settled: rows.filter(instance => terminalState(instance) !== "in-flight"),
2000
- truncated: rows.length + unreadable.length === INSTANCE_CAP,
2001
- loading: loading,
2002
- unreadable: unreadable
2003
- };
2004
- }, [ instances, loading, unreadable ]);
2005
- }
2006
-
2007
2737
  function TasksTab({filterSlot: filterSlot, instances: instances, loading: loading, identity: identity, onOpenTask: onOpenTask, onOpenWorkflow: onOpenWorkflow, segment: segment, truncated: truncated, unreadable: unreadable}) {
2008
2738
  const mineOnly = segment === "for-me", {binding: binding} = useWorkflowContext(), bands = useBandOpenState({
2009
2739
  segment: segment,
@@ -2011,21 +2741,38 @@ function TasksTab({filterSlot: filterSlot, instances: instances, loading: loadin
2011
2741
  }), [filters, setFilters] = useState({}), groups = useMemo(() => deriveTaskGroups({
2012
2742
  instances: instances,
2013
2743
  identity: identity
2014
- }), [ instances, identity ]), orphans = useOrphanedWorkflows(groups), listed = useMemo(() => hideOrphanedGroups(groups, orphans.groupKeys), [ groups, orphans.groupKeys ]), options = useMemo(() => taskFilterOptions(listed), [ listed ]), visible = useMemo(() => {
2744
+ }), [ instances, identity ]), orphans = useOrphanedWorkflows(groups), listed = useMemo(() => hideOrphanedGroups(groups, orphans.groupKeys), [ groups, orphans.groupKeys ]), options = useMemo(() => taskFilterOptions(listed), [ listed ]), leadDocuments = useMemo(() => listed.withDocuments.map(group => group.document), [ listed ]), previewTitles = useDocPreviewTitles(leadDocuments), visible = useMemo(() => {
2015
2745
  const filtered = applyTaskFilters({
2016
2746
  groups: listed,
2017
2747
  filters: filters,
2018
2748
  now: /* @__PURE__ */ new Date
2019
- });
2020
- return mineOnly ? onlyMyTasks(filtered) : filtered;
2021
- }, [ listed, filters, mineOnly ]);
2022
- return loading ?
2023
- /* @__PURE__ */ jsx(Box, {
2024
- paddingLeft: 2,
2749
+ }), cut = mineOnly ? onlyMyTasks(filtered) : filtered;
2750
+ return orderGroupsByPreviewTitle(cut, previewTitles.titles);
2751
+ }, [ listed, filters, mineOnly, previewTitles ]);
2752
+ if (loading) /* @__PURE__ */
2753
+ return jsx(TabStatusRow, {
2025
2754
  children: /* @__PURE__ */ jsx(LoadingRow, {
2026
2755
  label: "Loading tasks…"
2027
2756
  })
2028
- }) : /* @__PURE__ */ jsxs(Box, {
2757
+ });
2758
+ const empty = visible.withDocuments.length === 0 && visible.withoutDocuments.length === 0;
2759
+ let body;
2760
+ return empty ? mineOnly ? body = /* @__PURE__ */ jsx(ForMeEmptyState, {}) : body = /* @__PURE__ */ jsx(TabStatusRow, {
2761
+ children: /* @__PURE__ */ jsx(Text, {
2762
+ muted: !0,
2763
+ size: 1,
2764
+ children: "No tasks match — adjust the filters, or start a workflow"
2765
+ })
2766
+ }) : body = /* @__PURE__ */ jsx(TaskGroupList, {
2767
+ bands: bands,
2768
+ groups: visible,
2769
+ instanceDefaultOpen: instanceBandDefaultOpen(segment),
2770
+ onOpenTask: onOpenTask,
2771
+ onOpenWorkflow: onOpenWorkflow,
2772
+ showTerminalActions: mineOnly
2773
+ }), /* @__PURE__ */ jsxs(Flex, {
2774
+ direction: "column",
2775
+ flex: 1,
2029
2776
  children: [
2030
2777
  /* @__PURE__ */ jsx(FilterRowPortal, {
2031
2778
  filters: filters,
@@ -2033,91 +2780,78 @@ function TasksTab({filterSlot: filterSlot, instances: instances, loading: loadin
2033
2780
  options: options,
2034
2781
  slot: filterSlot
2035
2782
  }),
2036
- /* @__PURE__ */ jsxs(Stack, {
2783
+ /* @__PURE__ */ jsxs(Flex, {
2784
+ direction: "column",
2785
+ flex: 1,
2037
2786
  gap: 2,
2787
+ paddingBottom: 4,
2038
2788
  children: [
2039
2789
  /* @__PURE__ */ jsx(UnreadableDocsNote, {
2040
2790
  unreadable: unreadable
2041
2791
  }),
2042
2792
  /* @__PURE__ */ jsx(OrphanedWorkflowsNote, {
2043
2793
  orphans: orphans
2044
- }),
2045
- /* @__PURE__ */ jsx(TaskGroupList, {
2046
- bands: bands,
2047
- groups: visible,
2048
- instanceDefaultOpen: instanceBandDefaultOpen(segment),
2049
- onOpenTask: onOpenTask,
2050
- onOpenWorkflow: onOpenWorkflow,
2051
- showTerminalActions: mineOnly
2052
- }) ]
2053
- }), truncated ? /* @__PURE__ */ jsx(MutedNote, {
2054
- text: `Tasks from the latest ${INSTANCE_CAP} workflows — older ones aren't listed.`
2055
- }) : null ]
2794
+ }), body, truncated ? /* @__PURE__ */ jsx(MutedNote, {
2795
+ text: `Tasks from the latest ${INSTANCE_CAP} workflows — older ones aren't listed.`
2796
+ }) : null ]
2797
+ }) ]
2056
2798
  });
2057
2799
  }
2058
2800
 
2059
2801
  const TOOL_TABS = [ {
2060
2802
  value: "overview",
2061
2803
  label: "Overview"
2804
+ }, {
2805
+ value: "definitions",
2806
+ label: "Definitions"
2062
2807
  }, {
2063
2808
  value: "for-me",
2064
2809
  label: "For me"
2065
- } ], [firstToolTab, ...restToolTabs] = TOOL_TABS, TOOL_TAB_CODEC = workflowsTabCodec([ firstToolTab.value, ...restToolTabs.map(tab => tab.value) ]);
2810
+ } ], TOOL_TAB_VALUES = TOOL_TABS.map(tab => tab.value);
2066
2811
 
2067
- function useToolTab() {
2068
- const router = useRouter(), params = Object.fromEntries(router.state._searchParams ?? []);
2069
- return {
2070
- tab: TOOL_TAB_CODEC.read(params),
2071
- setTab: next => router.navigate({
2072
- _searchParams: definedEntries(TOOL_TAB_CODEC.write(params, next))
2073
- })
2074
- };
2075
- }
2076
-
2077
- function definedEntries(params) {
2078
- return Object.entries(params).filter(entry => entry[1] !== void 0);
2079
- }
2080
-
2081
- function carryingSearchParams(state, searchParams) {
2082
- return searchParams === void 0 ? state : {
2083
- ...state,
2084
- _searchParams: searchParams
2085
- };
2812
+ function InstanceStreamKeepAlive() {
2813
+ return useToolInstances(), null;
2086
2814
  }
2087
2815
 
2088
2816
  function WorkflowsToolRoot() {
2089
- const router = useRouter(), {seedInstance: seedInstance} = useWorkflowContext(), {tab: tab} = useToolTab();
2817
+ const router = useRouter(), {seedInstance: seedInstance} = useWorkflowContext(), telemetry = useWorkflowTelemetry(), [filterSlot, setFilterSlot] = useState(null), goHome = () => router.navigate({}), instanceId = typeof router.state.instanceId == "string" ? router.state.instanceId : void 0, definitionName = typeof router.state.definitionName == "string" ? router.state.definitionName : void 0, isHome = instanceId === void 0 && definitionName === void 0, [instanceStreamLatched, setInstanceStreamLatched] = useState(isHome);
2818
+ useEffect(() => {
2819
+ isHome && setInstanceStreamLatched(!0);
2820
+ }, [ isHome ]);
2821
+ let tab;
2822
+ instanceId !== void 0 ? tab = "overview" : definitionName !== void 0 ? tab = "definitions" : tab = pathSegmentTab({
2823
+ segment: router.state.workflowsTab,
2824
+ tabs: TOOL_TAB_VALUES,
2825
+ fallback: "overview"
2826
+ });
2827
+ const setTab = next => router.navigate(next === "overview" ? {} : {
2828
+ workflowsTab: next
2829
+ });
2090
2830
  useLogEventOnMount(WorkflowToolOpened, {
2091
2831
  tab: tab,
2092
2832
  via: "open"
2093
2833
  });
2094
- const instanceId = typeof router.state.instanceId == "string" ? router.state.instanceId : void 0;
2095
- return instanceId ? /* @__PURE__ */ jsx(WorkflowInstanceDetail, {
2834
+ let panel;
2835
+ return instanceId !== void 0 ? panel = /* @__PURE__ */ jsx(WorkflowInstanceDetail, {
2096
2836
  instanceId: instanceId,
2097
- onBack: () => router.navigate(carryingSearchParams({}, router.state._searchParams))
2098
- }, instanceId) : /* @__PURE__ */ jsx(WorkflowsHome, {
2837
+ onBack: goHome
2838
+ }, instanceId) : definitionName !== void 0 ? panel = /* @__PURE__ */ jsx(DefinitionDetail, {
2839
+ definitionName: definitionName
2840
+ }, definitionName) : panel = /* @__PURE__ */ jsx(WorkflowsHome, {
2841
+ filterSlot: filterSlot,
2842
+ onOpenDefinition: name => router.navigate({
2843
+ definitionName: name
2844
+ }),
2099
2845
  onOpenInstance: instance => {
2100
- typeof instance != "string" && seedInstance(instance), router.navigate(carryingSearchParams({
2846
+ typeof instance != "string" && seedInstance(instance), router.navigate({
2101
2847
  instanceId: typeof instance == "string" ? instance : instance._id
2102
- }, router.state._searchParams));
2103
- }
2104
- });
2105
- }
2106
-
2107
- function WorkflowsHome({onOpenInstance: onOpenInstance}) {
2108
- const {tab: tab, setTab: setTab} = useToolTab(), telemetry = useWorkflowTelemetry(), instances = useToolInstances(), identity = useAssignmentIdentity(), [openTask, setOpenTask] = useState(null), openInstance = target => {
2109
- if (typeof target != "string") return onOpenInstance(target);
2110
- const held = [ ...instances.inFlight, ...instances.settled ].find(i => i._id === target);
2111
- onOpenInstance(held ?? target);
2112
- }, [filterSlot, setFilterSlot] = useState(null), scrollerRef = useRef(null);
2113
- return useEffect(() => {
2114
- scrollerRef.current?.scrollTo({
2115
- top: 0
2116
- });
2117
- }, [ tab ]),
2848
+ });
2849
+ },
2850
+ tab: tab
2851
+ }),
2118
2852
  /* @__PURE__ */ jsxs(Card, {
2119
2853
  height: "fill",
2120
- children: [
2854
+ children: [ instanceStreamLatched ? /* @__PURE__ */ jsx(InstanceStreamKeepAlive, {}) : null,
2121
2855
  /* @__PURE__ */ jsxs(Flex, {
2122
2856
  direction: "column",
2123
2857
  height: "fill",
@@ -2126,75 +2860,99 @@ function WorkflowsHome({onOpenInstance: onOpenInstance}) {
2126
2860
  /* @__PURE__ */ jsx(Box, {
2127
2861
  flex: "none",
2128
2862
  padding: 3,
2129
- children: /* @__PURE__ */ jsx(Container, {
2130
- width: 2,
2131
- children: /* @__PURE__ */ jsxs(Stack, {
2863
+ children: /* @__PURE__ */ jsxs(Stack, {
2864
+ gap: 3,
2865
+ children: [
2866
+ /* @__PURE__ */ jsxs(Flex, {
2867
+ align: "center",
2132
2868
  gap: 3,
2869
+ paddingLeft: 2,
2133
2870
  children: [
2134
- /* @__PURE__ */ jsxs(Flex, {
2135
- align: "center",
2136
- gap: 3,
2137
- paddingLeft: 2,
2138
- children: [
2139
- /* @__PURE__ */ jsx(Text, {
2140
- size: 2,
2141
- weight: "semibold",
2142
- children: "Workflows"
2143
- }),
2144
- /* @__PURE__ */ jsx(Box, {
2145
- flex: 1
2146
- }),
2147
- /* @__PURE__ */ jsx(NewWorkflowButton, {}) ]
2871
+ /* @__PURE__ */ jsx(Text, {
2872
+ size: 1,
2873
+ weight: "semibold",
2874
+ children: "Workflows"
2148
2875
  }),
2149
- /* @__PURE__ */ jsx(TabSwitch, {
2150
- ariaControls: "workflows-tool-panel",
2151
- idPrefix: "workflows-tool-tab",
2152
- onSelect: next => {
2153
- next !== tab && telemetry.log(WorkflowToolOpened, {
2154
- tab: next,
2155
- via: "tab-switch"
2156
- }), setTab(next);
2157
- },
2158
- options: TOOL_TABS,
2159
- selected: tab
2876
+ /* @__PURE__ */ jsx(Box, {
2877
+ flex: 1
2160
2878
  }),
2161
- /* @__PURE__ */ jsx("div", {
2162
- ref: setFilterSlot
2163
- }) ]
2164
- })
2879
+ /* @__PURE__ */ jsx(NewWorkflowButton, {}) ]
2880
+ }),
2881
+ /* @__PURE__ */ jsx(TabSwitch, {
2882
+ ariaControls: "workflows-tool-panel",
2883
+ idPrefix: "workflows-tool-tab",
2884
+ onSelect: next => {
2885
+ next !== tab && telemetry.log(WorkflowToolOpened, {
2886
+ tab: next,
2887
+ via: "tab-switch"
2888
+ }), setTab(next);
2889
+ },
2890
+ options: TOOL_TABS,
2891
+ selected: tab
2892
+ }),
2893
+ /* @__PURE__ */ jsx("div", {
2894
+ ref: setFilterSlot
2895
+ }) ]
2165
2896
  })
2166
2897
  }),
2167
2898
  /* @__PURE__ */ jsx(Box, {
2168
- ref: scrollerRef,
2169
2899
  flex: 1,
2170
- overflow: "auto",
2171
- paddingX: 3,
2900
+ overflow: "hidden",
2901
+ children: panel
2902
+ }) ]
2903
+ }) ]
2904
+ });
2905
+ }
2906
+
2907
+ function WorkflowsHome({filterSlot: filterSlot, onOpenDefinition: onOpenDefinition, onOpenInstance: onOpenInstance, tab: tab}) {
2908
+ const instances = useToolInstances(), identity = useAssignmentIdentity(), [openTask, setOpenTask] = useState(null), openInstance = target => {
2909
+ if (typeof target != "string") return onOpenInstance(target);
2910
+ const held = [ ...instances.inFlight, ...instances.settled ].find(i => i._id === target);
2911
+ onOpenInstance(held ?? target);
2912
+ }, scrollerRef = useRef(null);
2913
+ return useEffect(() => {
2914
+ scrollerRef.current?.scrollTo({
2915
+ top: 0
2916
+ });
2917
+ }, [ tab ]), /* @__PURE__ */ jsxs(Flex, {
2918
+ direction: "column",
2919
+ height: "fill",
2920
+ overflow: "hidden",
2921
+ children: [
2922
+ /* @__PURE__ */ jsx(Box, {
2923
+ ref: scrollerRef,
2924
+ flex: 1,
2925
+ overflow: "auto",
2926
+ paddingX: 3,
2927
+ style: {
2928
+ scrollbarGutter: "stable"
2929
+ },
2930
+ children: /* @__PURE__ */ jsx(TabPanel, {
2931
+ "aria-labelledby": `workflows-tool-tab-${tab}`,
2932
+ id: "workflows-tool-panel",
2172
2933
  style: {
2173
- scrollbarGutter: "stable"
2934
+ display: "flex",
2935
+ flexDirection: "column",
2936
+ minHeight: "100%"
2174
2937
  },
2175
- children: /* @__PURE__ */ jsx(Container, {
2176
- width: 2,
2177
- children: /* @__PURE__ */ jsx(TabPanel, {
2178
- "aria-labelledby": `workflows-tool-tab-${tab}`,
2179
- id: "workflows-tool-panel",
2180
- children: /* @__PURE__ */ jsx(Box, {
2181
- paddingBottom: 4,
2182
- paddingTop: 1,
2183
- children: /* @__PURE__ */ jsx(TasksTab, {
2184
- filterSlot: filterSlot,
2185
- identity: identity,
2186
- instances: [ ...instances.inFlight, ...instances.settled ],
2187
- loading: instances.loading,
2188
- onOpenTask: setOpenTask,
2189
- onOpenWorkflow: openInstance,
2190
- segment: tab,
2191
- truncated: instances.truncated,
2192
- unreadable: instances.unreadable
2193
- })
2194
- })
2938
+ children: /* @__PURE__ */ jsx(Flex, {
2939
+ direction: "column",
2940
+ flex: 1,
2941
+ children: tab === "definitions" ? /* @__PURE__ */ jsx(DefinitionsTab, {
2942
+ onOpenDefinition: onOpenDefinition
2943
+ }) : /* @__PURE__ */ jsx(TasksTab, {
2944
+ filterSlot: filterSlot,
2945
+ identity: identity,
2946
+ instances: [ ...instances.inFlight, ...instances.settled ],
2947
+ loading: instances.loading,
2948
+ onOpenTask: setOpenTask,
2949
+ onOpenWorkflow: openInstance,
2950
+ segment: tab,
2951
+ truncated: instances.truncated,
2952
+ unreadable: instances.unreadable
2195
2953
  })
2196
2954
  })
2197
- }) ]
2955
+ })
2198
2956
  }), openTask ? /* @__PURE__ */ jsx(ToolActivityDialog, {
2199
2957
  onClose: () => setOpenTask(null),
2200
2958
  target: openTask