@sanity/workflow-studio-plugin 0.26.0 → 0.28.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
  "use strict";
2
2
 
3
- var jsxRuntime = require("react/jsx-runtime"), Timeline = require("@sanity/icons/Timeline"), ui = require("@sanity/ui"), workflowReact = require("@sanity/workflow-react"), react = require("react"), structure = require("sanity/structure"), workflowEngine = require("@sanity/workflow-engine"), Checkmark = require("@sanity/icons/Checkmark"), Close = require("@sanity/icons/Close"), formatDistanceToNow = require("date-fns/formatDistanceToNow"), workflowComponents = require("@sanity/workflow-components"), csm = require("@sanity/client/csm"), telemetry = require("@sanity/telemetry"), workflowStudio = require("@sanity/workflow-studio"), sanity = require("sanity"), Calendar = require("@sanity/icons/Calendar"), User = require("@sanity/icons/User"), Search = require("@sanity/icons/Search"), ChevronRight = require("@sanity/icons/ChevronRight"), Edit = require("@sanity/icons/Edit"), content = require("@sanity/util/content"), InfoOutline = require("@sanity/icons/InfoOutline"), Document = require("@sanity/icons/Document"), WarningOutline = require("@sanity/icons/WarningOutline"), router = require("sanity/router"), types = require("@sanity/types"), Launch = require("@sanity/icons/Launch"), Empty$1 = require("@sanity/icons/Empty"), ErrorFilled = require("@sanity/icons/ErrorFilled"), RemoveCircle = require("@sanity/icons/RemoveCircle"), Add = require("@sanity/icons/Add"), Bolt = require("@sanity/icons/Bolt"), ChevronDown = require("@sanity/icons/ChevronDown"), CheckmarkCircle = require("@sanity/icons/CheckmarkCircle"), Ulist = require("@sanity/icons/Ulist"), pluralize = require("pluralize-esm"), ArrowUp = require("@sanity/icons/ArrowUp"), rxjs = require("rxjs"), operators = require("rxjs/operators"), Transfer = require("@sanity/icons/Transfer");
3
+ var jsxRuntime = require("react/jsx-runtime"), Timeline = require("@sanity/icons/Timeline"), ui = require("@sanity/ui"), workflowReact = require("@sanity/workflow-react"), react = require("react"), structure = require("sanity/structure"), workflowEngine = require("@sanity/workflow-engine"), Checkmark = require("@sanity/icons/Checkmark"), Close = require("@sanity/icons/Close"), formatDistanceToNow = require("date-fns/formatDistanceToNow"), workflowComponents = require("@sanity/workflow-components"), csm = require("@sanity/client/csm"), telemetry = require("@sanity/telemetry"), workflowStudio = require("@sanity/workflow-studio"), sanity = require("sanity"), Calendar = require("@sanity/icons/Calendar"), User = require("@sanity/icons/User"), Search = require("@sanity/icons/Search"), ChevronRight = require("@sanity/icons/ChevronRight"), Edit = require("@sanity/icons/Edit"), content = require("@sanity/util/content"), InfoOutline = require("@sanity/icons/InfoOutline"), Document = require("@sanity/icons/Document"), WarningOutline = require("@sanity/icons/WarningOutline"), router = require("sanity/router"), types = require("@sanity/types"), Launch = require("@sanity/icons/Launch"), Empty$1 = require("@sanity/icons/Empty"), ErrorFilled = require("@sanity/icons/ErrorFilled"), RemoveCircle = require("@sanity/icons/RemoveCircle"), Add = require("@sanity/icons/Add"), Ulist = require("@sanity/icons/Ulist"), CheckmarkCircle = require("@sanity/icons/CheckmarkCircle"), Bolt = require("@sanity/icons/Bolt"), ChevronDown = require("@sanity/icons/ChevronDown"), pluralize = require("pluralize-esm"), EllipsisHorizontal = require("@sanity/icons/EllipsisHorizontal"), Clock = require("@sanity/icons/Clock"), Cog = require("@sanity/icons/Cog"), ArrowUp = require("@sanity/icons/ArrowUp"), ErrorOutline = require("@sanity/icons/ErrorOutline"), rxjs = require("rxjs"), operators = require("rxjs/operators"), Transfer = require("@sanity/icons/Transfer");
4
4
 
5
5
  function _interopDefaultCompat(e) {
6
6
  return e && typeof e == "object" && "default" in e ? e : {
@@ -291,13 +291,7 @@ function landingDefaultOpen(landing, instanceId) {
291
291
  if (!(landing === void 0 || !landing.instanceIds.includes(instanceId))) return instanceId === landing.focusedId;
292
292
  }
293
293
 
294
- const WORKFLOWS_TOOL_NAME = "workflows";
295
-
296
- function workflowsToolAvailable(tools) {
297
- return tools.some(tool => tool.name === WORKFLOWS_TOOL_NAME);
298
- }
299
-
300
- const WORKFLOW_INTENT = "workflow";
294
+ const WORKFLOWS_TOOL_NAME = "workflows", WORKFLOW_INTENT = "workflow";
301
295
 
302
296
  function pathSegmentName(args) {
303
297
  return args.names.find(name => name === args.segment);
@@ -370,6 +364,10 @@ function describeEditDisabledReason(reason) {
370
364
  return editDisabledSentence[reason.kind](reason);
371
365
  }
372
366
 
367
+ function reasonRestatesInstanceState(reason) {
368
+ return reason.kind === "instance-aborted" || reason.kind === "instance-completed";
369
+ }
370
+
373
371
  function formatDateTime(value) {
374
372
  if (!value) return "—";
375
373
  const d = new Date(value);
@@ -688,6 +686,11 @@ function changedAssignee(current, next) {
688
686
  return next.find(item => !current.some(existing => workflowComponents.sameAssignee(item, existing))) ?? current.find(item => !next.some(existing => workflowComponents.sameAssignee(item, existing)));
689
687
  }
690
688
 
689
+ function singleAssigneePick(current, next) {
690
+ const changed = changedAssignee(current ? [ current ] : [], next);
691
+ if (changed !== void 0) return current && workflowComponents.sameAssignee(changed, current) ? null : changed;
692
+ }
693
+
691
694
  function isAssigneeShape(value) {
692
695
  if (typeof value != "object" || value === null) return !1;
693
696
  const {type: type, id: id, role: role} = value;
@@ -700,22 +703,44 @@ function isActorShape(value) {
700
703
  return typeof id != "string" ? !1 : roles === void 0 || Array.isArray(roles) && roles.every(r => typeof r == "string");
701
704
  }
702
705
 
703
- function assigneeUserIdsOf(entries) {
704
- const ids = entries.flatMap(entry => entry._type === "assignees" ? entry.value.flatMap(a => a.type === "user" ? [ a.id ] : []) : entry._type === "assignee" ? entry.value?.type === "user" ? [ entry.value.id ] : [] : []);
705
- return [ ...new Set(ids) ];
706
+ function assigneesOf(entries) {
707
+ return entries.flatMap(entry => entry._type === "assignees" ? entry.value : []);
708
+ }
709
+
710
+ function assigneeEdit(current, next) {
711
+ const changed = changedAssignee(current, next);
712
+ if (changed !== void 0) return next.some(item => workflowComponents.sameAssignee(item, changed)) ? {
713
+ mode: "append",
714
+ value: changed
715
+ } : {
716
+ mode: "set",
717
+ value: next
718
+ };
706
719
  }
707
720
 
708
721
  function isItemAssignedTo(item, who) {
709
722
  return item.assignee != null && assigneeMatches(item.assignee, who);
710
723
  }
711
724
 
725
+ function matchingAssignees(state, who) {
726
+ return state.flatMap(entry => entry._type === "assignees" ? entry.value.filter(a => assigneeMatches(a, who)) : entry._type === "assignee" && entry.value !== null && assigneeMatches(entry.value, who) ? [ entry.value ] : []);
727
+ }
728
+
712
729
  function isActivityAssignedTo(args) {
713
- return args.state.some(entry => entry._type === "assignees" ? entry.value.some(a => assigneeMatches(a, args.who)) : entry._type === "assignee" ? entry.value !== null && assigneeMatches(entry.value, args.who) : !1);
730
+ return matchingAssignees(args.state, args.who).length > 0;
731
+ }
732
+
733
+ function isRoleAssignedTo(args) {
734
+ return matchingAssignees(args.state, args.who).some(member => member.type === "role");
735
+ }
736
+
737
+ function isItemRoleAssignedTo(item, who) {
738
+ return isItemAssignedTo(item, who) && item.assignee?.type === "role";
714
739
  }
715
740
 
716
741
  function assignedWork(args) {
717
- const {instance: instance, committed: committed, who: who} = args, evaluation = args.staleEvaluation === "keep" || isEvaluationCurrent(args) ? args.evaluation : void 0, byActivity = stateByActivity(instance), activities = (evaluation?.currentStage.activities ?? []).filter(t => isActivityAssignedTo({
718
- state: byActivity.get(t.activity.name) ?? [],
742
+ const {instance: instance, committed: committed, who: who} = args, evaluation = args.staleEvaluation === "keep" || isEvaluationCurrent(args) ? args.evaluation : void 0, byActivity = stateByActivity(instance), stateOf = t => byActivity.get(t.activity.name) ?? [], activities = (evaluation?.currentStage.activities ?? []).filter(t => isActivityAssignedTo({
743
+ state: stateOf(t),
719
744
  who: who
720
745
  })), items = deriveTodoItems({
721
746
  instance: instance,
@@ -725,7 +750,11 @@ function assignedWork(args) {
725
750
  return {
726
751
  activities: activities,
727
752
  openItems: items.filter(row => !isTodoDone(row.item)),
728
- doneItems: items.filter(row => isTodoDone(row.item))
753
+ doneItems: items.filter(row => isTodoDone(row.item)),
754
+ roleMatched: activities.some(t => isRoleAssignedTo({
755
+ state: stateOf(t),
756
+ who: who
757
+ })) || items.some(row => isItemRoleAssignedTo(row.item, who))
729
758
  };
730
759
  }
731
760
 
@@ -774,7 +803,8 @@ function forMeWorkOf(entries, identity) {
774
803
  return {
775
804
  work: work,
776
805
  count: work.reduce((n, {count: count}) => n + count, 0),
777
- hasRows: work.some(({shown: shown}) => hasAssignedRows(shown))
806
+ hasRows: work.some(({shown: shown}) => hasAssignedRows(shown)),
807
+ hasRoleMatched: work.some(({shown: shown}) => shown.roleMatched)
778
808
  };
779
809
  }
780
810
 
@@ -1032,7 +1062,7 @@ function activityRowProps(args) {
1032
1062
  blocked: showsBlockedTag(activityEval)
1033
1063
  },
1034
1064
  assignState: rowAssignControlState(controlArgs),
1035
- assigneeIds: assigneeUserIdsOf(state),
1065
+ assignees: assigneesOf(state),
1036
1066
  dateState: rowDateControlState(controlArgs),
1037
1067
  dueDates: dueDatesOf(state),
1038
1068
  terminalActions: rowTerminalActions({
@@ -1340,15 +1370,18 @@ function projectMembersFrom(users) {
1340
1370
  sanityUserId: profile?.sanityUserId,
1341
1371
  displayName: profile?.displayName,
1342
1372
  email: profile?.email,
1343
- imageUrl: profile?.imageUrl ?? void 0
1373
+ imageUrl: profile?.imageUrl ?? void 0,
1374
+ loginProvider: workflowEngine.userLoginProvider(profile),
1375
+ isCurrentUser: membership.isCurrentUser
1344
1376
  }));
1345
1377
  return projectMembersByUsers.set(users, members), members;
1346
1378
  }
1347
1379
 
1348
1380
  function useProjectMembers() {
1349
- const {users: users, loading: loading, error: error} = workflowStudio.useStudioProjectUsers();
1381
+ const {users: users, roles: roles, loading: loading, error: error} = workflowStudio.useStudioProjectUsers();
1350
1382
  return {
1351
1383
  members: react.useMemo(() => projectMembersFrom(users), [ users ]),
1384
+ roles: roles,
1352
1385
  loading: loading,
1353
1386
  error: error === void 0 ? void 0 : workflowEngine.errorMessage(error)
1354
1387
  };
@@ -1702,10 +1735,12 @@ function PickedValueRow({children: children, onRequestChange: onRequestChange})
1702
1735
  }
1703
1736
 
1704
1737
  function MemberPicker({selectedIds: selectedIds, onSelect: onSelect, unassignRow: unassignRow = !1}) {
1705
- const state = useProjectMembers();
1738
+ const {error: error, loading: loading, members: members} = useProjectMembers();
1706
1739
  /* @__PURE__ */
1707
1740
  return jsxRuntime.jsx(workflowComponents.MemberPicker, {
1708
- ...state,
1741
+ error: error,
1742
+ loading: loading,
1743
+ members: members,
1709
1744
  onSelect: onSelect,
1710
1745
  selectedIds: selectedIds,
1711
1746
  unassignRow: unassignRow
@@ -1722,6 +1757,17 @@ function AssigneePicker({value: value, onChange: onChange}) {
1722
1757
  });
1723
1758
  }
1724
1759
 
1760
+ function SingleAssigneePicker({current: current, onPick: onPick}) {
1761
+ /* @__PURE__ */
1762
+ return jsxRuntime.jsx(AssigneePicker, {
1763
+ onChange: next => {
1764
+ const picked = singleAssigneePick(current, next);
1765
+ picked !== void 0 && onPick(picked);
1766
+ },
1767
+ value: current ? [ current ] : []
1768
+ });
1769
+ }
1770
+
1725
1771
  function MemberPickerButton({label: label = "Select member…", onChange: onChange, selectedIds: selectedIds, unassignRow: unassignRow = !1, value: value}) {
1726
1772
  const [open, setOpen] = react.useState(!1), {imageUrl: imageUrl} = useUserDisplay(value?.id ?? ""), selected = selectedIds ?? (value ? /* @__PURE__ */ new Set([ value.id ]) : /* @__PURE__ */ new Set), toggle = () => setOpen(v => !v);
1727
1773
  /* @__PURE__ */
@@ -1731,7 +1777,7 @@ function MemberPickerButton({label: label = "Select member…", onChange: onChan
1731
1777
  setOpen(!1), onChange(member && !selected.has(member.id) ? {
1732
1778
  id: member.id,
1733
1779
  displayName: member.displayName,
1734
- roles: member.roles
1780
+ roles: member.roles.map(role => role.name)
1735
1781
  } : null);
1736
1782
  },
1737
1783
  selectedIds: selected,
@@ -2419,7 +2465,7 @@ function Separator() {
2419
2465
  alignItems: "center",
2420
2466
  display: "inline-flex",
2421
2467
  height: "0.7em",
2422
- margin: "0 0.25em",
2468
+ margin: "0 0.5em",
2423
2469
  overflow: "hidden"
2424
2470
  },
2425
2471
  children: /* @__PURE__ */ jsxRuntime.jsx(ChevronRight.ChevronRightIcon, {})
@@ -2478,20 +2524,20 @@ function noteRow(args) {
2478
2524
  }
2479
2525
 
2480
2526
  function AssigneeBadge({assignee: assignee}) {
2481
- const {members: members} = useProjectMembers();
2527
+ const vocabulary = useProjectMembers();
2482
2528
  /* @__PURE__ */
2483
2529
  return jsxRuntime.jsx(workflowComponents.AssigneeBadge, {
2484
2530
  assignee: assignee,
2485
- members: members
2531
+ vocabulary: vocabulary
2486
2532
  });
2487
2533
  }
2488
2534
 
2489
2535
  function AssigneeBadges({assignees: assignees}) {
2490
- const {members: members} = useProjectMembers();
2536
+ const vocabulary = useProjectMembers();
2491
2537
  /* @__PURE__ */
2492
2538
  return jsxRuntime.jsx(workflowComponents.AssigneeBadges, {
2493
2539
  assignees: assignees,
2494
- members: members
2540
+ vocabulary: vocabulary
2495
2541
  });
2496
2542
  }
2497
2543
 
@@ -3538,18 +3584,18 @@ function ActorField({field: field, instanceId: instanceId, onSave: onSave, onUns
3538
3584
  }
3539
3585
 
3540
3586
  function useAssigneePick(args) {
3541
- const {current: current, onSave: onSave, onUnset: onUnset} = args, {saving: saving, save: save} = useSaveField({
3587
+ const {onSave: onSave, onUnset: onUnset} = args, {saving: saving, save: save} = useSaveField({
3542
3588
  instanceId: args.instanceId
3543
3589
  });
3544
3590
  return {
3545
3591
  saving: saving,
3546
- pick: assignee => {
3592
+ pick: picked => {
3547
3593
  if (!saving) {
3548
- if (current && workflowComponents.sameAssignee(assignee, current)) {
3594
+ if (picked === null) {
3549
3595
  onUnset !== void 0 && save(onUnset);
3550
3596
  return;
3551
3597
  }
3552
- save(() => onSave(assignee));
3598
+ save(() => onSave(picked));
3553
3599
  }
3554
3600
  }
3555
3601
  };
@@ -3557,22 +3603,18 @@ function useAssigneePick(args) {
3557
3603
 
3558
3604
  function AssigneeField({field: field, instanceId: instanceId, onSave: onSave, onUnset: onUnset}) {
3559
3605
  const [open, setOpen] = react.useState(!1), cur = isAssigneeShape(field.value) ? field.value : null, {pick: pick} = useAssigneePick({
3560
- current: cur,
3561
3606
  instanceId: instanceId,
3562
3607
  onSave: onSave,
3563
3608
  onUnset: onUnset
3564
- }), pickAndClose = assignee => {
3565
- setOpen(!1), pick(assignee);
3566
- };
3609
+ });
3567
3610
  return field.editable ? /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
3568
3611
  align: "center",
3569
3612
  children: /* @__PURE__ */ jsxRuntime.jsx(DismissablePopover, {
3570
- content: /* @__PURE__ */ jsxRuntime.jsx(AssigneePicker, {
3571
- onChange: next => {
3572
- const changed = changedAssignee(cur ? [ cur ] : [], next);
3573
- changed && pickAndClose(changed);
3574
- },
3575
- value: cur ? [ cur ] : []
3613
+ content: /* @__PURE__ */ jsxRuntime.jsx(SingleAssigneePicker, {
3614
+ current: cur,
3615
+ onPick: picked => {
3616
+ setOpen(!1), pick(picked);
3617
+ }
3576
3618
  }),
3577
3619
  onDismiss: () => setOpen(!1),
3578
3620
  open: open,
@@ -4121,70 +4163,85 @@ function AvatarButton({avatar: avatar, onClick: onClick, onMouseDown: onMouseDow
4121
4163
  });
4122
4164
  }
4123
4165
 
4124
- function UserAvatar({id: id}) {
4125
- const {name: name, imageUrl: imageUrl} = useUserDisplay(id);
4166
+ function RowAssignees({assignees: assignees, hint: hint}) {
4167
+ const ids = assignees.flatMap(item => item.type === "user" ? [ item.id ] : []), vocabulary = useProjectMembers(), roles = assignees.flatMap(item => item.type === "role" ? [ workflowComponents.memberRoleFor(vocabulary, item.role) ] : []), displays = useUserDisplays(ids);
4168
+ if (ids.length === 0 && roles.length === 0) return null;
4169
+ const bothKinds = roles.length > 0 && displays.length > 0;
4126
4170
  /* @__PURE__ */
4127
4171
  return jsxRuntime.jsx(HoverHint, {
4128
- text: name,
4129
- children: /* @__PURE__ */ jsxRuntime.jsx(workflowComponents.MemberAvatar, {
4130
- imageUrl: imageUrl,
4131
- name: name
4132
- })
4133
- });
4134
- }
4135
-
4136
- function UserAvatarGroup({ids: ids, hint: hint}) {
4137
- const displays = useUserDisplays(ids);
4138
- return displays.length === 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(HoverHint, {
4139
- text: displays.map(d => d.name).join(", "),
4140
- ...hint === void 0 ? {} : {
4141
- description: hint
4142
- },
4143
- children: /* @__PURE__ */ jsxRuntime.jsx(workflowComponents.MemberAvatarGroup, {
4172
+ content:
4173
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
4174
+ gap: 3,
4175
+ children: [ roles.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(HintSection, {
4176
+ names: roles.map(workflowComponents.roleLabel),
4177
+ ...bothKinds ? {
4178
+ label: "Roles"
4179
+ } : {}
4180
+ }) : null, displays.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(HintSection, {
4181
+ names: displays.map(display => display.name),
4182
+ ...bothKinds ? {
4183
+ label: "Members"
4184
+ } : {}
4185
+ }) : null, hint === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
4186
+ muted: !0,
4187
+ size: 1,
4188
+ children: hint
4189
+ }) ]
4190
+ }),
4191
+ children: /* @__PURE__ */ jsxRuntime.jsx(workflowComponents.AssigneeStack, {
4144
4192
  members: displays.map(display => ({
4145
4193
  id: display.id,
4146
4194
  displayName: display.name,
4147
4195
  imageUrl: display.imageUrl
4148
- }))
4196
+ })),
4197
+ roles: roles
4149
4198
  })
4150
4199
  });
4151
4200
  }
4152
4201
 
4153
- function AssignActivityControl({instanceId: instanceId, state: state, surface: surface, assigneeIds: assigneeIds = []}) {
4202
+ function HintSection({label: label, names: names}) {
4203
+ /* @__PURE__ */
4204
+ return jsxRuntime.jsxs(ui.Stack, {
4205
+ gap: 2,
4206
+ children: [ label === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
4207
+ size: 1,
4208
+ weight: "medium",
4209
+ children: label
4210
+ }),
4211
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
4212
+ size: 1,
4213
+ children: names.join(", ")
4214
+ }) ]
4215
+ });
4216
+ }
4217
+
4218
+ function AssignActivityControl({instanceId: instanceId, state: state, surface: surface, assignees: assignees = []}) {
4154
4219
  const editField = useEditField(surface), report = useRejectionReport(), [open, setOpen] = react.useState(!1), [busy, setBusy] = react.useState(!1);
4155
- if (state.kind === "none") return assigneeIds.length === 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(AvatarDisplay, {
4220
+ if (state.kind === "none") return assignees.length === 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(AvatarDisplay, {
4156
4221
  "aria-label": "Assignees",
4157
- avatar: /* @__PURE__ */ jsxRuntime.jsx(UserAvatarGroup, {
4158
- ids: assigneeIds
4222
+ avatar: /* @__PURE__ */ jsxRuntime.jsx(RowAssignees, {
4223
+ assignees: assignees
4159
4224
  })
4160
4225
  });
4161
- if (state.kind === "closed") return assigneeIds.length === 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(AvatarButton, {
4226
+ if (state.kind === "closed") return assignees.length === 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(AvatarButton, {
4162
4227
  "aria-label": "Assignees",
4163
4228
  as: "span",
4164
- avatar: /* @__PURE__ */ jsxRuntime.jsx(UserAvatarGroup, {
4165
- hint: state.reason,
4166
- ids: assigneeIds
4229
+ avatar: /* @__PURE__ */ jsxRuntime.jsx(RowAssignees, {
4230
+ assignees: assignees,
4231
+ hint: state.reason
4167
4232
  }),
4168
4233
  onClick: stopRowClick,
4169
4234
  onMouseDown: stopRowMouseDown
4170
4235
  });
4171
- const field = state.kind === "editable" ? state.field : void 0, members = field?.value ?? [], selectedIds = new Set(members.flatMap(m => m.type === "user" ? [ m.id ] : [])), toggle = async memberId => {
4172
- if (!(busy || field === void 0)) {
4236
+ const field = state.kind === "editable" ? state.field : void 0, current = field?.value ?? [], change = async next => {
4237
+ const edit = assigneeEdit(current, next);
4238
+ if (!(busy || field === void 0 || edit === void 0)) {
4173
4239
  setBusy(!0);
4174
4240
  try {
4175
- selectedIds.has(memberId) ? await editField({
4176
- instanceId: instanceId,
4177
- field: field,
4178
- mode: "set",
4179
- value: members.filter(m => !(m.type === "user" && m.id === memberId))
4180
- }) : await editField({
4241
+ await editField({
4181
4242
  instanceId: instanceId,
4182
4243
  field: field,
4183
- mode: "append",
4184
- value: {
4185
- type: "user",
4186
- id: memberId
4187
- }
4244
+ ...edit
4188
4245
  }), report.dismiss(instanceToastId("assign", instanceId));
4189
4246
  } catch (err) {
4190
4247
  report.rejected({
@@ -4200,12 +4257,12 @@ function AssignActivityControl({instanceId: instanceId, state: state, surface: s
4200
4257
  }
4201
4258
  }, handleClick = e => {
4202
4259
  e.stopPropagation(), setOpen(v => !v);
4203
- }, button = assigneeIds.length > 0 ?
4260
+ }, button = assignees.length > 0 ?
4204
4261
  /* @__PURE__ */ jsxRuntime.jsx(AvatarButton, {
4205
4262
  "aria-label": "Assignees",
4206
4263
  as: "span",
4207
- avatar: /* @__PURE__ */ jsxRuntime.jsx(UserAvatarGroup, {
4208
- ids: assigneeIds
4264
+ avatar: /* @__PURE__ */ jsxRuntime.jsx(RowAssignees, {
4265
+ assignees: assignees
4209
4266
  }),
4210
4267
  onClick: handleClick,
4211
4268
  onMouseDown: stopRowMouseDown
@@ -4230,9 +4287,11 @@ function AssignActivityControl({instanceId: instanceId, state: state, surface: s
4230
4287
  children: state.kind === "loading" ? /* @__PURE__ */ jsxRuntime.jsx(LoadingRow, {
4231
4288
  label: "Loading…",
4232
4289
  padding: 3
4233
- }) : /* @__PURE__ */ jsxRuntime.jsx(MemberPicker, {
4234
- onSelect: member => member && void toggle(member.id),
4235
- selectedIds: selectedIds
4290
+ }) : /* @__PURE__ */ jsxRuntime.jsx(AssigneePicker, {
4291
+ onChange: next => {
4292
+ change(next);
4293
+ },
4294
+ value: current
4236
4295
  })
4237
4296
  }),
4238
4297
  onDismiss: () => setOpen(!1),
@@ -4264,6 +4323,58 @@ function canRemoveRow(args) {
4264
4323
  return editTarget === void 0 || appendTarget === void 0 ? !1 : editTarget.scope === appendTarget.scope && editTarget.field === appendTarget.field && editTarget.activity === appendTarget.activity;
4265
4324
  }
4266
4325
 
4326
+ function EmptyState({action: action, description: description, icon: icon, title: title}) {
4327
+ /* @__PURE__ */
4328
+ return jsxRuntime.jsx(ui.Card, {
4329
+ border: !0,
4330
+ flex: 1,
4331
+ padding: 4,
4332
+ radius: 3,
4333
+ style: {
4334
+ alignItems: "center",
4335
+ display: "flex",
4336
+ justifyContent: "center"
4337
+ },
4338
+ children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
4339
+ gap: 4,
4340
+ children: [
4341
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
4342
+ align: "center",
4343
+ size: 4,
4344
+ children: icon
4345
+ }),
4346
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
4347
+ gap: 3,
4348
+ children: [
4349
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
4350
+ align: "center",
4351
+ size: 1,
4352
+ weight: "medium",
4353
+ children: title
4354
+ }),
4355
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
4356
+ align: "center",
4357
+ muted: !0,
4358
+ size: 1,
4359
+ children: description
4360
+ }) ]
4361
+ }), action ? /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
4362
+ justify: "center",
4363
+ children: action
4364
+ }) : null ]
4365
+ })
4366
+ });
4367
+ }
4368
+
4369
+ function ForMeEmptyState() {
4370
+ /* @__PURE__ */
4371
+ return jsxRuntime.jsx(EmptyState, {
4372
+ description: "No activities or to-dos are assigned to you",
4373
+ icon: /* @__PURE__ */ jsxRuntime.jsx(CheckmarkCircle.CheckmarkCircleIcon, {}),
4374
+ title: "Nothing to do!"
4375
+ });
4376
+ }
4377
+
4267
4378
  function looksLikeDefinition(value) {
4268
4379
  return typeof value == "object" && value !== null && Array.isArray(value.stages);
4269
4380
  }
@@ -4421,22 +4532,18 @@ function DueDateControl({item: item, editable: editable, onPatch: onPatch}) {
4421
4532
  }
4422
4533
 
4423
4534
  function AssigneeControl({item: item, editable: editable, onPatch: onPatch}) {
4424
- const [open, setOpen] = react.useState(!1), assignedId = item.assignee?.type === "user" ? item.assignee.id : void 0, chip = assignedId ? /* @__PURE__ */ jsxRuntime.jsx(UserAvatar, {
4425
- id: assignedId
4535
+ const [open, setOpen] = react.useState(!1), current = item.assignee ?? null, chip = current ? /* @__PURE__ */ jsxRuntime.jsx(RowAssignees, {
4536
+ assignees: [ current ]
4426
4537
  }) : null;
4427
4538
  return editable ? /* @__PURE__ */ jsxRuntime.jsx(DismissablePopover, {
4428
4539
  content:
4429
- /* @__PURE__ */ jsxRuntime.jsx(MemberPicker, {
4430
- onSelect: member => {
4540
+ /* @__PURE__ */ jsxRuntime.jsx(SingleAssigneePicker, {
4541
+ current: current,
4542
+ onPick: picked => {
4431
4543
  setOpen(!1), onPatch({
4432
- assignee: member && member.id !== assignedId ? {
4433
- type: "user",
4434
- id: member.id
4435
- } : null
4544
+ assignee: picked
4436
4545
  });
4437
- },
4438
- selectedIds: assignedId ? /* @__PURE__ */ new Set([ assignedId ]) : /* @__PURE__ */ new Set,
4439
- unassignRow: !0
4546
+ }
4440
4547
  }),
4441
4548
  onDismiss: () => setOpen(!1),
4442
4549
  open: open,
@@ -4632,7 +4739,7 @@ function TodoItemRowView({breadcrumb: breadcrumb, row: row, onToggle: onToggle,
4632
4739
  });
4633
4740
  }
4634
4741
 
4635
- function TodoItemsList({breadcrumb: breadcrumb, entry: entry, filter: filter, surface: surface}) {
4742
+ function TodoItemsList({breadcrumb: breadcrumb, entry: entry, filter: filter, showEmpty: showEmpty = !1, surface: surface}) {
4636
4743
  const {instance: instance} = entry, definition = useDefinition(entry), {editFieldFor: editFieldFor, fireActionFor: fireActionFor} = useWorkflowContext(), telemetry2 = workflowReact.useWorkflowTelemetry(), report = useRejectionReport(), [busy, setBusy] = react.useState(!1), derivation = deriveTodoItems(entry), rows = derivation.rows.filter(row => rowMatches(row, filter)), appendTarget = appendTargetFor(derivation.appendTargets, filter), run = async op => {
4637
4744
  if (busy) return !1;
4638
4745
  setBusy(!0);
@@ -4728,8 +4835,28 @@ function TodoItemsList({breadcrumb: breadcrumb, entry: entry, filter: filter, su
4728
4835
  kind: "remove",
4729
4836
  success: success
4730
4837
  });
4731
- };
4732
- if (rows.length === 0 && !appendTarget) return null;
4838
+ }, empty = rows.length === 0;
4839
+ if (empty && !showEmpty) return null;
4840
+ const addControl = appendTarget ? /* @__PURE__ */ jsxRuntime.jsx(AddItemControl, {
4841
+ busy: busy,
4842
+ button: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
4843
+ fontSize: 1,
4844
+ icon: Add.AddIcon,
4845
+ mode: "ghost",
4846
+ padding: 2,
4847
+ text: "Add item"
4848
+ }),
4849
+ onAdd: addItem
4850
+ }) : null;
4851
+ if (empty) /* @__PURE__ */
4852
+ return jsxRuntime.jsx(EmptyState, {
4853
+ ...addControl === null ? {} : {
4854
+ action: addControl
4855
+ },
4856
+ description: "Nothing has been added to this list",
4857
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Ulist.UlistIcon, {}),
4858
+ title: "No to-dos"
4859
+ });
4733
4860
  const rowKey = row => `${row.scope}:${row.activityName ?? ""}:${row.fieldName}:${row.item._key}`, rowBreadcrumb = row => {
4734
4861
  if (breadcrumb === void 0 || row.activityName === void 0) return breadcrumb;
4735
4862
  const {title: title} = findActivity({
@@ -4763,19 +4890,9 @@ function TodoItemsList({breadcrumb: breadcrumb, entry: entry, filter: filter, su
4763
4890
  },
4764
4891
  row: row
4765
4892
  }, rowKey(row)))
4766
- }), appendTarget ? /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
4767
- children: /* @__PURE__ */ jsxRuntime.jsx(AddItemControl, {
4768
- busy: busy,
4769
- button: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
4770
- fontSize: 1,
4771
- icon: Add.AddIcon,
4772
- mode: "ghost",
4773
- padding: 2,
4774
- text: "Add item"
4775
- }),
4776
- onAdd: addItem
4777
- })
4778
- }) : null ]
4893
+ }), addControl === null ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
4894
+ children: addControl
4895
+ }) ]
4779
4896
  });
4780
4897
  }
4781
4898
 
@@ -5214,6 +5331,7 @@ function FieldRow({field: field, detail: detail, entry: entry, activityName: act
5214
5331
  field: field.name,
5215
5332
  activity: activityName
5216
5333
  },
5334
+ showEmpty: !0,
5217
5335
  surface: "activity-dialog"
5218
5336
  }) ]
5219
5337
  });
@@ -5270,58 +5388,6 @@ function blockedNotice(detail) {
5270
5388
  });
5271
5389
  }
5272
5390
 
5273
- function EmptyState({action: action, description: description, icon: icon, title: title}) {
5274
- /* @__PURE__ */
5275
- return jsxRuntime.jsx(ui.Card, {
5276
- border: !0,
5277
- flex: 1,
5278
- padding: 4,
5279
- radius: 3,
5280
- style: {
5281
- alignItems: "center",
5282
- display: "flex",
5283
- justifyContent: "center"
5284
- },
5285
- children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
5286
- gap: 4,
5287
- children: [
5288
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
5289
- align: "center",
5290
- size: 4,
5291
- children: icon
5292
- }),
5293
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
5294
- gap: 3,
5295
- children: [
5296
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
5297
- align: "center",
5298
- size: 1,
5299
- weight: "medium",
5300
- children: title
5301
- }),
5302
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
5303
- align: "center",
5304
- muted: !0,
5305
- size: 1,
5306
- children: description
5307
- }) ]
5308
- }), action ? /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
5309
- justify: "center",
5310
- children: action
5311
- }) : null ]
5312
- })
5313
- });
5314
- }
5315
-
5316
- function ForMeEmptyState() {
5317
- /* @__PURE__ */
5318
- return jsxRuntime.jsx(EmptyState, {
5319
- description: "No activities or to-dos are assigned to you",
5320
- icon: /* @__PURE__ */ jsxRuntime.jsx(CheckmarkCircle.CheckmarkCircleIcon, {}),
5321
- title: "Nothing to do!"
5322
- });
5323
- }
5324
-
5325
5391
  function CountedLabel({count: count, label: label}) {
5326
5392
  return count === void 0 || count === 0 ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, {
5327
5393
  children: label
@@ -5522,17 +5588,13 @@ function TitleTag({hint: hint, tone: tone, children: children}) {
5522
5588
  });
5523
5589
  }
5524
5590
 
5525
- function ActivityRow({face: face, breadcrumb: breadcrumb, assigneeIds: assigneeIds, assignState: assignState, dateState: dateState, dueDates: dueDates, instanceId: instanceId, onOpen: onOpen, surface: surface, terminalActions: terminalActions = []}) {
5591
+ function ActivityRow({face: face, breadcrumb: breadcrumb, assignees: assignees, assignState: assignState, dateState: dateState, dueDates: dueDates, instanceId: instanceId, onOpen: onOpen, surface: surface, terminalActions: terminalActions = []}) {
5526
5592
  const settled = workflowEngine.isTerminalActivityStatus(face.status), dimmed = settledDim(settled);
5527
5593
  /* @__PURE__ */
5528
5594
  return jsxRuntime.jsxs(WorkRow, {
5529
- end: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
5530
- children: [ settled || terminalActions.length === 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(RowTerminalActions, {
5531
- actions: terminalActions,
5532
- activity: face.activityName,
5533
- instanceId: instanceId,
5534
- surface: surface
5535
- }),
5595
+ end:
5596
+ /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
5597
+ children: [
5536
5598
  /* @__PURE__ */ jsxRuntime.jsx(ActivityDateControl, {
5537
5599
  dueDates: dueDates,
5538
5600
  instanceId: instanceId,
@@ -5540,10 +5602,15 @@ function ActivityRow({face: face, breadcrumb: breadcrumb, assigneeIds: assigneeI
5540
5602
  surface: surface
5541
5603
  }),
5542
5604
  /* @__PURE__ */ jsxRuntime.jsx(AssignActivityControl, {
5543
- assigneeIds: assigneeIds,
5605
+ assignees: assignees,
5544
5606
  instanceId: instanceId,
5545
5607
  state: assignState,
5546
5608
  surface: surface
5609
+ }), settled || terminalActions.length === 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(RowTerminalActions, {
5610
+ actions: terminalActions,
5611
+ activity: face.activityName,
5612
+ instanceId: instanceId,
5613
+ surface: surface
5547
5614
  }) ]
5548
5615
  }),
5549
5616
  lead: /* @__PURE__ */ jsxRuntime.jsx(ActivityStatusLead, {
@@ -5767,6 +5834,35 @@ function deriveFieldPills(args) {
5767
5834
  });
5768
5835
  }
5769
5836
 
5837
+ function UserAvatar({id: id}) {
5838
+ const {name: name, imageUrl: imageUrl} = useUserDisplay(id);
5839
+ /* @__PURE__ */
5840
+ return jsxRuntime.jsx(HoverHint, {
5841
+ text: name,
5842
+ children: /* @__PURE__ */ jsxRuntime.jsx(workflowComponents.MemberAvatar, {
5843
+ imageUrl: imageUrl,
5844
+ name: name
5845
+ })
5846
+ });
5847
+ }
5848
+
5849
+ function UserAvatarGroup({ids: ids, hint: hint}) {
5850
+ const displays = useUserDisplays(ids);
5851
+ return displays.length === 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(HoverHint, {
5852
+ text: displays.map(d => d.name).join(", "),
5853
+ ...hint === void 0 ? {} : {
5854
+ description: hint
5855
+ },
5856
+ children: /* @__PURE__ */ jsxRuntime.jsx(workflowComponents.MemberAvatarGroup, {
5857
+ members: displays.map(display => ({
5858
+ id: display.id,
5859
+ displayName: display.name,
5860
+ imageUrl: display.imageUrl
5861
+ }))
5862
+ })
5863
+ });
5864
+ }
5865
+
5770
5866
  function TodoFieldDialog({entry: entry, scope: scope, field: field, title: title, onClose: onClose}) {
5771
5867
  /* @__PURE__ */
5772
5868
  return jsxRuntime.jsx(ui.Dialog, {
@@ -5783,6 +5879,7 @@ function TodoFieldDialog({entry: entry, scope: scope, field: field, title: title
5783
5879
  scope: scope,
5784
5880
  field: field
5785
5881
  },
5882
+ showEmpty: !0,
5786
5883
  surface: "todo-field-dialog"
5787
5884
  })
5788
5885
  })
@@ -5900,19 +5997,31 @@ function PillContent({pill: pill}) {
5900
5997
  children: [ lead,
5901
5998
  /* @__PURE__ */ jsxRuntime.jsx(FaceText, {
5902
5999
  muted: !0,
5903
- children: pill.editability?.editable === !0 ? `Set ${pill.title}` : pill.title
6000
+ children: pill.title
5904
6001
  }) ]
5905
6002
  }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
5906
6003
  children: [ lead,
5907
- /* @__PURE__ */ jsxRuntime.jsx(SetFace, {
5908
- face: face
5909
- }) ]
5910
- });
5911
- }
5912
-
5913
- function AvatarCapAligned({children: children}) {
5914
- const trim = useAvatarCapTrim();
5915
- /* @__PURE__ */
6004
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
6005
+ align: "center",
6006
+ gap: 1,
6007
+ style: {
6008
+ minWidth: 0
6009
+ },
6010
+ children: [
6011
+ /* @__PURE__ */ jsxRuntime.jsx(FaceText, {
6012
+ muted: !0,
6013
+ children: `${pill.title}:`
6014
+ }),
6015
+ /* @__PURE__ */ jsxRuntime.jsx(SetFace, {
6016
+ face: face
6017
+ }) ]
6018
+ }) ]
6019
+ });
6020
+ }
6021
+
6022
+ function AvatarCapAligned({children: children}) {
6023
+ const trim = useAvatarCapTrim();
6024
+ /* @__PURE__ */
5916
6025
  return jsxRuntime.jsx(ui.Flex, {
5917
6026
  align: "center",
5918
6027
  style: {
@@ -5925,7 +6034,7 @@ function AvatarCapAligned({children: children}) {
5925
6034
  }
5926
6035
 
5927
6036
  function AssigneesFace({assignees: assignees}) {
5928
- const userIds = assignees.flatMap(a => a.type === "user" ? [ a.id ] : []), roles = assignees.flatMap(a => a.type === "role" ? [ a.role ] : []);
6037
+ const vocabulary = useProjectMembers(), userIds = assignees.flatMap(a => a.type === "user" ? [ a.id ] : []), roles = assignees.flatMap(a => a.type === "role" ? [ workflowComponents.roleLabelFor(vocabulary, a.role) ] : []);
5929
6038
  /* @__PURE__ */
5930
6039
  return jsxRuntime.jsxs(jsxRuntime.Fragment, {
5931
6040
  children: [ userIds.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(AvatarCapAligned, {
@@ -5958,14 +6067,11 @@ function usePillChrome(face) {
5958
6067
  }
5959
6068
 
5960
6069
  function PillHint({pill: pill, disabled: disabled = !1, children: children}) {
6070
+ const {description: description} = pill;
5961
6071
  /* @__PURE__ */
5962
6072
  return jsxRuntime.jsx(HoverHint, {
5963
- disabled: disabled,
5964
- text: pill.title,
5965
- textWeight: "medium",
5966
- ...pill.description === void 0 ? {} : {
5967
- description: pill.description
5968
- },
6073
+ disabled: disabled || description === void 0,
6074
+ text: description ?? "",
5969
6075
  children: children
5970
6076
  });
5971
6077
  }
@@ -6051,7 +6157,7 @@ function PillPopover({pill: pill, content: content2, open: open, onToggle: onTog
6051
6157
  }
6052
6158
 
6053
6159
  function ReadOnlyPill({pill: pill}) {
6054
- const [open, setOpen] = react.useState(!1), reason = pill.editability?.disabledReason;
6160
+ const [open, setOpen] = react.useState(!1), verdict = pill.editability?.disabledReason, reason = verdict !== void 0 && reasonRestatesInstanceState(verdict) ? void 0 : verdict;
6055
6161
  /* @__PURE__ */
6056
6162
  return jsxRuntime.jsx(PillPopover, {
6057
6163
  content: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
@@ -6234,19 +6340,17 @@ function AssigneePill({entry: entry, pill: pill, editability: editability, surfa
6234
6340
  editability: editability,
6235
6341
  surface: surface
6236
6342
  }), current = pill.entry?._type === "assignee" ? pill.entry.value : null, {pick: pick} = useAssigneePick({
6237
- current: current,
6238
6343
  instanceId: entry.instance._id,
6239
6344
  onSave: set,
6240
6345
  onUnset: unset
6241
6346
  });
6242
6347
  /* @__PURE__ */
6243
6348
  return jsxRuntime.jsx(PillPopover, {
6244
- content: /* @__PURE__ */ jsxRuntime.jsx(AssigneePicker, {
6245
- onChange: next => {
6246
- const changed = changedAssignee(current ? [ current ] : [], next);
6247
- changed && (setOpen(!1), pick(changed));
6248
- },
6249
- value: current ? [ current ] : []
6349
+ content: /* @__PURE__ */ jsxRuntime.jsx(SingleAssigneePicker, {
6350
+ current: current,
6351
+ onPick: picked => {
6352
+ setOpen(!1), pick(picked);
6353
+ }
6250
6354
  }),
6251
6355
  onDismiss: () => setOpen(!1),
6252
6356
  onToggle: () => setOpen(v => !v),
@@ -6375,165 +6479,6 @@ function instanceBreadcrumb(instance, definition) {
6375
6479
  return [ instanceTitle(instance, definition), stageTitle(definition, instance.currentStage) ];
6376
6480
  }
6377
6481
 
6378
- function Hairline({weight: weight, style: style}) {
6379
- const {color: color} = ui.useTheme_v2();
6380
- /* @__PURE__ */
6381
- return jsxRuntime.jsx("div", {
6382
- style: {
6383
- borderTop: `${weight}px solid ${color.border}`,
6384
- ...style
6385
- }
6386
- });
6387
- }
6388
-
6389
- function CollapsibleBand({header: header, children: children, background: background = !1, defaultOpen: defaultOpen = !0, onToggle: onToggle, open: controlledOpen, sticky: sticky = !1, title: title}) {
6390
- const [heldOpen, setHeldOpen] = react.useState(defaultOpen), open = controlledOpen ?? heldOpen, toggle = onToggle ?? (() => setHeldOpen(value => !value)), verb = open ? "Collapse" : "Expand";
6391
- /* @__PURE__ */
6392
- return jsxRuntime.jsxs(ui.Stack, {
6393
- gap: 1,
6394
- children: [
6395
- /* @__PURE__ */ jsxRuntime.jsx(ui.Card, {
6396
- onDoubleClick: event => {
6397
- event.target instanceof Element && event.target.closest("a, button") || toggle();
6398
- },
6399
- padding: 1,
6400
- radius: 3,
6401
- style: {
6402
- userSelect: "none",
6403
- ...sticky ? {
6404
- position: "sticky",
6405
- top: 0,
6406
- zIndex: 1
6407
- } : {}
6408
- },
6409
- tone: background ? "transparent" : "inherit",
6410
- children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
6411
- align: "center",
6412
- children: [
6413
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
6414
- "aria-label": `${verb} ${title}`,
6415
- fontSize: 1,
6416
- icon: open ? ChevronDown.ChevronDownIcon : ChevronRight.ChevronRightIcon,
6417
- mode: "bleed",
6418
- onClick: toggle,
6419
- padding: 2
6420
- }), header ]
6421
- })
6422
- }), open ? children : null ]
6423
- });
6424
- }
6425
-
6426
- function TrailingHairline() {
6427
- /* @__PURE__ */
6428
- return jsxRuntime.jsx(ui.Box, {
6429
- flex: 1,
6430
- paddingLeft: 1,
6431
- paddingRight: 1,
6432
- children: /* @__PURE__ */ jsxRuntime.jsx(Hairline, {
6433
- weight: .5
6434
- })
6435
- });
6436
- }
6437
-
6438
- function InstanceAccordion({entry: entry, children: children, defaultOpen: defaultOpen}) {
6439
- const definition = useDefinition(entry), {instance: instance} = entry, settled = !isLiveEntry(entry), title = instanceTitle(instance, definition), badgeTrim = useBadgeCapTrim();
6440
- /* @__PURE__ */
6441
- return jsxRuntime.jsx(CollapsibleBand, {
6442
- defaultOpen: defaultOpen ?? !settled,
6443
- title: title,
6444
- header: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
6445
- children: [
6446
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
6447
- align: "center",
6448
- gap: 2,
6449
- paddingLeft: 2,
6450
- style: {
6451
- minWidth: 0
6452
- },
6453
- children: [
6454
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
6455
- size: 1,
6456
- style: {
6457
- minWidth: 0
6458
- },
6459
- textOverflow: "ellipsis",
6460
- weight: "medium",
6461
- children: title
6462
- }),
6463
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
6464
- align: "center",
6465
- gap: 2,
6466
- style: badgeTrim,
6467
- children: [
6468
- /* @__PURE__ */ jsxRuntime.jsx(AbortedBadge, {
6469
- instance: instance
6470
- }), settled ? null : /* @__PURE__ */ jsxRuntime.jsx(OlderDefinitionBadge, {
6471
- instance: instance
6472
- }) ]
6473
- }) ]
6474
- }),
6475
- /* @__PURE__ */ jsxRuntime.jsx(TrailingHairline, {}) ]
6476
- }),
6477
- sticky: !0,
6478
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
6479
- paddingBottom: 2,
6480
- paddingLeft: 5,
6481
- children: children
6482
- })
6483
- });
6484
- }
6485
-
6486
- function InstanceToolLink({entry: entry}) {
6487
- const {tools: tools} = sanity.useWorkspace(), instanceId = entry.instance._id, WorkflowIntentLink = react.useMemo(() => function(linkProps) {
6488
- /* @__PURE__ */
6489
- return jsxRuntime.jsx(router.IntentLink, {
6490
- ...linkProps,
6491
- intent: WORKFLOW_INTENT,
6492
- params: {
6493
- instanceId: instanceId
6494
- }
6495
- });
6496
- }, [ instanceId ]);
6497
- return workflowsToolAvailable(tools) ? /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
6498
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
6499
- as: WorkflowIntentLink,
6500
- fontSize: 1,
6501
- mode: "bleed",
6502
- padding: 2,
6503
- text: "View workflow details"
6504
- })
6505
- }) : null;
6506
- }
6507
-
6508
- function PartOfBand({instance: instance}) {
6509
- const parentRef = instance.ancestors.at(-1), parentId = parentRef ? workflowEngine.toBareId(parentRef.id) : null, parentEntry = useWorkflowInstanceEntry(parentId), parentDefinition = useDefinition(parentEntry);
6510
- if (!parentId) return null;
6511
- const title = parentEntry ? instanceTitle(parentEntry.instance, parentDefinition) : parentId;
6512
- /* @__PURE__ */
6513
- return jsxRuntime.jsx(ui.Card, {
6514
- border: !0,
6515
- padding: 3,
6516
- radius: 3,
6517
- tone: "primary",
6518
- children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
6519
- align: "center",
6520
- gap: 2,
6521
- children: [
6522
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
6523
- size: 1,
6524
- children: /* @__PURE__ */ jsxRuntime.jsx(ArrowUp.ArrowUpIcon, {})
6525
- }),
6526
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, {
6527
- size: 1,
6528
- children: [ "Part of ",
6529
- /* @__PURE__ */ jsxRuntime.jsx("strong", {
6530
- children: title
6531
- }) ]
6532
- }) ]
6533
- })
6534
- });
6535
- }
6536
-
6537
6482
  const UNCONDITIONAL_WHENS = /* @__PURE__ */ new Set([ "true", workflowEngine.DEFAULT_TRANSITION_WHEN ]);
6538
6483
 
6539
6484
  function stageRounds(instance) {
@@ -6593,6 +6538,31 @@ function nodeState(args) {
6593
6538
  return args.name === args.instance.currentStage ? "current" : args.visits === 0 ? "upcoming" : args.currentIndex >= 0 && args.index > args.currentIndex ? "revisit" : "done";
6594
6539
  }
6595
6540
 
6541
+ function roundDetail(round) {
6542
+ return round === void 0 ? void 0 : `Round ${round}`;
6543
+ }
6544
+
6545
+ function instanceStageFace(args) {
6546
+ const {definition: definition, instance: instance} = args;
6547
+ if (workflowEngine.isUnprimed(instance)) return;
6548
+ const current = definition === void 0 ? void 0 : deriveSpine({
6549
+ definition: definition,
6550
+ instance: instance
6551
+ }).find(node => node.state === "current");
6552
+ if (current === void 0) return {
6553
+ title: stageTitle(definition, instance.currentStage),
6554
+ completed: workflowEngine.terminalState(instance) === "completed"
6555
+ };
6556
+ const detail = roundDetail(current.round);
6557
+ return {
6558
+ title: current.title,
6559
+ completed: current.completedAt !== void 0,
6560
+ ...detail === void 0 ? {} : {
6561
+ detail: detail
6562
+ }
6563
+ };
6564
+ }
6565
+
6596
6566
  function stageOverview(args) {
6597
6567
  const {definition: definition, node: node, transitions: transitions} = args, stage = definition.stages.find(s => s.name === node.name), advance = node.state === "current" ? advanceHint({
6598
6568
  definition: definition,
@@ -6670,86 +6640,867 @@ function conditionLines(description) {
6670
6640
  });
6671
6641
  }
6672
6642
 
6673
- function StageGlyph(props) {
6643
+ function Hairline({weight: weight, style: style}) {
6644
+ const {color: color} = ui.useTheme_v2();
6645
+ /* @__PURE__ */
6646
+ return jsxRuntime.jsx("div", {
6647
+ style: {
6648
+ borderTop: `${weight}px solid ${color.border}`,
6649
+ ...style
6650
+ }
6651
+ });
6652
+ }
6653
+
6654
+ function StageGlyph(props) {
6655
+ /* @__PURE__ */
6656
+ return jsxRuntime.jsxs("svg", {
6657
+ "data-sanity-icon": "stage",
6658
+ fill: "none",
6659
+ height: "1em",
6660
+ viewBox: "0 0 25 25",
6661
+ width: "1em",
6662
+ xmlns: "http://www.w3.org/2000/svg",
6663
+ ...props,
6664
+ children: [
6665
+ /* @__PURE__ */ jsxRuntime.jsx("path", {
6666
+ d: "M14.7998 12.5C14.7998 11.2295 13.7705 10.2002 12.5 10.2002C11.2295 10.2002 10.2002 11.2295 10.2002 12.5C10.2002 13.7705 11.2295 14.7998 12.5 14.7998V16C10.5668 16 9 14.4332 9 12.5C9 10.5668 10.5668 9 12.5 9C14.4332 9 16 10.5668 16 12.5C16 14.4332 14.4332 16 12.5 16V14.7998C13.7705 14.7998 14.7998 13.7705 14.7998 12.5Z",
6667
+ fill: "currentColor"
6668
+ }),
6669
+ /* @__PURE__ */ jsxRuntime.jsx("path", {
6670
+ d: "M4.5 12.5C4.5 12.1687 4.76863 11.9 5.1 11.9H9.5V13.1H5.1C4.76863 13.1 4.5 12.8314 4.5 12.5V12.5Z",
6671
+ fill: "currentColor"
6672
+ }),
6673
+ /* @__PURE__ */ jsxRuntime.jsx("path", {
6674
+ d: "M15.5 11.9H19.9C20.2314 11.9 20.5 12.1687 20.5 12.5V12.5C20.5 12.8314 20.2314 13.1 19.9 13.1H15.5V11.9Z",
6675
+ fill: "currentColor"
6676
+ }) ]
6677
+ });
6678
+ }
6679
+
6680
+ function StageFace({completed: completed = !1, detail: detail, glyph: glyph = !0, title: title}) {
6681
+ const tone = completed ? "default" : "primary";
6682
+ /* @__PURE__ */
6683
+ return jsxRuntime.jsxs(ui.Flex, {
6684
+ align: "center",
6685
+ as: "span",
6686
+ gap: 2,
6687
+ children: [ glyph ? /* @__PURE__ */ jsxRuntime.jsx(sanity.TextWithTone, {
6688
+ size: 1,
6689
+ tone: tone,
6690
+ children: completed ? /* @__PURE__ */ jsxRuntime.jsx(CheckmarkCircleFilledIcon, {
6691
+ style: {
6692
+ color: "inherit"
6693
+ }
6694
+ }) : /* @__PURE__ */ jsxRuntime.jsx(StageGlyph, {
6695
+ style: {
6696
+ color: "inherit"
6697
+ }
6698
+ })
6699
+ }) : null,
6700
+ /* @__PURE__ */ jsxRuntime.jsx(sanity.TextWithTone, {
6701
+ size: 1,
6702
+ tone: tone,
6703
+ weight: "medium",
6704
+ children: title
6705
+ }), detail === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
6706
+ muted: !0,
6707
+ size: 1,
6708
+ children: detail
6709
+ }) ]
6710
+ });
6711
+ }
6712
+
6713
+ function StageChip({completed: completed = !1, detail: detail, interactive: interactive = !1, title: title}) {
6714
+ const {color: color} = ui.useTheme_v2();
6715
+ /* @__PURE__ */
6716
+ return jsxRuntime.jsx(ui.Card, {
6717
+ padding: 3,
6718
+ radius: 4,
6719
+ style: {
6720
+ boxShadow: `inset 0 0 0 1px ${completed ? color.badge.default.fg : color.focusRing}`,
6721
+ cursor: interactive ? "help" : "default"
6722
+ },
6723
+ tone: completed ? "default" : "primary",
6724
+ ...interactive ? {
6725
+ tabIndex: 0
6726
+ } : {},
6727
+ children: /* @__PURE__ */ jsxRuntime.jsx(StageFace, {
6728
+ completed: completed,
6729
+ title: title,
6730
+ ...detail === void 0 ? {} : {
6731
+ detail: detail
6732
+ }
6733
+ })
6734
+ });
6735
+ }
6736
+
6737
+ function StartIncompleteBadge({style: style}) {
6738
+ /* @__PURE__ */
6739
+ return jsxRuntime.jsx(ui.Badge, {
6740
+ fontSize: 1,
6741
+ mode: "outline",
6742
+ style: style,
6743
+ tone: "caution",
6744
+ children: "Start incomplete"
6745
+ });
6746
+ }
6747
+
6748
+ function normalizeAbortReason(raw) {
6749
+ const trimmed = raw.trim();
6750
+ return trimmed === "" ? void 0 : trimmed;
6751
+ }
6752
+
6753
+ function abortCommitReport(args) {
6754
+ return args.changed ? {
6755
+ outcome: "aborted",
6756
+ toast: abortedToast(args.title)
6757
+ } : {
6758
+ outcome: "already-settled",
6759
+ toast: abortAlreadySettledToast(args.title)
6760
+ };
6761
+ }
6762
+
6763
+ function abortedToast(title) {
6764
+ return {
6765
+ id: TOAST_ID.abort,
6766
+ status: "info",
6767
+ title: `Aborted “${title}”`
6768
+ };
6769
+ }
6770
+
6771
+ function abortAlreadySettledToast(title) {
6772
+ return {
6773
+ id: TOAST_ID.abort,
6774
+ status: "info",
6775
+ title: `“${title}” had already finished`,
6776
+ description: "Nothing was aborted — the workflow reached a terminal state first."
6777
+ };
6778
+ }
6779
+
6780
+ function abortUnconfirmedToast(args) {
6781
+ return {
6782
+ id: TOAST_ID.abort,
6783
+ status: "warning",
6784
+ title: `Couldn’t confirm “${args.title}” was aborted`,
6785
+ description: `${describeError(args.err)} — the abort may still have committed, so check the workflow’s state before trying again.`
6786
+ };
6787
+ }
6788
+
6789
+ function AbortWorkflowDialog({entry: entry, onClose: onClose}) {
6790
+ const {engine: engine} = useWorkflowContext(), definition = useDefinition(entry), toast = useWorkflowToast(), telemetry2 = workflowReact.useWorkflowTelemetry(), [typedReason, setTypedReason] = react.useState(""), [pending, setPending] = react.useState(!1), {instance: instance} = entry, title = instanceTitle(instance, definition), reason = normalizeAbortReason(typedReason), reasonInputId = `abort-workflow-reason-${instance._id}`;
6791
+ useLogEventOnMount(WorkflowAbortDialogOpened, {
6792
+ instanceId: instance._id
6793
+ });
6794
+ const confirm = async () => {
6795
+ if (reason === void 0) return;
6796
+ const log = outcome => telemetry2.log(WorkflowAbortDialogSubmitted, {
6797
+ instanceId: instance._id,
6798
+ outcome: outcome
6799
+ });
6800
+ setPending(!0);
6801
+ try {
6802
+ const {changed: changed} = await engine.abortInstance({
6803
+ instanceId: instance._id,
6804
+ reason: reason
6805
+ }), report = abortCommitReport({
6806
+ title: title,
6807
+ changed: changed
6808
+ });
6809
+ toast.push(report.toast), log(report.outcome), onClose();
6810
+ } catch (err) {
6811
+ toast.push(abortUnconfirmedToast({
6812
+ title: title,
6813
+ err: err
6814
+ })), log("unconfirmed"), setPending(!1);
6815
+ }
6816
+ };
6817
+ /* @__PURE__ */
6818
+ return jsxRuntime.jsx(ui.Dialog, {
6819
+ footer: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
6820
+ padding: 3,
6821
+ children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
6822
+ gap: 2,
6823
+ justify: "flex-end",
6824
+ children: [
6825
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
6826
+ disabled: pending,
6827
+ fontSize: 1,
6828
+ mode: "bleed",
6829
+ onClick: onClose,
6830
+ padding: 2,
6831
+ text: "Cancel"
6832
+ }),
6833
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
6834
+ disabled: reason === void 0,
6835
+ fontSize: 1,
6836
+ loading: pending,
6837
+ onClick: () => {
6838
+ confirm();
6839
+ },
6840
+ padding: 2,
6841
+ text: "Abort workflow",
6842
+ tone: "critical"
6843
+ }) ]
6844
+ })
6845
+ }),
6846
+ header: "Abort workflow",
6847
+ id: `abort-workflow-${instance._id}`,
6848
+ onClose: () => {
6849
+ pending || onClose();
6850
+ },
6851
+ width: 0,
6852
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
6853
+ padding: 4,
6854
+ children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
6855
+ gap: 5,
6856
+ children: [
6857
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, {
6858
+ size: 1,
6859
+ children: [ "Abort the ",
6860
+ /* @__PURE__ */ jsxRuntime.jsx("strong", {
6861
+ children: title
6862
+ }), " workflow? This cannot be undone." ]
6863
+ }),
6864
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
6865
+ gap: 3,
6866
+ children: [
6867
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
6868
+ as: "label",
6869
+ htmlFor: reasonInputId,
6870
+ size: 1,
6871
+ weight: "medium",
6872
+ children: "Reason"
6873
+ }),
6874
+ /* @__PURE__ */ jsxRuntime.jsx(ui.TextInput, {
6875
+ autoFocus: !0,
6876
+ fontSize: 1,
6877
+ id: reasonInputId,
6878
+ onChange: event => setTypedReason(event.currentTarget.value),
6879
+ placeholder: "Why is this workflow being stopped?",
6880
+ value: typedReason
6881
+ }) ]
6882
+ }) ]
6883
+ })
6884
+ })
6885
+ });
6886
+ }
6887
+
6888
+ function makeTitleResolver(definition) {
6889
+ const activities = (definition?.stages ?? []).flatMap(s => s.activities ?? []);
6890
+ return {
6891
+ action: (activityName, actionName) => activities.find(t => t.name === activityName)?.actions?.find(a => a.name === actionName)?.title ?? actionName,
6892
+ activity: name => activities.find(t => t.name === name)?.title ?? name,
6893
+ stage: name => stageTitle(definition, name)
6894
+ };
6895
+ }
6896
+
6897
+ function attributed(actor, ...parts) {
6898
+ if (actor) return {
6899
+ actorId: actor.id,
6900
+ parts: parts
6901
+ };
6902
+ const [first, ...rest] = parts;
6903
+ return typeof first != "string" ? {
6904
+ actorId: void 0,
6905
+ parts: parts
6906
+ } : {
6907
+ actorId: void 0,
6908
+ parts: [ first.charAt(0).toUpperCase() + first.slice(1), ...rest ]
6909
+ };
6910
+ }
6911
+
6912
+ function standalone(...parts) {
6913
+ return {
6914
+ actorId: void 0,
6915
+ parts: parts
6916
+ };
6917
+ }
6918
+
6919
+ const historyLiner = {
6920
+ stageEntered: (h, titles) => attributed(h.actor, `entered ${titles.stage(h.stage)}${h.fromStage ? ` from ${titles.stage(h.fromStage)}` : ""}`),
6921
+ stageExited: (h, titles) => attributed(h.actor, `left ${titles.stage(h.stage)} for ${titles.stage(h.toStage)}`),
6922
+ activityStatusChanged: (h, titles) => attributed(h.actor, `changed ${titles.activity(h.activity)}: ${h.from} → ${h.to}`),
6923
+ actionFired: (h, titles) => {
6924
+ const phrase = `fired ${titles.action(h.activity, h.action)} on ${titles.activity(h.activity)}`;
6925
+ return h.triggered ? standalone(`The workflow ${phrase}`) : attributed(h.actor, phrase);
6926
+ },
6927
+ transitionFired: (h, titles) => attributed(h.actor, `moved ${titles.stage(h.fromStage)} → ${titles.stage(h.toStage)}`),
6928
+ effectQueued: h => standalone("Effect ", {
6929
+ code: h.effect
6930
+ }, " queued"),
6931
+ effectCompleted: h => {
6932
+ const detail = h.detail ? ` — ${h.detail}` : "";
6933
+ return h.actor ? attributed(h.actor, "resolved effect ", {
6934
+ code: h.effect
6935
+ }, ` — ${h.status}${detail}`) : standalone("Effect ", {
6936
+ code: h.effect
6937
+ }, ` ${h.status}${detail}`);
6938
+ },
6939
+ effectClaimReleased: h => attributed(h.actor, "released a stale claim on effect ", {
6940
+ code: h.effect
6941
+ }, ` ${h.via === "sweep" ? "via the sweeper" : "via a drain takeover"}`),
6942
+ spawned: (h, titles) => attributed(h.actor, `spawned a child workflow from ${titles.activity(h.activity)}`),
6943
+ subworkflowAdopted: (h, titles) => standalone(`Re-adopted child workflow into ${titles.activity(h.activity)} on re-entering ${titles.stage(h.stage)}`),
6944
+ subworkflowResolved: (h, titles) => standalone(`Child workflow of ${titles.activity(h.activity)} ${h.status === "done" ? "completed" : "was aborted"}`),
6945
+ subworkflowOrphaned: h => standalone(`Orphaned child workflow reached terminal — ${h.detail}`),
6946
+ aborted: (h, titles) => attributed(h.actor, `aborted the workflow at ${titles.stage(h.stage)}${h.reason ? ` — ${h.reason}` : ""}`),
6947
+ 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 ", {
6948
+ code: h.opType
6949
+ }),
6950
+ fieldQueryDiscarded: h => standalone({
6951
+ code: JSON.stringify(h)
6952
+ })
6953
+ };
6954
+
6955
+ function historyLine(h, titles) {
6956
+ return historyLiner[h._type](h, titles);
6957
+ }
6958
+
6959
+ function CodeChip({value: value}) {
6960
+ /* @__PURE__ */
6961
+ return jsxRuntime.jsx("code", {
6962
+ style: {
6963
+ overflowWrap: "anywhere"
6964
+ },
6965
+ children: value
6966
+ });
6967
+ }
6968
+
6969
+ function HintedMenuButton({hint: hint, ...menuButtonProps}) {
6970
+ const [open, setOpen] = react.useState(!1), popover = {
6971
+ tone: "default",
6972
+ ...menuButtonProps.popover?.placement === void 0 ? {
6973
+ placement: "bottom-end",
6974
+ fallbackPlacements: [ "top-end" ]
6975
+ } : {},
6976
+ ...menuButtonProps.popover
6977
+ };
6978
+ return hint === void 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.MenuButton, {
6979
+ ...menuButtonProps,
6980
+ popover: popover
6981
+ }) : /* @__PURE__ */ jsxRuntime.jsx(HoverHint, {
6982
+ disabled: open,
6983
+ text: hint,
6984
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.MenuButton, {
6985
+ ...menuButtonProps,
6986
+ onClose: () => setOpen(!1),
6987
+ onOpen: () => setOpen(!0),
6988
+ popover: popover
6989
+ })
6990
+ });
6991
+ }
6992
+
6993
+ function historyWindow(args) {
6994
+ const {entries: entries, expanded: expanded} = args;
6995
+ return {
6996
+ overflows: entries.length > 6,
6997
+ shown: expanded ? entries : entries.slice(0, 6)
6998
+ };
6999
+ }
7000
+
7001
+ function PendingEffectRows({instance: instance, now: now}) {
7002
+ const {drainEffectsFor: drainEffectsFor, completeEffectFor: completeEffectFor, effectHandlers: effectHandlers} = useWorkflowContext(), toast = useWorkflowToast(), [busy, setBusy] = react.useState(!1), pending = instance.pendingEffects ?? [];
7003
+ if (pending.length === 0) return null;
7004
+ const runRegistered = async () => {
7005
+ setBusy(!0);
7006
+ try {
7007
+ await drainEffectsFor(instance._id), toast.push({
7008
+ id: TOAST_ID.effectsDrain,
7009
+ status: "info",
7010
+ title: "Ran the registered handlers"
7011
+ });
7012
+ } catch (err) {
7013
+ toast.push({
7014
+ id: TOAST_ID.effectsDrain,
7015
+ status: "error",
7016
+ title: "Failed to run pending effects",
7017
+ description: describeError(err)
7018
+ });
7019
+ } finally {
7020
+ setBusy(!1);
7021
+ }
7022
+ }, resolve = async (effectKey, status) => {
7023
+ setBusy(!0);
7024
+ try {
7025
+ await completeEffectFor(instance._id, {
7026
+ effectKey: effectKey,
7027
+ status: status,
7028
+ detail: "Resolved in Studio"
7029
+ }), toast.push({
7030
+ id: TOAST_ID.effectResolve,
7031
+ status: "info",
7032
+ title: `Effect marked as ${status}`
7033
+ });
7034
+ } catch (err) {
7035
+ toast.push({
7036
+ id: TOAST_ID.effectResolve,
7037
+ status: "error",
7038
+ title: "Failed to resolve the effect",
7039
+ description: describeError(err)
7040
+ });
7041
+ } finally {
7042
+ setBusy(!1);
7043
+ }
7044
+ };
7045
+ /* @__PURE__ */
7046
+ return jsxRuntime.jsx(jsxRuntime.Fragment, {
7047
+ children: pending.map(fx => /* @__PURE__ */ jsxRuntime.jsx(PendingEffectRow, {
7048
+ busy: busy,
7049
+ effect: fx,
7050
+ instanceId: instance._id,
7051
+ now: now,
7052
+ onResolve: status => resolve(fx._key, status),
7053
+ onRunHandlers: runRegistered,
7054
+ registered: fx.name in effectHandlers
7055
+ }, fx._key))
7056
+ });
7057
+ }
7058
+
7059
+ function PendingEffectRow({busy: busy, effect: effect, instanceId: instanceId, now: now, onResolve: onResolve, onRunHandlers: onRunHandlers, registered: registered}) {
7060
+ const label = effect.title ?? effect.name, avatarSize = useAvatarSize();
7061
+ /* @__PURE__ */
7062
+ return jsxRuntime.jsxs(ui.Flex, {
7063
+ align: "center",
7064
+ gap: 2,
7065
+ children: [
7066
+ /* @__PURE__ */ jsxRuntime.jsx(FeedGlyph, {
7067
+ hint: "Waiting to run",
7068
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Clock.ClockIcon, {})
7069
+ }),
7070
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
7071
+ align: "center",
7072
+ flex: 1,
7073
+ gap: 1,
7074
+ style: {
7075
+ minWidth: 0
7076
+ },
7077
+ children: [
7078
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
7079
+ style: {
7080
+ minWidth: 0
7081
+ },
7082
+ children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, {
7083
+ size: 1,
7084
+ textOverflow: "ellipsis",
7085
+ children: [ effect.title ?? /* @__PURE__ */ jsxRuntime.jsx(CodeChip, {
7086
+ value: effect.name
7087
+ }), registered ? " — ready to run in Studio" : " — waiting for the runtime" ]
7088
+ })
7089
+ }),
7090
+ /* @__PURE__ */ jsxRuntime.jsx(FeedStamp, {
7091
+ at: effect.queuedAt,
7092
+ now: now
7093
+ }) ]
7094
+ }),
7095
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
7096
+ align: "center",
7097
+ flex: "none",
7098
+ style: {
7099
+ height: avatarSize
7100
+ },
7101
+ children: /* @__PURE__ */ jsxRuntime.jsx(HintedMenuButton, {
7102
+ button: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
7103
+ "aria-label": `Resolve ${label}`,
7104
+ disabled: busy,
7105
+ fontSize: 1,
7106
+ icon: EllipsisHorizontal.EllipsisHorizontalIcon,
7107
+ mode: "bleed",
7108
+ padding: 2
7109
+ }),
7110
+ hint: "Resolve",
7111
+ id: `pending-effect-menu-${instanceId}-${effect._key}`,
7112
+ menu: /* @__PURE__ */ jsxRuntime.jsxs(ui.Menu, {
7113
+ children: [ registered ? /* @__PURE__ */ jsxRuntime.jsx(ui.MenuItem, {
7114
+ onClick: onRunHandlers,
7115
+ text: "Run registered handlers"
7116
+ }) : null,
7117
+ /* @__PURE__ */ jsxRuntime.jsx(ui.MenuItem, {
7118
+ onClick: () => onResolve("done"),
7119
+ text: "Mark done"
7120
+ }),
7121
+ /* @__PURE__ */ jsxRuntime.jsx(ui.MenuItem, {
7122
+ onClick: () => onResolve("failed"),
7123
+ text: "Mark failed",
7124
+ tone: "critical"
7125
+ }) ]
7126
+ }),
7127
+ popover: {
7128
+ placement: "bottom-end",
7129
+ portal: !0
7130
+ }
7131
+ })
7132
+ }) ]
7133
+ });
7134
+ }
7135
+
7136
+ function ActivityLog({instance: instance, definition: definition, windowed: windowed = !0}) {
7137
+ const titles = react.useMemo(() => makeTitleResolver(definition), [ definition ]), entries = react.useMemo(() => instance.history.toReversed(), [ instance.history ]), [now, setNow] = react.useState(() => /* @__PURE__ */ new Date), [expanded, setExpanded] = react.useState(!1);
7138
+ react.useEffect(() => {
7139
+ const timer = setInterval(() => setNow(/* @__PURE__ */ new Date), 6e4);
7140
+ return () => clearInterval(timer);
7141
+ }, []);
7142
+ const history = historyWindow({
7143
+ entries: entries,
7144
+ expanded: expanded || !windowed
7145
+ });
7146
+ return entries.length === 0 && (instance.pendingEffects ?? []).length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
7147
+ muted: !0,
7148
+ size: 1,
7149
+ children: "No activity yet"
7150
+ }) : /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
7151
+ gap: 3,
7152
+ children: [
7153
+ /* @__PURE__ */ jsxRuntime.jsx(PendingEffectRows, {
7154
+ instance: instance,
7155
+ now: now
7156
+ }), history.shown.map(h => /* @__PURE__ */ jsxRuntime.jsx(HistoryRow, {
7157
+ entry: h,
7158
+ now: now,
7159
+ titles: titles
7160
+ }, h._key)), windowed && history.overflows ? /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
7161
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
7162
+ fontSize: 1,
7163
+ mode: "bleed",
7164
+ onClick: () => setExpanded(!expanded),
7165
+ padding: 2,
7166
+ text: expanded ? "Show less history" : "Show all history"
7167
+ })
7168
+ }) : null ]
7169
+ });
7170
+ }
7171
+
7172
+ function FeedStamp({at: at, now: now}) {
7173
+ /* @__PURE__ */
7174
+ return jsxRuntime.jsxs(ui.Flex, {
7175
+ align: "center",
7176
+ flex: "none",
7177
+ gap: 1,
7178
+ children: [
7179
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
7180
+ muted: !0,
7181
+ size: 1,
7182
+ children: "·"
7183
+ }),
7184
+ /* @__PURE__ */ jsxRuntime.jsx(HoverHint, {
7185
+ text: formatDateTime(at),
7186
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
7187
+ muted: !0,
7188
+ size: 1,
7189
+ style: {
7190
+ whiteSpace: "nowrap"
7191
+ },
7192
+ children: formatShortAgo(at, now)
7193
+ })
7194
+ }) ]
7195
+ });
7196
+ }
7197
+
7198
+ function HistoryRow({entry: entry, now: now, titles: titles}) {
7199
+ const line = historyLine(entry, titles);
7200
+ /* @__PURE__ */
7201
+ return jsxRuntime.jsxs(ui.Flex, {
7202
+ align: "center",
7203
+ gap: 2,
7204
+ children: [ line.actorId === void 0 ? /* @__PURE__ */ jsxRuntime.jsx(FeedGlyph, {
7205
+ hint: "The workflow",
7206
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Cog.CogIcon, {})
7207
+ }) : /* @__PURE__ */ jsxRuntime.jsx(UserAvatar, {
7208
+ id: line.actorId
7209
+ }),
7210
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
7211
+ align: "center",
7212
+ flex: 1,
7213
+ gap: 1,
7214
+ style: {
7215
+ minWidth: 0
7216
+ },
7217
+ children: [
7218
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
7219
+ style: {
7220
+ minWidth: 0
7221
+ },
7222
+ children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, {
7223
+ muted: !0,
7224
+ size: 1,
7225
+ textOverflow: "ellipsis",
7226
+ children: [ line.actorId === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
7227
+ children: [
7228
+ /* @__PURE__ */ jsxRuntime.jsx(ActorNameSpan, {
7229
+ id: line.actorId
7230
+ }), " " ]
7231
+ }), line.parts.map((part, index) => typeof part == "string" ? part : /* @__PURE__ */ jsxRuntime.jsx(CodeChip, {
7232
+ value: part.code
7233
+ }, index)) ]
7234
+ })
7235
+ }),
7236
+ /* @__PURE__ */ jsxRuntime.jsx(FeedStamp, {
7237
+ at: entry.at,
7238
+ now: now
7239
+ }) ]
7240
+ }) ]
7241
+ });
7242
+ }
7243
+
7244
+ function ActorNameSpan({id: id}) {
7245
+ const {name: name} = useUserDisplay(id), {font: font} = ui.useTheme_v2();
7246
+ /* @__PURE__ */
7247
+ return jsxRuntime.jsx("span", {
7248
+ style: {
7249
+ fontWeight: font.text.weights.medium
7250
+ },
7251
+ children: name
7252
+ });
7253
+ }
7254
+
7255
+ function FeedGlyph({hint: hint, icon: icon}) {
7256
+ const size = useAvatarSize();
7257
+ /* @__PURE__ */
7258
+ return jsxRuntime.jsx(HoverHint, {
7259
+ text: hint,
7260
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
7261
+ align: "center",
7262
+ flex: "none",
7263
+ justify: "center",
7264
+ style: {
7265
+ height: size,
7266
+ width: size
7267
+ },
7268
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
7269
+ muted: !0,
7270
+ size: 1,
7271
+ children: icon
7272
+ })
7273
+ })
7274
+ });
7275
+ }
7276
+
7277
+ function InstanceHistoryDialog({entry: entry, onClose: onClose}) {
7278
+ const definition = useDefinition(entry), {instance: instance} = entry;
7279
+ /* @__PURE__ */
7280
+ return jsxRuntime.jsx(ui.Dialog, {
7281
+ header: /* @__PURE__ */ jsxRuntime.jsx(Breadcrumb, {
7282
+ emphasizeCurrent: !0,
7283
+ segments: [ instanceTitle(instance, definition), "History" ]
7284
+ }),
7285
+ id: `workflow-instance-history-${instance._id}`,
7286
+ onClose: onClose,
7287
+ width: 1,
7288
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
7289
+ padding: 4,
7290
+ children: /* @__PURE__ */ jsxRuntime.jsx(ActivityLog, {
7291
+ definition: definition,
7292
+ instance: instance,
7293
+ windowed: !1
7294
+ })
7295
+ })
7296
+ });
7297
+ }
7298
+
7299
+ function InstanceCardMenu({entry: entry, title: title}) {
7300
+ const [dialog, setDialog] = react.useState(void 0), menuId = react.useId(), close = () => setDialog(void 0);
7301
+ /* @__PURE__ */
7302
+ return jsxRuntime.jsxs(jsxRuntime.Fragment, {
7303
+ children: [
7304
+ /* @__PURE__ */ jsxRuntime.jsx(ui.MenuButton, {
7305
+ button:
7306
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
7307
+ "aria-label": `More options for ${title}`,
7308
+ fontSize: 1,
7309
+ icon: EllipsisHorizontal.EllipsisHorizontalIcon,
7310
+ mode: "bleed",
7311
+ padding: 2
7312
+ }),
7313
+ id: `workflow-instance-menu-${menuId}`,
7314
+ menu: /* @__PURE__ */ jsxRuntime.jsxs(ui.Menu, {
7315
+ children: [
7316
+ /* @__PURE__ */ jsxRuntime.jsx(ui.MenuItem, {
7317
+ onClick: () => setDialog("history"),
7318
+ text: "Workflow history"
7319
+ }), isLiveEntry(entry) ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
7320
+ children: [
7321
+ /* @__PURE__ */ jsxRuntime.jsx(ui.MenuDivider, {}),
7322
+ /* @__PURE__ */ jsxRuntime.jsx(ui.MenuItem, {
7323
+ onClick: () => setDialog("abort"),
7324
+ text: "Abort workflow…",
7325
+ tone: "critical"
7326
+ }) ]
7327
+ }) : null ]
7328
+ }),
7329
+ popover: {
7330
+ placement: "bottom-end",
7331
+ portal: !0
7332
+ }
7333
+ }), dialog === "history" ? /* @__PURE__ */ jsxRuntime.jsx(InstanceHistoryDialog, {
7334
+ entry: entry,
7335
+ onClose: close
7336
+ }) : null, dialog === "abort" ? /* @__PURE__ */ jsxRuntime.jsx(AbortWorkflowDialog, {
7337
+ entry: entry,
7338
+ onClose: close
7339
+ }) : null ]
7340
+ });
7341
+ }
7342
+
7343
+ function InstanceCard({entry: entry, children: children, defaultOpen: defaultOpen}) {
7344
+ const definition = useDefinition(entry), {instance: instance} = entry, settled = !isLiveEntry(entry), [open, setOpen] = react.useState(defaultOpen ?? !settled), title = instanceTitle(instance, definition), menuSlot = useSpaceToken(2) * 2 + useTextIconSize();
6674
7345
  /* @__PURE__ */
6675
- return jsxRuntime.jsxs("svg", {
6676
- "data-sanity-icon": "stage",
6677
- fill: "none",
6678
- height: "1em",
6679
- viewBox: "0 0 25 25",
6680
- width: "1em",
6681
- xmlns: "http://www.w3.org/2000/svg",
6682
- ...props,
7346
+ return jsxRuntime.jsxs(ui.Card, {
7347
+ border: !0,
7348
+ overflow: "hidden",
7349
+ radius: 4,
6683
7350
  children: [
6684
- /* @__PURE__ */ jsxRuntime.jsx("path", {
6685
- d: "M14.7998 12.5C14.7998 11.2295 13.7705 10.2002 12.5 10.2002C11.2295 10.2002 10.2002 11.2295 10.2002 12.5C10.2002 13.7705 11.2295 14.7998 12.5 14.7998V16C10.5668 16 9 14.4332 9 12.5C9 10.5668 10.5668 9 12.5 9C14.4332 9 16 10.5668 16 12.5C16 14.4332 14.4332 16 12.5 16V14.7998C13.7705 14.7998 14.7998 13.7705 14.7998 12.5Z",
6686
- fill: "currentColor"
6687
- }),
6688
- /* @__PURE__ */ jsxRuntime.jsx("path", {
6689
- d: "M4.5 12.5C4.5 12.1687 4.76863 11.9 5.1 11.9H9.5V13.1H5.1C4.76863 13.1 4.5 12.8314 4.5 12.5V12.5Z",
6690
- fill: "currentColor"
6691
- }),
6692
- /* @__PURE__ */ jsxRuntime.jsx("path", {
6693
- d: "M15.5 11.9H19.9C20.2314 11.9 20.5 12.1687 20.5 12.5V12.5C20.5 12.8314 20.2314 13.1 19.9 13.1H15.5V11.9Z",
6694
- fill: "currentColor"
6695
- }) ]
7351
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Box, {
7352
+ style: {
7353
+ position: "relative"
7354
+ },
7355
+ children: [
7356
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Card, {
7357
+ "aria-expanded": open,
7358
+ as: "button",
7359
+ onClick: () => setOpen(value => !value),
7360
+ padding: 3,
7361
+ style: {
7362
+ display: "block",
7363
+ textAlign: "left",
7364
+ width: "100%"
7365
+ },
7366
+ ...open ? {
7367
+ tone: "transparent"
7368
+ } : {},
7369
+ children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
7370
+ align: "center",
7371
+ gap: 3,
7372
+ children: [
7373
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
7374
+ muted: !0,
7375
+ size: 1,
7376
+ children: open ? /* @__PURE__ */ jsxRuntime.jsx(ChevronDown.ChevronDownIcon, {}) : /* @__PURE__ */ jsxRuntime.jsx(ChevronRight.ChevronRightIcon, {})
7377
+ }),
7378
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
7379
+ flex: 1,
7380
+ gap: 2,
7381
+ style: {
7382
+ minWidth: 0
7383
+ },
7384
+ children: [
7385
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
7386
+ size: 1,
7387
+ textOverflow: "ellipsis",
7388
+ weight: "medium",
7389
+ children: title
7390
+ }),
7391
+ /* @__PURE__ */ jsxRuntime.jsx(HeaderStage, {
7392
+ entry: entry
7393
+ }) ]
7394
+ }),
7395
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
7396
+ align: "center",
7397
+ flex: "none",
7398
+ children: [
7399
+ /* @__PURE__ */ jsxRuntime.jsx(HeaderBadges, {
7400
+ instance: instance,
7401
+ settled: settled
7402
+ }),
7403
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
7404
+ flex: "none",
7405
+ style: {
7406
+ width: menuSlot
7407
+ }
7408
+ }) ]
7409
+ }) ]
7410
+ })
7411
+ }),
7412
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
7413
+ align: "center",
7414
+ style: {
7415
+ bottom: 0,
7416
+ position: "absolute",
7417
+ right: 0,
7418
+ top: 0
7419
+ },
7420
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
7421
+ paddingRight: 3,
7422
+ children: /* @__PURE__ */ jsxRuntime.jsx(InstanceCardMenu, {
7423
+ entry: entry,
7424
+ title: title
7425
+ })
7426
+ })
7427
+ }) ]
7428
+ }), open ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
7429
+ children: [
7430
+ /* @__PURE__ */ jsxRuntime.jsx(Hairline, {
7431
+ weight: 1
7432
+ }),
7433
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
7434
+ padding: 3,
7435
+ children: children
7436
+ }) ]
7437
+ }) : null ]
6696
7438
  });
6697
7439
  }
6698
7440
 
6699
- function StageFace({completed: completed = !1, detail: detail, title: title}) {
6700
- const tone = completed ? "default" : "primary";
7441
+ function HeaderStage({entry: entry}) {
7442
+ const definition = useDefinition(entry), badgeTrim = useBadgeCapTrim(), face = instanceStageFace({
7443
+ definition: definition,
7444
+ instance: entry.instance
7445
+ });
7446
+ /* @__PURE__ */
7447
+ return jsxRuntime.jsx(ui.Flex, {
7448
+ align: "center",
7449
+ children: face === void 0 ? /* @__PURE__ */ jsxRuntime.jsx(StartIncompleteBadge, {
7450
+ style: badgeTrim
7451
+ }) : /* @__PURE__ */ jsxRuntime.jsx(StageFace, {
7452
+ ...face.detail === void 0 ? {} : {
7453
+ detail: face.detail
7454
+ },
7455
+ completed: face.completed,
7456
+ glyph: !1,
7457
+ title: face.title
7458
+ })
7459
+ });
7460
+ }
7461
+
7462
+ function HeaderBadges({instance: instance, settled: settled}) {
7463
+ const badgeTrim = useBadgeCapTrim();
6701
7464
  /* @__PURE__ */
6702
7465
  return jsxRuntime.jsxs(ui.Flex, {
6703
7466
  align: "center",
6704
- as: "span",
7467
+ flex: "none",
6705
7468
  gap: 2,
7469
+ style: badgeTrim,
6706
7470
  children: [
6707
- /* @__PURE__ */ jsxRuntime.jsx(sanity.TextWithTone, {
6708
- size: 1,
6709
- tone: tone,
6710
- children: completed ? /* @__PURE__ */ jsxRuntime.jsx(CheckmarkCircleFilledIcon, {
6711
- style: {
6712
- color: "inherit"
6713
- }
6714
- }) : /* @__PURE__ */ jsxRuntime.jsx(StageGlyph, {
6715
- style: {
6716
- color: "inherit"
6717
- }
6718
- })
6719
- }),
6720
- /* @__PURE__ */ jsxRuntime.jsx(sanity.TextWithTone, {
6721
- size: 1,
6722
- tone: tone,
6723
- weight: "medium",
6724
- children: title
6725
- }), detail === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
6726
- muted: !0,
6727
- size: 1,
6728
- children: detail
7471
+ /* @__PURE__ */ jsxRuntime.jsx(AbortedBadge, {
7472
+ instance: instance
7473
+ }), settled ? null : /* @__PURE__ */ jsxRuntime.jsx(OlderDefinitionBadge, {
7474
+ instance: instance
6729
7475
  }) ]
6730
7476
  });
6731
7477
  }
6732
7478
 
6733
- function StageChip({completed: completed = !1, detail: detail, interactive: interactive = !1, title: title}) {
6734
- const {color: color} = ui.useTheme_v2();
7479
+ function PartOfBand({instance: instance}) {
7480
+ const parentRef = instance.ancestors.at(-1), parentId = parentRef ? workflowEngine.toBareId(parentRef.id) : null, parentEntry = useWorkflowInstanceEntry(parentId), parentDefinition = useDefinition(parentEntry);
7481
+ if (!parentId) return null;
7482
+ const title = parentEntry ? instanceTitle(parentEntry.instance, parentDefinition) : parentId;
6735
7483
  /* @__PURE__ */
6736
7484
  return jsxRuntime.jsx(ui.Card, {
7485
+ border: !0,
6737
7486
  padding: 3,
6738
- radius: 4,
6739
- style: {
6740
- boxShadow: `inset 0 0 0 1px ${completed ? color.badge.default.fg : color.focusRing}`,
6741
- cursor: interactive ? "help" : "default"
6742
- },
6743
- tone: completed ? "default" : "primary",
6744
- ...interactive ? {
6745
- tabIndex: 0
6746
- } : {},
6747
- children: /* @__PURE__ */ jsxRuntime.jsx(StageFace, {
6748
- completed: completed,
6749
- title: title,
6750
- ...detail === void 0 ? {} : {
6751
- detail: detail
6752
- }
7487
+ radius: 3,
7488
+ tone: "primary",
7489
+ children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
7490
+ align: "center",
7491
+ gap: 2,
7492
+ children: [
7493
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
7494
+ size: 1,
7495
+ children: /* @__PURE__ */ jsxRuntime.jsx(ArrowUp.ArrowUpIcon, {})
7496
+ }),
7497
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, {
7498
+ size: 1,
7499
+ children: [ "Part of ",
7500
+ /* @__PURE__ */ jsxRuntime.jsx("strong", {
7501
+ children: title
7502
+ }) ]
7503
+ }) ]
6753
7504
  })
6754
7505
  });
6755
7506
  }
@@ -6796,20 +7547,23 @@ function SpineNodeView({definition: definition, node: node, transitions: transit
6796
7547
  transitions: transitions
6797
7548
  })
6798
7549
  });
6799
- if (node.state === "current") /* @__PURE__ */
6800
- return jsxRuntime.jsx(HoverHint, {
6801
- content: card,
6802
- "data-testid": `spine-node-${node.name}`,
6803
- flush: !0,
6804
- children: /* @__PURE__ */ jsxRuntime.jsx(StageChip, {
6805
- ...node.round === void 0 ? {} : {
6806
- detail: `Round ${node.round}`
6807
- },
6808
- completed: node.completedAt !== void 0,
6809
- interactive: !0,
6810
- title: node.title
6811
- })
6812
- });
7550
+ if (node.state === "current") {
7551
+ const detail = roundDetail(node.round);
7552
+ /* @__PURE__ */
7553
+ return jsxRuntime.jsx(HoverHint, {
7554
+ content: card,
7555
+ "data-testid": `spine-node-${node.name}`,
7556
+ flush: !0,
7557
+ children: /* @__PURE__ */ jsxRuntime.jsx(StageChip, {
7558
+ ...detail === void 0 ? {} : {
7559
+ detail: detail
7560
+ },
7561
+ completed: node.completedAt !== void 0,
7562
+ interactive: !0,
7563
+ title: node.title
7564
+ })
7565
+ });
7566
+ }
6813
7567
  const Icon = NODE_ICON[node.state];
6814
7568
  /* @__PURE__ */
6815
7569
  return jsxRuntime.jsx(HoverHint, {
@@ -6960,20 +7714,13 @@ function StampLines({stamp: stamp}) {
6960
7714
 
6961
7715
  function WorkflowInstanceSection({defaultOpen: defaultOpen, entry: entry, onOpenActivity: onOpenActivity}) {
6962
7716
  /* @__PURE__ */
6963
- return jsxRuntime.jsx(InstanceAccordion, {
7717
+ return jsxRuntime.jsx(InstanceCard, {
6964
7718
  defaultOpen: defaultOpen,
6965
7719
  entry: entry,
6966
- children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
6967
- gap: 3,
6968
- children: [
6969
- /* @__PURE__ */ jsxRuntime.jsx(InstanceSnapshotBody, {
6970
- entry: entry,
6971
- onOpenActivity: onOpenActivity,
6972
- surface: "document-view"
6973
- }),
6974
- /* @__PURE__ */ jsxRuntime.jsx(InstanceToolLink, {
6975
- entry: entry
6976
- }) ]
7720
+ children: /* @__PURE__ */ jsxRuntime.jsx(InstanceSnapshotBody, {
7721
+ entry: entry,
7722
+ onOpenActivity: onOpenActivity,
7723
+ surface: "document-view"
6977
7724
  })
6978
7725
  });
6979
7726
  }
@@ -7000,7 +7747,9 @@ function InstanceSnapshotBody({entry: entry, onOpenActivity: onOpenActivity, sur
7000
7747
  /* @__PURE__ */ jsxRuntime.jsx(ui.Card, {
7001
7748
  borderBottom: !0,
7002
7749
  padding: 2,
7003
- tone: definition ? "neutral" : "caution",
7750
+ ...definition ? {} : {
7751
+ tone: "caution"
7752
+ },
7004
7753
  children: definition ? /* @__PURE__ */ jsxRuntime.jsx(WorkflowSpine, {
7005
7754
  definition: definition,
7006
7755
  evaluation: entry.evaluation,
@@ -7045,18 +7794,23 @@ function StageSection({entry: entry, onOpenActivity: onOpenActivity, surface: su
7045
7794
  });
7046
7795
  }
7047
7796
 
7048
- function CautionNote({action: action, label: label}) {
7797
+ const BANNER_PADDING = 3, ICONS = {
7798
+ caution: /* @__PURE__ */ jsxRuntime.jsx(WarningOutline.WarningOutlineIcon, {}),
7799
+ critical: /* @__PURE__ */ jsxRuntime.jsx(ErrorOutline.ErrorOutlineIcon, {})
7800
+ };
7801
+
7802
+ function NoteBanner({action: action, label: label, tone: tone = "caution"}) {
7049
7803
  /* @__PURE__ */
7050
7804
  return jsxRuntime.jsxs(ui.Card, {
7051
7805
  paddingLeft: 3,
7052
7806
  paddingRight: 2,
7053
- paddingY: 3,
7807
+ paddingY: BANNER_PADDING,
7054
7808
  radius: 3,
7055
7809
  style: {
7056
7810
  alignItems: "center",
7057
7811
  display: "flex"
7058
7812
  },
7059
- tone: "caution",
7813
+ tone: tone,
7060
7814
  children: [
7061
7815
  /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
7062
7816
  align: "center",
@@ -7066,7 +7820,7 @@ function CautionNote({action: action, label: label}) {
7066
7820
  /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
7067
7821
  muted: !0,
7068
7822
  size: 1,
7069
- children: /* @__PURE__ */ jsxRuntime.jsx(WarningOutline.WarningOutlineIcon, {})
7823
+ children: ICONS[tone]
7070
7824
  }),
7071
7825
  /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
7072
7826
  muted: !0,
@@ -7103,7 +7857,7 @@ function UnreadableDocsNote({unreadable: unreadable}) {
7103
7857
  if (unreadable.length === 0) return null;
7104
7858
  const label = unreadable.length === 1 ? "1 workflow document isn’t listed — this Studio can’t read it. Share the details with your Studio maintainers." : `${unreadable.length} workflow documents aren’t listed — this Studio can’t read them. Share the details with your Studio maintainers.`;
7105
7859
  /* @__PURE__ */
7106
- return jsxRuntime.jsx(CautionNote, {
7860
+ return jsxRuntime.jsx(NoteBanner, {
7107
7861
  action: /* @__PURE__ */ jsxRuntime.jsx(CopyDetailsButton, {
7108
7862
  unreadable: unreadable
7109
7863
  }),
@@ -7149,6 +7903,21 @@ function InvalidDocNotice({invalid: invalid}) {
7149
7903
  });
7150
7904
  }
7151
7905
 
7906
+ function RoleAssignedNotice() {
7907
+ /* @__PURE__ */
7908
+ return jsxRuntime.jsx(ui.Box, {
7909
+ padding: 2,
7910
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
7911
+ muted: !0,
7912
+ size: 1,
7913
+ style: {
7914
+ fontStyle: "italic"
7915
+ },
7916
+ children: "Including tasks assigned to your role"
7917
+ })
7918
+ });
7919
+ }
7920
+
7152
7921
  function TabSwitch({ariaControls: ariaControls, idPrefix: idPrefix, options: options, selected: selected, onSelect: onSelect}) {
7153
7922
  /* @__PURE__ */
7154
7923
  return jsxRuntime.jsx(ui.TabList, {
@@ -7175,30 +7944,6 @@ function openActivityGone(args) {
7175
7944
  return evaluation !== void 0 && !evaluation.currentStage.activities.some(a => a.activity.name === target.activityName);
7176
7945
  }
7177
7946
 
7178
- function HintedMenuButton({hint: hint, ...menuButtonProps}) {
7179
- const [open, setOpen] = react.useState(!1), popover = {
7180
- tone: "default",
7181
- ...menuButtonProps.popover?.placement === void 0 ? {
7182
- placement: "bottom-end",
7183
- fallbackPlacements: [ "top-end" ]
7184
- } : {},
7185
- ...menuButtonProps.popover
7186
- };
7187
- return hint === void 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.MenuButton, {
7188
- ...menuButtonProps,
7189
- popover: popover
7190
- }) : /* @__PURE__ */ jsxRuntime.jsx(HoverHint, {
7191
- disabled: open,
7192
- text: hint,
7193
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.MenuButton, {
7194
- ...menuButtonProps,
7195
- onClose: () => setOpen(!1),
7196
- onOpen: () => setOpen(!0),
7197
- popover: popover
7198
- })
7199
- });
7200
- }
7201
-
7202
7947
  function subjectGdr(ctx) {
7203
7948
  return !ctx.subjectDocId || !ctx.mapping ? null : subjectGdrRef({
7204
7949
  mapping: ctx.mapping,
@@ -7437,8 +8182,15 @@ function presentedResumeEntry(args) {
7437
8182
  if (!args.startNew) return findResumeEntry(args);
7438
8183
  }
7439
8184
 
8185
+ function settledByAnotherWriter(cause, instance) {
8186
+ return workflowEngine.isRevisionConflict(cause) && workflowEngine.terminalState(instance) === "completed";
8187
+ }
8188
+
7440
8189
  function classifyStartError(err) {
7441
- return err instanceof workflowEngine.StartNotSettledError ? {
8190
+ return err instanceof workflowEngine.StartNotSettledError ? err.instance !== void 0 && settledByAnotherWriter(err.cause, err.instance) ? {
8191
+ kind: "started-settled-elsewhere",
8192
+ instance: err.instance
8193
+ } : {
7442
8194
  kind: "started-not-settled",
7443
8195
  instance: err.instance,
7444
8196
  description: describeError(err.cause)
@@ -7451,8 +8203,16 @@ function classifyStartError(err) {
7451
8203
  };
7452
8204
  }
7453
8205
 
8206
+ function startProducedRun(outcome) {
8207
+ return outcome.kind === "started-not-settled" || outcome.kind === "started-settled-elsewhere";
8208
+ }
8209
+
7454
8210
  function startOutcomeToast(outcome, label) {
7455
- return outcome.kind === "started-not-settled" ? {
8211
+ return outcome.kind === "started-settled-elsewhere" ? {
8212
+ id: TOAST_ID.start,
8213
+ status: "info",
8214
+ title: `“${label}” started and finished`
8215
+ } : outcome.kind === "started-not-settled" ? {
7456
8216
  id: TOAST_ID.start,
7457
8217
  status: "warning",
7458
8218
  title: `“${label}” started but didn’t finish`,
@@ -8018,7 +8778,7 @@ function DiscoverySpinner() {
8018
8778
  });
8019
8779
  }
8020
8780
 
8021
- const BOOT_CUE_DELAY_MS = 400, GROUP_GAP = 1;
8781
+ const BOOT_CUE_DELAY_MS = 400, GROUP_GAP = 2;
8022
8782
 
8023
8783
  function useWorkflowsTab() {
8024
8784
  const {params: params, setParams: setParams} = structure.usePaneRouter();
@@ -8183,10 +8943,10 @@ function OverviewEmptyState({mappings: mappings, docId: docId, initialValue: ini
8183
8943
  }
8184
8944
 
8185
8945
  function ForMeTab({forMe: forMe, assignedWorkUnknown: assignedWorkUnknown, onOpenActivity: onOpenActivity}) {
8186
- return forMe.hasRows ? /* @__PURE__ */ jsxRuntime.jsx(ui.Stack, {
8946
+ return forMe.hasRows ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
8187
8947
  gap: GROUP_GAP,
8188
8948
  paddingBottom: 4,
8189
- children: forMe.work.map(({entry: entry, who: who, shown: shown}) => /* @__PURE__ */ jsxRuntime.jsx(ForMeList, {
8949
+ children: [ forMe.hasRoleMatched ? /* @__PURE__ */ jsxRuntime.jsx(RoleAssignedNotice, {}) : null, forMe.work.map(({entry: entry, who: who, shown: shown}) => /* @__PURE__ */ jsxRuntime.jsx(ForMeList, {
8190
8950
  entry: entry,
8191
8951
  identity: who,
8192
8952
  work: shown,
@@ -8195,7 +8955,7 @@ function ForMeTab({forMe: forMe, assignedWorkUnknown: assignedWorkUnknown, onOpe
8195
8955
  activityName: activityName,
8196
8956
  stage: entry.instance.currentStage
8197
8957
  })
8198
- }, entry.instance._id))
8958
+ }, entry.instance._id)) ]
8199
8959
  }) : assignedWorkUnknown ? null : /* @__PURE__ */ jsxRuntime.jsx(ForMeEmptyState, {});
8200
8960
  }
8201
8961
 
@@ -8899,27 +9659,19 @@ function logOnce(messages, logged) {
8899
9659
  }
8900
9660
 
8901
9661
  function AssigneesInput({value: value, onChange: onChange}) {
8902
- const {members: members} = useProjectMembers(), [membersOpen, setMembersOpen] = react.useState(!1), roles = react.useMemo(() => [ ...new Set(members.flatMap(m => m.roles)) ].toSorted(), [ members ]), userIds = react.useMemo(() => new Set(value.flatMap(a => a.type === "user" ? [ a.id ] : [])), [ value ]), add = a => {
8903
- value.some(x => workflowComponents.sameAssignee(x, a)) || onChange([ ...value, a ]);
8904
- }, remove = i => onChange(value.filter((_, idx) => idx !== i)), toggleUser = id => {
8905
- const user = {
8906
- type: "user",
8907
- id: id
8908
- };
8909
- userIds.has(id) ? onChange(value.filter(a => !workflowComponents.sameAssignee(a, user))) : add(user);
8910
- };
9662
+ const [open, setOpen] = react.useState(!1), remove = index => onChange(value.filter((_, i) => i !== index));
8911
9663
  /* @__PURE__ */
8912
9664
  return jsxRuntime.jsxs(ui.Stack, {
8913
9665
  gap: 2,
8914
9666
  children: [ value.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
8915
9667
  gap: 2,
8916
9668
  wrap: "wrap",
8917
- children: value.map((a, i) => /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
9669
+ children: value.map((assignee, index) => /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
8918
9670
  align: "center",
8919
9671
  gap: 1,
8920
9672
  children: [
8921
9673
  /* @__PURE__ */ jsxRuntime.jsx(AssigneeBadge, {
8922
- assignee: a
9674
+ assignee: assignee
8923
9675
  }),
8924
9676
  /* @__PURE__ */ jsxRuntime.jsx(HoverHint, {
8925
9677
  text: "Remove",
@@ -8928,60 +9680,33 @@ function AssigneesInput({value: value, onChange: onChange}) {
8928
9680
  fontSize: 1,
8929
9681
  icon: Close.CloseIcon,
8930
9682
  mode: "bleed",
8931
- onClick: () => remove(i),
9683
+ onClick: () => remove(index),
8932
9684
  padding: 2
8933
9685
  })
8934
9686
  }) ]
8935
- }, a.type === "user" ? `user:${a.id}` : `role:${a.role}`))
9687
+ }, assignee.type === "user" ? `user:${assignee.id}` : `role:${assignee.role}`))
8936
9688
  }) : null,
8937
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
9689
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
8938
9690
  align: "center",
8939
9691
  gap: 2,
8940
9692
  wrap: "wrap",
8941
- children: [
8942
- /* @__PURE__ */ jsxRuntime.jsx(DismissablePopover, {
8943
- content: /* @__PURE__ */ jsxRuntime.jsx(MemberPicker, {
8944
- onSelect: member => member && toggleUser(member.id),
8945
- selectedIds: userIds
9693
+ children: /* @__PURE__ */ jsxRuntime.jsx(DismissablePopover, {
9694
+ content: /* @__PURE__ */ jsxRuntime.jsx(AssigneePicker, {
9695
+ onChange: next => onChange([ ...next ]),
9696
+ value: value
8946
9697
  }),
8947
- onDismiss: () => setMembersOpen(!1),
8948
- open: membersOpen,
9698
+ onDismiss: () => setOpen(!1),
9699
+ open: open,
8949
9700
  placement: "bottom-start",
8950
9701
  children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
8951
9702
  fontSize: 1,
8952
9703
  icon: User.UserIcon,
8953
9704
  mode: "ghost",
8954
- onClick: () => setMembersOpen(v => !v),
8955
- padding: 2,
8956
- text: "Add member"
8957
- })
8958
- }), roles.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.MenuButton, {
8959
- button: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
8960
- fontSize: 1,
8961
- icon: Add.AddIcon,
8962
- mode: "ghost",
9705
+ onClick: () => setOpen(v => !v),
8963
9706
  padding: 2,
8964
- text: "Add role"
8965
- }),
8966
- id: "assignees-add-role",
8967
- menu: /* @__PURE__ */ jsxRuntime.jsx(ui.Menu, {
8968
- style: {
8969
- maxHeight: 280,
8970
- overflowY: "auto"
8971
- },
8972
- children: roles.map(r => /* @__PURE__ */ jsxRuntime.jsx(ui.MenuItem, {
8973
- onClick: () => add({
8974
- type: "role",
8975
- role: r
8976
- }),
8977
- text: `Role: ${r}`
8978
- }, r))
9707
+ text: "Assign"
8979
9708
  })
8980
- }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
8981
- muted: !0,
8982
- size: 1,
8983
- children: "No project roles found"
8984
- }) ]
9709
+ })
8985
9710
  }) ]
8986
9711
  });
8987
9712
  }
@@ -9468,7 +10193,7 @@ function ResumeNote({onStartNew: onStartNew}) {
9468
10193
 
9469
10194
  function handleStartError(args) {
9470
10195
  const {label: label, toast: toast, seedInstance: seedInstance, onClose: onClose} = args, outcome = classifyStartError(args.err);
9471
- toast.push(startOutcomeToast(outcome, label)), outcome.kind === "started-not-settled" && (outcome.instance !== void 0 && seedInstance(outcome.instance),
10196
+ toast.push(startOutcomeToast(outcome, label)), startProducedRun(outcome) && (outcome.instance !== void 0 && seedInstance(outcome.instance),
9472
10197
  onClose());
9473
10198
  }
9474
10199
 
@@ -9821,7 +10546,7 @@ async function startRequest(engine, request) {
9821
10546
  };
9822
10547
  } catch (err) {
9823
10548
  const outcome = classifyStartError(err);
9824
- return outcome.kind === "started-not-settled" ? outcome.instance ? {
10549
+ return startProducedRun(outcome) ? outcome.instance ? {
9825
10550
  instance: outcome.instance
9826
10551
  } : {} : outcome.kind === "not-allowed" ? {} : {
9827
10552
  failure: outcome.description
@@ -9911,17 +10636,6 @@ function makePerspectiveBadge(documentId) {
9911
10636
  return WorkflowPerspectiveBadge;
9912
10637
  }
9913
10638
 
9914
- function StartIncompleteBadge({style: style}) {
9915
- /* @__PURE__ */
9916
- return jsxRuntime.jsx(ui.Badge, {
9917
- fontSize: 1,
9918
- mode: "outline",
9919
- style: style,
9920
- tone: "caution",
9921
- children: "Start incomplete"
9922
- });
9923
- }
9924
-
9925
10639
  const GLANCE_CAP = 3;
9926
10640
 
9927
10641
  function AssignedTasksHint({work: work}) {
@@ -10433,15 +11147,17 @@ function WorkflowRootInput(props) {
10433
11147
  });
10434
11148
  }
10435
11149
 
11150
+ exports.AbortWorkflowDialog = AbortWorkflowDialog;
11151
+
10436
11152
  exports.ActivityDetailDialog = ActivityDetailDialog;
10437
11153
 
11154
+ exports.ActivityLog = ActivityLog;
11155
+
10438
11156
  exports.ActivityRow = ActivityRow;
10439
11157
 
10440
11158
  exports.BreadcrumbTail = BreadcrumbTail;
10441
11159
 
10442
- exports.CautionNote = CautionNote;
10443
-
10444
- exports.CollapsibleBand = CollapsibleBand;
11160
+ exports.CodeChip = CodeChip;
10445
11161
 
10446
11162
  exports.CountedLabel = CountedLabel;
10447
11163
 
@@ -10457,8 +11173,6 @@ exports.ForMeEmptyState = ForMeEmptyState;
10457
11173
 
10458
11174
  exports.Hairline = Hairline;
10459
11175
 
10460
- exports.HintedMenuButton = HintedMenuButton;
10461
-
10462
11176
  exports.HoverHint = HoverHint;
10463
11177
 
10464
11178
  exports.InstanceSnapshotBody = InstanceSnapshotBody;
@@ -10473,6 +11187,10 @@ exports.LogEventOnMount = LogEventOnMount;
10473
11187
 
10474
11188
  exports.MetaRow = MetaRow;
10475
11189
 
11190
+ exports.NoteBanner = NoteBanner;
11191
+
11192
+ exports.RoleAssignedNotice = RoleAssignedNotice;
11193
+
10476
11194
  exports.SpinnerSlot = SpinnerSlot;
10477
11195
 
10478
11196
  exports.StageFace = StageFace;
@@ -10485,20 +11203,12 @@ exports.TOOL_TABS = TOOL_TABS;
10485
11203
 
10486
11204
  exports.TabSwitch = TabSwitch;
10487
11205
 
10488
- exports.TrailingHairline = TrailingHairline;
10489
-
10490
11206
  exports.UnreadableDocsNote = UnreadableDocsNote;
10491
11207
 
10492
- exports.UserAvatar = UserAvatar;
10493
-
10494
11208
  exports.WORKFLOW_API_VERSION = WORKFLOW_API_VERSION;
10495
11209
 
10496
11210
  exports.WORKFLOW_PAGE_TABS = WORKFLOW_PAGE_TABS;
10497
11211
 
10498
- exports.WorkflowAbortDialogOpened = WorkflowAbortDialogOpened;
10499
-
10500
- exports.WorkflowAbortDialogSubmitted = WorkflowAbortDialogSubmitted;
10501
-
10502
11212
  exports.WorkflowBoardWorkflowSelected = WorkflowBoardWorkflowSelected;
10503
11213
 
10504
11214
  exports.WorkflowDefinitionDetailViewed = WorkflowDefinitionDetailViewed;
@@ -10513,7 +11223,7 @@ exports.WorkflowToolOpened = WorkflowToolOpened;
10513
11223
 
10514
11224
  exports.activityRowProps = activityRowProps;
10515
11225
 
10516
- exports.assigneeUserIdsOf = assigneeUserIdsOf;
11226
+ exports.assigneesOf = assigneesOf;
10517
11227
 
10518
11228
  exports.backToTabLabel = backToTabLabel;
10519
11229
 
@@ -10537,10 +11247,6 @@ exports.findActivityNode = findActivityNode;
10537
11247
 
10538
11248
  exports.formatDate = formatDate;
10539
11249
 
10540
- exports.formatDateTime = formatDateTime;
10541
-
10542
- exports.formatShortAgo = formatShortAgo;
10543
-
10544
11250
  exports.formatShortDateTime = formatShortDateTime;
10545
11251
 
10546
11252
  exports.formatTimeAgo = formatTimeAgo;
@@ -10561,6 +11267,8 @@ exports.isLiveEntry = isLiveEntry;
10561
11267
 
10562
11268
  exports.isOpenActivityStatus = isOpenActivityStatus;
10563
11269
 
11270
+ exports.isRoleAssignedTo = isRoleAssignedTo;
11271
+
10564
11272
  exports.landingState = landingState;
10565
11273
 
10566
11274
  exports.mappingIssueDetail = mappingIssueDetail;
@@ -10591,8 +11299,6 @@ exports.toolTabState = toolTabState;
10591
11299
 
10592
11300
  exports.useAssignmentIdentity = useAssignmentIdentity;
10593
11301
 
10594
- exports.useAvatarSize = useAvatarSize;
10595
-
10596
11302
  exports.useBadgeCapTrim = useBadgeCapTrim;
10597
11303
 
10598
11304
  exports.useContainerToken = useContainerToken;
@@ -10607,8 +11313,6 @@ exports.useProjectMembers = useProjectMembers;
10607
11313
 
10608
11314
  exports.useSpaceToken = useSpaceToken;
10609
11315
 
10610
- exports.useUserDisplay = useUserDisplay;
10611
-
10612
11316
  exports.useUserDisplays = useUserDisplays;
10613
11317
 
10614
11318
  exports.useWorkflowContext = useWorkflowContext;