@sanity/workflow-studio-plugin 0.25.0 → 0.27.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"), 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,9 +703,19 @@ 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) {
@@ -1032,7 +1045,7 @@ function activityRowProps(args) {
1032
1045
  blocked: showsBlockedTag(activityEval)
1033
1046
  },
1034
1047
  assignState: rowAssignControlState(controlArgs),
1035
- assigneeIds: assigneeUserIdsOf(state),
1048
+ assignees: assigneesOf(state),
1036
1049
  dateState: rowDateControlState(controlArgs),
1037
1050
  dueDates: dueDatesOf(state),
1038
1051
  terminalActions: rowTerminalActions({
@@ -1340,7 +1353,9 @@ function projectMembersFrom(users) {
1340
1353
  sanityUserId: profile?.sanityUserId,
1341
1354
  displayName: profile?.displayName,
1342
1355
  email: profile?.email,
1343
- imageUrl: profile?.imageUrl ?? void 0
1356
+ imageUrl: profile?.imageUrl ?? void 0,
1357
+ loginProvider: workflowEngine.userLoginProvider(profile),
1358
+ isCurrentUser: membership.isCurrentUser
1344
1359
  }));
1345
1360
  return projectMembersByUsers.set(users, members), members;
1346
1361
  }
@@ -1722,6 +1737,17 @@ function AssigneePicker({value: value, onChange: onChange}) {
1722
1737
  });
1723
1738
  }
1724
1739
 
1740
+ function SingleAssigneePicker({current: current, onPick: onPick}) {
1741
+ /* @__PURE__ */
1742
+ return jsxRuntime.jsx(AssigneePicker, {
1743
+ onChange: next => {
1744
+ const picked = singleAssigneePick(current, next);
1745
+ picked !== void 0 && onPick(picked);
1746
+ },
1747
+ value: current ? [ current ] : []
1748
+ });
1749
+ }
1750
+
1725
1751
  function MemberPickerButton({label: label = "Select member…", onChange: onChange, selectedIds: selectedIds, unassignRow: unassignRow = !1, value: value}) {
1726
1752
  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
1753
  /* @__PURE__ */
@@ -1731,7 +1757,7 @@ function MemberPickerButton({label: label = "Select member…", onChange: onChan
1731
1757
  setOpen(!1), onChange(member && !selected.has(member.id) ? {
1732
1758
  id: member.id,
1733
1759
  displayName: member.displayName,
1734
- roles: member.roles
1760
+ roles: member.roles.map(role => role.name)
1735
1761
  } : null);
1736
1762
  },
1737
1763
  selectedIds: selected,
@@ -2419,7 +2445,7 @@ function Separator() {
2419
2445
  alignItems: "center",
2420
2446
  display: "inline-flex",
2421
2447
  height: "0.7em",
2422
- margin: "0 0.25em",
2448
+ margin: "0 0.5em",
2423
2449
  overflow: "hidden"
2424
2450
  },
2425
2451
  children: /* @__PURE__ */ jsxRuntime.jsx(ChevronRight.ChevronRightIcon, {})
@@ -3538,18 +3564,18 @@ function ActorField({field: field, instanceId: instanceId, onSave: onSave, onUns
3538
3564
  }
3539
3565
 
3540
3566
  function useAssigneePick(args) {
3541
- const {current: current, onSave: onSave, onUnset: onUnset} = args, {saving: saving, save: save} = useSaveField({
3567
+ const {onSave: onSave, onUnset: onUnset} = args, {saving: saving, save: save} = useSaveField({
3542
3568
  instanceId: args.instanceId
3543
3569
  });
3544
3570
  return {
3545
3571
  saving: saving,
3546
- pick: assignee => {
3572
+ pick: picked => {
3547
3573
  if (!saving) {
3548
- if (current && workflowComponents.sameAssignee(assignee, current)) {
3574
+ if (picked === null) {
3549
3575
  onUnset !== void 0 && save(onUnset);
3550
3576
  return;
3551
3577
  }
3552
- save(() => onSave(assignee));
3578
+ save(() => onSave(picked));
3553
3579
  }
3554
3580
  }
3555
3581
  };
@@ -3557,22 +3583,18 @@ function useAssigneePick(args) {
3557
3583
 
3558
3584
  function AssigneeField({field: field, instanceId: instanceId, onSave: onSave, onUnset: onUnset}) {
3559
3585
  const [open, setOpen] = react.useState(!1), cur = isAssigneeShape(field.value) ? field.value : null, {pick: pick} = useAssigneePick({
3560
- current: cur,
3561
3586
  instanceId: instanceId,
3562
3587
  onSave: onSave,
3563
3588
  onUnset: onUnset
3564
- }), pickAndClose = assignee => {
3565
- setOpen(!1), pick(assignee);
3566
- };
3589
+ });
3567
3590
  return field.editable ? /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
3568
3591
  align: "center",
3569
3592
  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 ] : []
3593
+ content: /* @__PURE__ */ jsxRuntime.jsx(SingleAssigneePicker, {
3594
+ current: cur,
3595
+ onPick: picked => {
3596
+ setOpen(!1), pick(picked);
3597
+ }
3576
3598
  }),
3577
3599
  onDismiss: () => setOpen(!1),
3578
3600
  open: open,
@@ -4121,70 +4143,85 @@ function AvatarButton({avatar: avatar, onClick: onClick, onMouseDown: onMouseDow
4121
4143
  });
4122
4144
  }
4123
4145
 
4124
- function UserAvatar({id: id}) {
4125
- const {name: name, imageUrl: imageUrl} = useUserDisplay(id);
4146
+ function RowAssignees({assignees: assignees, hint: hint}) {
4147
+ const ids = assignees.flatMap(item => item.type === "user" ? [ item.id ] : []), {members: members} = useProjectMembers(), roles = assignees.flatMap(item => item.type === "role" ? [ workflowComponents.memberRoleFor(members, item.role) ] : []), displays = useUserDisplays(ids);
4148
+ if (ids.length === 0 && roles.length === 0) return null;
4149
+ const bothKinds = roles.length > 0 && displays.length > 0;
4126
4150
  /* @__PURE__ */
4127
4151
  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, {
4152
+ content:
4153
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
4154
+ gap: 3,
4155
+ children: [ roles.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(HintSection, {
4156
+ names: roles.map(workflowComponents.roleLabel),
4157
+ ...bothKinds ? {
4158
+ label: "Roles"
4159
+ } : {}
4160
+ }) : null, displays.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(HintSection, {
4161
+ names: displays.map(display => display.name),
4162
+ ...bothKinds ? {
4163
+ label: "Members"
4164
+ } : {}
4165
+ }) : null, hint === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
4166
+ muted: !0,
4167
+ size: 1,
4168
+ children: hint
4169
+ }) ]
4170
+ }),
4171
+ children: /* @__PURE__ */ jsxRuntime.jsx(workflowComponents.AssigneeStack, {
4144
4172
  members: displays.map(display => ({
4145
4173
  id: display.id,
4146
4174
  displayName: display.name,
4147
4175
  imageUrl: display.imageUrl
4148
- }))
4176
+ })),
4177
+ roles: roles
4149
4178
  })
4150
4179
  });
4151
4180
  }
4152
4181
 
4153
- function AssignActivityControl({instanceId: instanceId, state: state, surface: surface, assigneeIds: assigneeIds = []}) {
4182
+ function HintSection({label: label, names: names}) {
4183
+ /* @__PURE__ */
4184
+ return jsxRuntime.jsxs(ui.Stack, {
4185
+ gap: 2,
4186
+ children: [ label === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
4187
+ size: 1,
4188
+ weight: "medium",
4189
+ children: label
4190
+ }),
4191
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
4192
+ size: 1,
4193
+ children: names.join(", ")
4194
+ }) ]
4195
+ });
4196
+ }
4197
+
4198
+ function AssignActivityControl({instanceId: instanceId, state: state, surface: surface, assignees: assignees = []}) {
4154
4199
  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, {
4200
+ if (state.kind === "none") return assignees.length === 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(AvatarDisplay, {
4156
4201
  "aria-label": "Assignees",
4157
- avatar: /* @__PURE__ */ jsxRuntime.jsx(UserAvatarGroup, {
4158
- ids: assigneeIds
4202
+ avatar: /* @__PURE__ */ jsxRuntime.jsx(RowAssignees, {
4203
+ assignees: assignees
4159
4204
  })
4160
4205
  });
4161
- if (state.kind === "closed") return assigneeIds.length === 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(AvatarButton, {
4206
+ if (state.kind === "closed") return assignees.length === 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(AvatarButton, {
4162
4207
  "aria-label": "Assignees",
4163
4208
  as: "span",
4164
- avatar: /* @__PURE__ */ jsxRuntime.jsx(UserAvatarGroup, {
4165
- hint: state.reason,
4166
- ids: assigneeIds
4209
+ avatar: /* @__PURE__ */ jsxRuntime.jsx(RowAssignees, {
4210
+ assignees: assignees,
4211
+ hint: state.reason
4167
4212
  }),
4168
4213
  onClick: stopRowClick,
4169
4214
  onMouseDown: stopRowMouseDown
4170
4215
  });
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)) {
4216
+ const field = state.kind === "editable" ? state.field : void 0, current = field?.value ?? [], change = async next => {
4217
+ const edit = assigneeEdit(current, next);
4218
+ if (!(busy || field === void 0 || edit === void 0)) {
4173
4219
  setBusy(!0);
4174
4220
  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({
4221
+ await editField({
4181
4222
  instanceId: instanceId,
4182
4223
  field: field,
4183
- mode: "append",
4184
- value: {
4185
- type: "user",
4186
- id: memberId
4187
- }
4224
+ ...edit
4188
4225
  }), report.dismiss(instanceToastId("assign", instanceId));
4189
4226
  } catch (err) {
4190
4227
  report.rejected({
@@ -4200,12 +4237,12 @@ function AssignActivityControl({instanceId: instanceId, state: state, surface: s
4200
4237
  }
4201
4238
  }, handleClick = e => {
4202
4239
  e.stopPropagation(), setOpen(v => !v);
4203
- }, button = assigneeIds.length > 0 ?
4240
+ }, button = assignees.length > 0 ?
4204
4241
  /* @__PURE__ */ jsxRuntime.jsx(AvatarButton, {
4205
4242
  "aria-label": "Assignees",
4206
4243
  as: "span",
4207
- avatar: /* @__PURE__ */ jsxRuntime.jsx(UserAvatarGroup, {
4208
- ids: assigneeIds
4244
+ avatar: /* @__PURE__ */ jsxRuntime.jsx(RowAssignees, {
4245
+ assignees: assignees
4209
4246
  }),
4210
4247
  onClick: handleClick,
4211
4248
  onMouseDown: stopRowMouseDown
@@ -4230,9 +4267,11 @@ function AssignActivityControl({instanceId: instanceId, state: state, surface: s
4230
4267
  children: state.kind === "loading" ? /* @__PURE__ */ jsxRuntime.jsx(LoadingRow, {
4231
4268
  label: "Loading…",
4232
4269
  padding: 3
4233
- }) : /* @__PURE__ */ jsxRuntime.jsx(MemberPicker, {
4234
- onSelect: member => member && void toggle(member.id),
4235
- selectedIds: selectedIds
4270
+ }) : /* @__PURE__ */ jsxRuntime.jsx(AssigneePicker, {
4271
+ onChange: next => {
4272
+ change(next);
4273
+ },
4274
+ value: current
4236
4275
  })
4237
4276
  }),
4238
4277
  onDismiss: () => setOpen(!1),
@@ -4264,6 +4303,58 @@ function canRemoveRow(args) {
4264
4303
  return editTarget === void 0 || appendTarget === void 0 ? !1 : editTarget.scope === appendTarget.scope && editTarget.field === appendTarget.field && editTarget.activity === appendTarget.activity;
4265
4304
  }
4266
4305
 
4306
+ function EmptyState({action: action, description: description, icon: icon, title: title}) {
4307
+ /* @__PURE__ */
4308
+ return jsxRuntime.jsx(ui.Card, {
4309
+ border: !0,
4310
+ flex: 1,
4311
+ padding: 4,
4312
+ radius: 3,
4313
+ style: {
4314
+ alignItems: "center",
4315
+ display: "flex",
4316
+ justifyContent: "center"
4317
+ },
4318
+ children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
4319
+ gap: 4,
4320
+ children: [
4321
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
4322
+ align: "center",
4323
+ size: 4,
4324
+ children: icon
4325
+ }),
4326
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
4327
+ gap: 3,
4328
+ children: [
4329
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
4330
+ align: "center",
4331
+ size: 1,
4332
+ weight: "medium",
4333
+ children: title
4334
+ }),
4335
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
4336
+ align: "center",
4337
+ muted: !0,
4338
+ size: 1,
4339
+ children: description
4340
+ }) ]
4341
+ }), action ? /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
4342
+ justify: "center",
4343
+ children: action
4344
+ }) : null ]
4345
+ })
4346
+ });
4347
+ }
4348
+
4349
+ function ForMeEmptyState() {
4350
+ /* @__PURE__ */
4351
+ return jsxRuntime.jsx(EmptyState, {
4352
+ description: "No activities or to-dos are assigned to you",
4353
+ icon: /* @__PURE__ */ jsxRuntime.jsx(CheckmarkCircle.CheckmarkCircleIcon, {}),
4354
+ title: "Nothing to do!"
4355
+ });
4356
+ }
4357
+
4267
4358
  function looksLikeDefinition(value) {
4268
4359
  return typeof value == "object" && value !== null && Array.isArray(value.stages);
4269
4360
  }
@@ -4421,22 +4512,18 @@ function DueDateControl({item: item, editable: editable, onPatch: onPatch}) {
4421
4512
  }
4422
4513
 
4423
4514
  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
4515
+ const [open, setOpen] = react.useState(!1), current = item.assignee ?? null, chip = current ? /* @__PURE__ */ jsxRuntime.jsx(RowAssignees, {
4516
+ assignees: [ current ]
4426
4517
  }) : null;
4427
4518
  return editable ? /* @__PURE__ */ jsxRuntime.jsx(DismissablePopover, {
4428
4519
  content:
4429
- /* @__PURE__ */ jsxRuntime.jsx(MemberPicker, {
4430
- onSelect: member => {
4520
+ /* @__PURE__ */ jsxRuntime.jsx(SingleAssigneePicker, {
4521
+ current: current,
4522
+ onPick: picked => {
4431
4523
  setOpen(!1), onPatch({
4432
- assignee: member && member.id !== assignedId ? {
4433
- type: "user",
4434
- id: member.id
4435
- } : null
4524
+ assignee: picked
4436
4525
  });
4437
- },
4438
- selectedIds: assignedId ? /* @__PURE__ */ new Set([ assignedId ]) : /* @__PURE__ */ new Set,
4439
- unassignRow: !0
4526
+ }
4440
4527
  }),
4441
4528
  onDismiss: () => setOpen(!1),
4442
4529
  open: open,
@@ -4632,7 +4719,7 @@ function TodoItemRowView({breadcrumb: breadcrumb, row: row, onToggle: onToggle,
4632
4719
  });
4633
4720
  }
4634
4721
 
4635
- function TodoItemsList({breadcrumb: breadcrumb, entry: entry, filter: filter, surface: surface}) {
4722
+ function TodoItemsList({breadcrumb: breadcrumb, entry: entry, filter: filter, showEmpty: showEmpty = !1, surface: surface}) {
4636
4723
  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
4724
  if (busy) return !1;
4638
4725
  setBusy(!0);
@@ -4728,8 +4815,28 @@ function TodoItemsList({breadcrumb: breadcrumb, entry: entry, filter: filter, su
4728
4815
  kind: "remove",
4729
4816
  success: success
4730
4817
  });
4731
- };
4732
- if (rows.length === 0 && !appendTarget) return null;
4818
+ }, empty = rows.length === 0;
4819
+ if (empty && !showEmpty) return null;
4820
+ const addControl = appendTarget ? /* @__PURE__ */ jsxRuntime.jsx(AddItemControl, {
4821
+ busy: busy,
4822
+ button: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
4823
+ fontSize: 1,
4824
+ icon: Add.AddIcon,
4825
+ mode: "ghost",
4826
+ padding: 2,
4827
+ text: "Add item"
4828
+ }),
4829
+ onAdd: addItem
4830
+ }) : null;
4831
+ if (empty) /* @__PURE__ */
4832
+ return jsxRuntime.jsx(EmptyState, {
4833
+ ...addControl === null ? {} : {
4834
+ action: addControl
4835
+ },
4836
+ description: "Nothing has been added to this list",
4837
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Ulist.UlistIcon, {}),
4838
+ title: "No to-dos"
4839
+ });
4733
4840
  const rowKey = row => `${row.scope}:${row.activityName ?? ""}:${row.fieldName}:${row.item._key}`, rowBreadcrumb = row => {
4734
4841
  if (breadcrumb === void 0 || row.activityName === void 0) return breadcrumb;
4735
4842
  const {title: title} = findActivity({
@@ -4763,19 +4870,9 @@ function TodoItemsList({breadcrumb: breadcrumb, entry: entry, filter: filter, su
4763
4870
  },
4764
4871
  row: row
4765
4872
  }, 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 ]
4873
+ }), addControl === null ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
4874
+ children: addControl
4875
+ }) ]
4779
4876
  });
4780
4877
  }
4781
4878
 
@@ -5214,6 +5311,7 @@ function FieldRow({field: field, detail: detail, entry: entry, activityName: act
5214
5311
  field: field.name,
5215
5312
  activity: activityName
5216
5313
  },
5314
+ showEmpty: !0,
5217
5315
  surface: "activity-dialog"
5218
5316
  }) ]
5219
5317
  });
@@ -5270,58 +5368,6 @@ function blockedNotice(detail) {
5270
5368
  });
5271
5369
  }
5272
5370
 
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
5371
  function CountedLabel({count: count, label: label}) {
5326
5372
  return count === void 0 || count === 0 ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, {
5327
5373
  children: label
@@ -5522,17 +5568,13 @@ function TitleTag({hint: hint, tone: tone, children: children}) {
5522
5568
  });
5523
5569
  }
5524
5570
 
5525
- function ActivityRow({face: face, breadcrumb: breadcrumb, assigneeIds: assigneeIds, assignState: assignState, dateState: dateState, dueDates: dueDates, instanceId: instanceId, onOpen: onOpen, surface: surface, terminalActions: terminalActions = []}) {
5571
+ function ActivityRow({face: face, breadcrumb: breadcrumb, assignees: assignees, assignState: assignState, dateState: dateState, dueDates: dueDates, instanceId: instanceId, onOpen: onOpen, surface: surface, terminalActions: terminalActions = []}) {
5526
5572
  const settled = workflowEngine.isTerminalActivityStatus(face.status), dimmed = settledDim(settled);
5527
5573
  /* @__PURE__ */
5528
5574
  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
- }),
5575
+ end:
5576
+ /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
5577
+ children: [
5536
5578
  /* @__PURE__ */ jsxRuntime.jsx(ActivityDateControl, {
5537
5579
  dueDates: dueDates,
5538
5580
  instanceId: instanceId,
@@ -5540,10 +5582,15 @@ function ActivityRow({face: face, breadcrumb: breadcrumb, assigneeIds: assigneeI
5540
5582
  surface: surface
5541
5583
  }),
5542
5584
  /* @__PURE__ */ jsxRuntime.jsx(AssignActivityControl, {
5543
- assigneeIds: assigneeIds,
5585
+ assignees: assignees,
5544
5586
  instanceId: instanceId,
5545
5587
  state: assignState,
5546
5588
  surface: surface
5589
+ }), settled || terminalActions.length === 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(RowTerminalActions, {
5590
+ actions: terminalActions,
5591
+ activity: face.activityName,
5592
+ instanceId: instanceId,
5593
+ surface: surface
5547
5594
  }) ]
5548
5595
  }),
5549
5596
  lead: /* @__PURE__ */ jsxRuntime.jsx(ActivityStatusLead, {
@@ -5767,6 +5814,35 @@ function deriveFieldPills(args) {
5767
5814
  });
5768
5815
  }
5769
5816
 
5817
+ function UserAvatar({id: id}) {
5818
+ const {name: name, imageUrl: imageUrl} = useUserDisplay(id);
5819
+ /* @__PURE__ */
5820
+ return jsxRuntime.jsx(HoverHint, {
5821
+ text: name,
5822
+ children: /* @__PURE__ */ jsxRuntime.jsx(workflowComponents.MemberAvatar, {
5823
+ imageUrl: imageUrl,
5824
+ name: name
5825
+ })
5826
+ });
5827
+ }
5828
+
5829
+ function UserAvatarGroup({ids: ids, hint: hint}) {
5830
+ const displays = useUserDisplays(ids);
5831
+ return displays.length === 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(HoverHint, {
5832
+ text: displays.map(d => d.name).join(", "),
5833
+ ...hint === void 0 ? {} : {
5834
+ description: hint
5835
+ },
5836
+ children: /* @__PURE__ */ jsxRuntime.jsx(workflowComponents.MemberAvatarGroup, {
5837
+ members: displays.map(display => ({
5838
+ id: display.id,
5839
+ displayName: display.name,
5840
+ imageUrl: display.imageUrl
5841
+ }))
5842
+ })
5843
+ });
5844
+ }
5845
+
5770
5846
  function TodoFieldDialog({entry: entry, scope: scope, field: field, title: title, onClose: onClose}) {
5771
5847
  /* @__PURE__ */
5772
5848
  return jsxRuntime.jsx(ui.Dialog, {
@@ -5783,6 +5859,7 @@ function TodoFieldDialog({entry: entry, scope: scope, field: field, title: title
5783
5859
  scope: scope,
5784
5860
  field: field
5785
5861
  },
5862
+ showEmpty: !0,
5786
5863
  surface: "todo-field-dialog"
5787
5864
  })
5788
5865
  })
@@ -5900,12 +5977,24 @@ function PillContent({pill: pill}) {
5900
5977
  children: [ lead,
5901
5978
  /* @__PURE__ */ jsxRuntime.jsx(FaceText, {
5902
5979
  muted: !0,
5903
- children: pill.editability?.editable === !0 ? `Set ${pill.title}` : pill.title
5980
+ children: pill.title
5904
5981
  }) ]
5905
5982
  }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
5906
5983
  children: [ lead,
5907
- /* @__PURE__ */ jsxRuntime.jsx(SetFace, {
5908
- face: face
5984
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
5985
+ align: "center",
5986
+ gap: 1,
5987
+ style: {
5988
+ minWidth: 0
5989
+ },
5990
+ children: [
5991
+ /* @__PURE__ */ jsxRuntime.jsx(FaceText, {
5992
+ muted: !0,
5993
+ children: `${pill.title}:`
5994
+ }),
5995
+ /* @__PURE__ */ jsxRuntime.jsx(SetFace, {
5996
+ face: face
5997
+ }) ]
5909
5998
  }) ]
5910
5999
  });
5911
6000
  }
@@ -5925,7 +6014,7 @@ function AvatarCapAligned({children: children}) {
5925
6014
  }
5926
6015
 
5927
6016
  function AssigneesFace({assignees: assignees}) {
5928
- const userIds = assignees.flatMap(a => a.type === "user" ? [ a.id ] : []), roles = assignees.flatMap(a => a.type === "role" ? [ a.role ] : []);
6017
+ const {members: members} = useProjectMembers(), userIds = assignees.flatMap(a => a.type === "user" ? [ a.id ] : []), roles = assignees.flatMap(a => a.type === "role" ? [ workflowComponents.roleLabelFor(members, a.role) ] : []);
5929
6018
  /* @__PURE__ */
5930
6019
  return jsxRuntime.jsxs(jsxRuntime.Fragment, {
5931
6020
  children: [ userIds.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(AvatarCapAligned, {
@@ -5958,14 +6047,11 @@ function usePillChrome(face) {
5958
6047
  }
5959
6048
 
5960
6049
  function PillHint({pill: pill, disabled: disabled = !1, children: children}) {
6050
+ const {description: description} = pill;
5961
6051
  /* @__PURE__ */
5962
6052
  return jsxRuntime.jsx(HoverHint, {
5963
- disabled: disabled,
5964
- text: pill.title,
5965
- textWeight: "medium",
5966
- ...pill.description === void 0 ? {} : {
5967
- description: pill.description
5968
- },
6053
+ disabled: disabled || description === void 0,
6054
+ text: description ?? "",
5969
6055
  children: children
5970
6056
  });
5971
6057
  }
@@ -6051,7 +6137,7 @@ function PillPopover({pill: pill, content: content2, open: open, onToggle: onTog
6051
6137
  }
6052
6138
 
6053
6139
  function ReadOnlyPill({pill: pill}) {
6054
- const [open, setOpen] = react.useState(!1), reason = pill.editability?.disabledReason;
6140
+ const [open, setOpen] = react.useState(!1), verdict = pill.editability?.disabledReason, reason = verdict !== void 0 && reasonRestatesInstanceState(verdict) ? void 0 : verdict;
6055
6141
  /* @__PURE__ */
6056
6142
  return jsxRuntime.jsx(PillPopover, {
6057
6143
  content: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
@@ -6234,19 +6320,17 @@ function AssigneePill({entry: entry, pill: pill, editability: editability, surfa
6234
6320
  editability: editability,
6235
6321
  surface: surface
6236
6322
  }), current = pill.entry?._type === "assignee" ? pill.entry.value : null, {pick: pick} = useAssigneePick({
6237
- current: current,
6238
6323
  instanceId: entry.instance._id,
6239
6324
  onSave: set,
6240
6325
  onUnset: unset
6241
6326
  });
6242
6327
  /* @__PURE__ */
6243
6328
  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 ] : []
6329
+ content: /* @__PURE__ */ jsxRuntime.jsx(SingleAssigneePicker, {
6330
+ current: current,
6331
+ onPick: picked => {
6332
+ setOpen(!1), pick(picked);
6333
+ }
6250
6334
  }),
6251
6335
  onDismiss: () => setOpen(!1),
6252
6336
  onToggle: () => setOpen(v => !v),
@@ -6375,165 +6459,6 @@ function instanceBreadcrumb(instance, definition) {
6375
6459
  return [ instanceTitle(instance, definition), stageTitle(definition, instance.currentStage) ];
6376
6460
  }
6377
6461
 
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
6462
  const UNCONDITIONAL_WHENS = /* @__PURE__ */ new Set([ "true", workflowEngine.DEFAULT_TRANSITION_WHEN ]);
6538
6463
 
6539
6464
  function stageRounds(instance) {
@@ -6593,6 +6518,31 @@ function nodeState(args) {
6593
6518
  return args.name === args.instance.currentStage ? "current" : args.visits === 0 ? "upcoming" : args.currentIndex >= 0 && args.index > args.currentIndex ? "revisit" : "done";
6594
6519
  }
6595
6520
 
6521
+ function roundDetail(round) {
6522
+ return round === void 0 ? void 0 : `Round ${round}`;
6523
+ }
6524
+
6525
+ function instanceStageFace(args) {
6526
+ const {definition: definition, instance: instance} = args;
6527
+ if (workflowEngine.isUnprimed(instance)) return;
6528
+ const current = definition === void 0 ? void 0 : deriveSpine({
6529
+ definition: definition,
6530
+ instance: instance
6531
+ }).find(node => node.state === "current");
6532
+ if (current === void 0) return {
6533
+ title: stageTitle(definition, instance.currentStage),
6534
+ completed: workflowEngine.terminalState(instance) === "completed"
6535
+ };
6536
+ const detail = roundDetail(current.round);
6537
+ return {
6538
+ title: current.title,
6539
+ completed: current.completedAt !== void 0,
6540
+ ...detail === void 0 ? {} : {
6541
+ detail: detail
6542
+ }
6543
+ };
6544
+ }
6545
+
6596
6546
  function stageOverview(args) {
6597
6547
  const {definition: definition, node: node, transitions: transitions} = args, stage = definition.stages.find(s => s.name === node.name), advance = node.state === "current" ? advanceHint({
6598
6548
  definition: definition,
@@ -6659,97 +6609,878 @@ function advanceHint(args) {
6659
6609
  };
6660
6610
  }
6661
6611
 
6662
- function conditionLines(description) {
6663
- return description.checklist.kind === "group" && description.checklist.op === "all" ? description.checklist.items.flatMap(item => workflowEngine.checklistLines({
6664
- ...description,
6665
- checklist: item
6666
- }, {
6667
- marks: !1
6668
- })) : workflowEngine.checklistLines(description, {
6669
- marks: !1
6612
+ function conditionLines(description) {
6613
+ return description.checklist.kind === "group" && description.checklist.op === "all" ? description.checklist.items.flatMap(item => workflowEngine.checklistLines({
6614
+ ...description,
6615
+ checklist: item
6616
+ }, {
6617
+ marks: !1
6618
+ })) : workflowEngine.checklistLines(description, {
6619
+ marks: !1
6620
+ });
6621
+ }
6622
+
6623
+ function Hairline({weight: weight, style: style}) {
6624
+ const {color: color} = ui.useTheme_v2();
6625
+ /* @__PURE__ */
6626
+ return jsxRuntime.jsx("div", {
6627
+ style: {
6628
+ borderTop: `${weight}px solid ${color.border}`,
6629
+ ...style
6630
+ }
6631
+ });
6632
+ }
6633
+
6634
+ function StageGlyph(props) {
6635
+ /* @__PURE__ */
6636
+ return jsxRuntime.jsxs("svg", {
6637
+ "data-sanity-icon": "stage",
6638
+ fill: "none",
6639
+ height: "1em",
6640
+ viewBox: "0 0 25 25",
6641
+ width: "1em",
6642
+ xmlns: "http://www.w3.org/2000/svg",
6643
+ ...props,
6644
+ children: [
6645
+ /* @__PURE__ */ jsxRuntime.jsx("path", {
6646
+ 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",
6647
+ fill: "currentColor"
6648
+ }),
6649
+ /* @__PURE__ */ jsxRuntime.jsx("path", {
6650
+ 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",
6651
+ fill: "currentColor"
6652
+ }),
6653
+ /* @__PURE__ */ jsxRuntime.jsx("path", {
6654
+ 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",
6655
+ fill: "currentColor"
6656
+ }) ]
6657
+ });
6658
+ }
6659
+
6660
+ function StageFace({completed: completed = !1, detail: detail, glyph: glyph = !0, title: title}) {
6661
+ const tone = completed ? "default" : "primary";
6662
+ /* @__PURE__ */
6663
+ return jsxRuntime.jsxs(ui.Flex, {
6664
+ align: "center",
6665
+ as: "span",
6666
+ gap: 2,
6667
+ children: [ glyph ? /* @__PURE__ */ jsxRuntime.jsx(sanity.TextWithTone, {
6668
+ size: 1,
6669
+ tone: tone,
6670
+ children: completed ? /* @__PURE__ */ jsxRuntime.jsx(CheckmarkCircleFilledIcon, {
6671
+ style: {
6672
+ color: "inherit"
6673
+ }
6674
+ }) : /* @__PURE__ */ jsxRuntime.jsx(StageGlyph, {
6675
+ style: {
6676
+ color: "inherit"
6677
+ }
6678
+ })
6679
+ }) : null,
6680
+ /* @__PURE__ */ jsxRuntime.jsx(sanity.TextWithTone, {
6681
+ size: 1,
6682
+ tone: tone,
6683
+ weight: "medium",
6684
+ children: title
6685
+ }), detail === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
6686
+ muted: !0,
6687
+ size: 1,
6688
+ children: detail
6689
+ }) ]
6690
+ });
6691
+ }
6692
+
6693
+ function StageChip({completed: completed = !1, detail: detail, interactive: interactive = !1, title: title}) {
6694
+ const {color: color} = ui.useTheme_v2();
6695
+ /* @__PURE__ */
6696
+ return jsxRuntime.jsx(ui.Card, {
6697
+ padding: 3,
6698
+ radius: 4,
6699
+ style: {
6700
+ boxShadow: `inset 0 0 0 1px ${completed ? color.badge.default.fg : color.focusRing}`,
6701
+ cursor: interactive ? "help" : "default"
6702
+ },
6703
+ tone: completed ? "default" : "primary",
6704
+ ...interactive ? {
6705
+ tabIndex: 0
6706
+ } : {},
6707
+ children: /* @__PURE__ */ jsxRuntime.jsx(StageFace, {
6708
+ completed: completed,
6709
+ title: title,
6710
+ ...detail === void 0 ? {} : {
6711
+ detail: detail
6712
+ }
6713
+ })
6714
+ });
6715
+ }
6716
+
6717
+ function StartIncompleteBadge({style: style}) {
6718
+ /* @__PURE__ */
6719
+ return jsxRuntime.jsx(ui.Badge, {
6720
+ fontSize: 1,
6721
+ mode: "outline",
6722
+ style: style,
6723
+ tone: "caution",
6724
+ children: "Start incomplete"
6725
+ });
6726
+ }
6727
+
6728
+ function normalizeAbortReason(raw) {
6729
+ const trimmed = raw.trim();
6730
+ return trimmed === "" ? void 0 : trimmed;
6731
+ }
6732
+
6733
+ function abortCommitReport(args) {
6734
+ return args.changed ? {
6735
+ outcome: "aborted",
6736
+ toast: abortedToast(args.title)
6737
+ } : {
6738
+ outcome: "already-settled",
6739
+ toast: abortAlreadySettledToast(args.title)
6740
+ };
6741
+ }
6742
+
6743
+ function abortedToast(title) {
6744
+ return {
6745
+ id: TOAST_ID.abort,
6746
+ status: "info",
6747
+ title: `Aborted “${title}”`
6748
+ };
6749
+ }
6750
+
6751
+ function abortAlreadySettledToast(title) {
6752
+ return {
6753
+ id: TOAST_ID.abort,
6754
+ status: "info",
6755
+ title: `“${title}” had already finished`,
6756
+ description: "Nothing was aborted — the workflow reached a terminal state first."
6757
+ };
6758
+ }
6759
+
6760
+ function abortUnconfirmedToast(args) {
6761
+ return {
6762
+ id: TOAST_ID.abort,
6763
+ status: "warning",
6764
+ title: `Couldn’t confirm “${args.title}” was aborted`,
6765
+ description: `${describeError(args.err)} — the abort may still have committed, so check the workflow’s state before trying again.`
6766
+ };
6767
+ }
6768
+
6769
+ function AbortWorkflowDialog({entry: entry, onClose: onClose}) {
6770
+ 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}`;
6771
+ useLogEventOnMount(WorkflowAbortDialogOpened, {
6772
+ instanceId: instance._id
6773
+ });
6774
+ const confirm = async () => {
6775
+ if (reason === void 0) return;
6776
+ const log = outcome => telemetry2.log(WorkflowAbortDialogSubmitted, {
6777
+ instanceId: instance._id,
6778
+ outcome: outcome
6779
+ });
6780
+ setPending(!0);
6781
+ try {
6782
+ const {changed: changed} = await engine.abortInstance({
6783
+ instanceId: instance._id,
6784
+ reason: reason
6785
+ }), report = abortCommitReport({
6786
+ title: title,
6787
+ changed: changed
6788
+ });
6789
+ toast.push(report.toast), log(report.outcome), onClose();
6790
+ } catch (err) {
6791
+ toast.push(abortUnconfirmedToast({
6792
+ title: title,
6793
+ err: err
6794
+ })), log("unconfirmed"), setPending(!1);
6795
+ }
6796
+ };
6797
+ /* @__PURE__ */
6798
+ return jsxRuntime.jsx(ui.Dialog, {
6799
+ footer: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
6800
+ padding: 3,
6801
+ children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
6802
+ gap: 2,
6803
+ justify: "flex-end",
6804
+ children: [
6805
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
6806
+ disabled: pending,
6807
+ fontSize: 1,
6808
+ mode: "bleed",
6809
+ onClick: onClose,
6810
+ padding: 2,
6811
+ text: "Cancel"
6812
+ }),
6813
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
6814
+ disabled: reason === void 0,
6815
+ fontSize: 1,
6816
+ loading: pending,
6817
+ onClick: () => {
6818
+ confirm();
6819
+ },
6820
+ padding: 2,
6821
+ text: "Abort workflow",
6822
+ tone: "critical"
6823
+ }) ]
6824
+ })
6825
+ }),
6826
+ header: "Abort workflow",
6827
+ id: `abort-workflow-${instance._id}`,
6828
+ onClose: () => {
6829
+ pending || onClose();
6830
+ },
6831
+ width: 0,
6832
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
6833
+ padding: 4,
6834
+ children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
6835
+ gap: 5,
6836
+ children: [
6837
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, {
6838
+ size: 1,
6839
+ children: [ "Abort the ",
6840
+ /* @__PURE__ */ jsxRuntime.jsx("strong", {
6841
+ children: title
6842
+ }), " workflow? This cannot be undone." ]
6843
+ }),
6844
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
6845
+ gap: 3,
6846
+ children: [
6847
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
6848
+ as: "label",
6849
+ htmlFor: reasonInputId,
6850
+ size: 1,
6851
+ weight: "medium",
6852
+ children: "Reason"
6853
+ }),
6854
+ /* @__PURE__ */ jsxRuntime.jsx(ui.TextInput, {
6855
+ autoFocus: !0,
6856
+ fontSize: 1,
6857
+ id: reasonInputId,
6858
+ onChange: event => setTypedReason(event.currentTarget.value),
6859
+ placeholder: "Why is this workflow being stopped?",
6860
+ value: typedReason
6861
+ }) ]
6862
+ }) ]
6863
+ })
6864
+ })
6865
+ });
6866
+ }
6867
+
6868
+ function makeTitleResolver(definition) {
6869
+ const activities = (definition?.stages ?? []).flatMap(s => s.activities ?? []);
6870
+ return {
6871
+ action: (activityName, actionName) => activities.find(t => t.name === activityName)?.actions?.find(a => a.name === actionName)?.title ?? actionName,
6872
+ activity: name => activities.find(t => t.name === name)?.title ?? name,
6873
+ stage: name => stageTitle(definition, name)
6874
+ };
6875
+ }
6876
+
6877
+ function attributed(actor, ...parts) {
6878
+ if (actor) return {
6879
+ actorId: actor.id,
6880
+ parts: parts
6881
+ };
6882
+ const [first, ...rest] = parts;
6883
+ return typeof first != "string" ? {
6884
+ actorId: void 0,
6885
+ parts: parts
6886
+ } : {
6887
+ actorId: void 0,
6888
+ parts: [ first.charAt(0).toUpperCase() + first.slice(1), ...rest ]
6889
+ };
6890
+ }
6891
+
6892
+ function standalone(...parts) {
6893
+ return {
6894
+ actorId: void 0,
6895
+ parts: parts
6896
+ };
6897
+ }
6898
+
6899
+ const historyLiner = {
6900
+ stageEntered: (h, titles) => attributed(h.actor, `entered ${titles.stage(h.stage)}${h.fromStage ? ` from ${titles.stage(h.fromStage)}` : ""}`),
6901
+ stageExited: (h, titles) => attributed(h.actor, `left ${titles.stage(h.stage)} for ${titles.stage(h.toStage)}`),
6902
+ activityStatusChanged: (h, titles) => attributed(h.actor, `changed ${titles.activity(h.activity)}: ${h.from} → ${h.to}`),
6903
+ actionFired: (h, titles) => {
6904
+ const phrase = `fired ${titles.action(h.activity, h.action)} on ${titles.activity(h.activity)}`;
6905
+ return h.triggered ? standalone(`The workflow ${phrase}`) : attributed(h.actor, phrase);
6906
+ },
6907
+ transitionFired: (h, titles) => attributed(h.actor, `moved ${titles.stage(h.fromStage)} → ${titles.stage(h.toStage)}`),
6908
+ effectQueued: h => standalone("Effect ", {
6909
+ code: h.effect
6910
+ }, " queued"),
6911
+ effectCompleted: h => {
6912
+ const detail = h.detail ? ` — ${h.detail}` : "";
6913
+ return h.actor ? attributed(h.actor, "resolved effect ", {
6914
+ code: h.effect
6915
+ }, ` — ${h.status}${detail}`) : standalone("Effect ", {
6916
+ code: h.effect
6917
+ }, ` ${h.status}${detail}`);
6918
+ },
6919
+ effectClaimReleased: h => attributed(h.actor, "released a stale claim on effect ", {
6920
+ code: h.effect
6921
+ }, ` ${h.via === "sweep" ? "via the sweeper" : "via a drain takeover"}`),
6922
+ spawned: (h, titles) => attributed(h.actor, `spawned a child workflow from ${titles.activity(h.activity)}`),
6923
+ subworkflowAdopted: (h, titles) => standalone(`Re-adopted child workflow into ${titles.activity(h.activity)} on re-entering ${titles.stage(h.stage)}`),
6924
+ subworkflowResolved: (h, titles) => standalone(`Child workflow of ${titles.activity(h.activity)} ${h.status === "done" ? "completed" : "was aborted"}`),
6925
+ subworkflowOrphaned: h => standalone(`Orphaned child workflow reached terminal — ${h.detail}`),
6926
+ aborted: (h, titles) => attributed(h.actor, `aborted the workflow at ${titles.stage(h.stage)}${h.reason ? ` — ${h.reason}` : ""}`),
6927
+ 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 ", {
6928
+ code: h.opType
6929
+ }),
6930
+ fieldQueryDiscarded: h => standalone({
6931
+ code: JSON.stringify(h)
6932
+ })
6933
+ };
6934
+
6935
+ function historyLine(h, titles) {
6936
+ return historyLiner[h._type](h, titles);
6937
+ }
6938
+
6939
+ function CodeChip({value: value}) {
6940
+ /* @__PURE__ */
6941
+ return jsxRuntime.jsx("code", {
6942
+ style: {
6943
+ overflowWrap: "anywhere"
6944
+ },
6945
+ children: value
6946
+ });
6947
+ }
6948
+
6949
+ function HintedMenuButton({hint: hint, ...menuButtonProps}) {
6950
+ const [open, setOpen] = react.useState(!1), popover = {
6951
+ tone: "default",
6952
+ ...menuButtonProps.popover?.placement === void 0 ? {
6953
+ placement: "bottom-end",
6954
+ fallbackPlacements: [ "top-end" ]
6955
+ } : {},
6956
+ ...menuButtonProps.popover
6957
+ };
6958
+ return hint === void 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.MenuButton, {
6959
+ ...menuButtonProps,
6960
+ popover: popover
6961
+ }) : /* @__PURE__ */ jsxRuntime.jsx(HoverHint, {
6962
+ disabled: open,
6963
+ text: hint,
6964
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.MenuButton, {
6965
+ ...menuButtonProps,
6966
+ onClose: () => setOpen(!1),
6967
+ onOpen: () => setOpen(!0),
6968
+ popover: popover
6969
+ })
6970
+ });
6971
+ }
6972
+
6973
+ function historyWindow(args) {
6974
+ const {entries: entries, expanded: expanded} = args;
6975
+ return {
6976
+ overflows: entries.length > 6,
6977
+ shown: expanded ? entries : entries.slice(0, 6)
6978
+ };
6979
+ }
6980
+
6981
+ function PendingEffectRows({instance: instance, now: now}) {
6982
+ const {drainEffectsFor: drainEffectsFor, completeEffectFor: completeEffectFor, effectHandlers: effectHandlers} = useWorkflowContext(), toast = useWorkflowToast(), [busy, setBusy] = react.useState(!1), pending = instance.pendingEffects ?? [];
6983
+ if (pending.length === 0) return null;
6984
+ const runRegistered = async () => {
6985
+ setBusy(!0);
6986
+ try {
6987
+ await drainEffectsFor(instance._id), toast.push({
6988
+ id: TOAST_ID.effectsDrain,
6989
+ status: "info",
6990
+ title: "Ran the registered handlers"
6991
+ });
6992
+ } catch (err) {
6993
+ toast.push({
6994
+ id: TOAST_ID.effectsDrain,
6995
+ status: "error",
6996
+ title: "Failed to run pending effects",
6997
+ description: describeError(err)
6998
+ });
6999
+ } finally {
7000
+ setBusy(!1);
7001
+ }
7002
+ }, resolve = async (effectKey, status) => {
7003
+ setBusy(!0);
7004
+ try {
7005
+ await completeEffectFor(instance._id, {
7006
+ effectKey: effectKey,
7007
+ status: status,
7008
+ detail: "Resolved in Studio"
7009
+ }), toast.push({
7010
+ id: TOAST_ID.effectResolve,
7011
+ status: "info",
7012
+ title: `Effect marked as ${status}`
7013
+ });
7014
+ } catch (err) {
7015
+ toast.push({
7016
+ id: TOAST_ID.effectResolve,
7017
+ status: "error",
7018
+ title: "Failed to resolve the effect",
7019
+ description: describeError(err)
7020
+ });
7021
+ } finally {
7022
+ setBusy(!1);
7023
+ }
7024
+ };
7025
+ /* @__PURE__ */
7026
+ return jsxRuntime.jsx(jsxRuntime.Fragment, {
7027
+ children: pending.map(fx => /* @__PURE__ */ jsxRuntime.jsx(PendingEffectRow, {
7028
+ busy: busy,
7029
+ effect: fx,
7030
+ instanceId: instance._id,
7031
+ now: now,
7032
+ onResolve: status => resolve(fx._key, status),
7033
+ onRunHandlers: runRegistered,
7034
+ registered: fx.name in effectHandlers
7035
+ }, fx._key))
7036
+ });
7037
+ }
7038
+
7039
+ function PendingEffectRow({busy: busy, effect: effect, instanceId: instanceId, now: now, onResolve: onResolve, onRunHandlers: onRunHandlers, registered: registered}) {
7040
+ const label = effect.title ?? effect.name, avatarSize = useAvatarSize();
7041
+ /* @__PURE__ */
7042
+ return jsxRuntime.jsxs(ui.Flex, {
7043
+ align: "center",
7044
+ gap: 2,
7045
+ children: [
7046
+ /* @__PURE__ */ jsxRuntime.jsx(FeedGlyph, {
7047
+ hint: "Waiting to run",
7048
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Clock.ClockIcon, {})
7049
+ }),
7050
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
7051
+ align: "center",
7052
+ flex: 1,
7053
+ gap: 1,
7054
+ style: {
7055
+ minWidth: 0
7056
+ },
7057
+ children: [
7058
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
7059
+ style: {
7060
+ minWidth: 0
7061
+ },
7062
+ children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, {
7063
+ size: 1,
7064
+ textOverflow: "ellipsis",
7065
+ children: [ effect.title ?? /* @__PURE__ */ jsxRuntime.jsx(CodeChip, {
7066
+ value: effect.name
7067
+ }), registered ? " — ready to run in Studio" : " — waiting for the runtime" ]
7068
+ })
7069
+ }),
7070
+ /* @__PURE__ */ jsxRuntime.jsx(FeedStamp, {
7071
+ at: effect.queuedAt,
7072
+ now: now
7073
+ }) ]
7074
+ }),
7075
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
7076
+ align: "center",
7077
+ flex: "none",
7078
+ style: {
7079
+ height: avatarSize
7080
+ },
7081
+ children: /* @__PURE__ */ jsxRuntime.jsx(HintedMenuButton, {
7082
+ button: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
7083
+ "aria-label": `Resolve ${label}`,
7084
+ disabled: busy,
7085
+ fontSize: 1,
7086
+ icon: EllipsisHorizontal.EllipsisHorizontalIcon,
7087
+ mode: "bleed",
7088
+ padding: 2
7089
+ }),
7090
+ hint: "Resolve",
7091
+ id: `pending-effect-menu-${instanceId}-${effect._key}`,
7092
+ menu: /* @__PURE__ */ jsxRuntime.jsxs(ui.Menu, {
7093
+ children: [ registered ? /* @__PURE__ */ jsxRuntime.jsx(ui.MenuItem, {
7094
+ onClick: onRunHandlers,
7095
+ text: "Run registered handlers"
7096
+ }) : null,
7097
+ /* @__PURE__ */ jsxRuntime.jsx(ui.MenuItem, {
7098
+ onClick: () => onResolve("done"),
7099
+ text: "Mark done"
7100
+ }),
7101
+ /* @__PURE__ */ jsxRuntime.jsx(ui.MenuItem, {
7102
+ onClick: () => onResolve("failed"),
7103
+ text: "Mark failed",
7104
+ tone: "critical"
7105
+ }) ]
7106
+ }),
7107
+ popover: {
7108
+ placement: "bottom-end",
7109
+ portal: !0
7110
+ }
7111
+ })
7112
+ }) ]
7113
+ });
7114
+ }
7115
+
7116
+ function ActivityLog({instance: instance, definition: definition, windowed: windowed = !0}) {
7117
+ 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);
7118
+ react.useEffect(() => {
7119
+ const timer = setInterval(() => setNow(/* @__PURE__ */ new Date), 6e4);
7120
+ return () => clearInterval(timer);
7121
+ }, []);
7122
+ const history = historyWindow({
7123
+ entries: entries,
7124
+ expanded: expanded || !windowed
7125
+ });
7126
+ return entries.length === 0 && (instance.pendingEffects ?? []).length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
7127
+ muted: !0,
7128
+ size: 1,
7129
+ children: "No activity yet"
7130
+ }) : /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
7131
+ gap: 3,
7132
+ children: [
7133
+ /* @__PURE__ */ jsxRuntime.jsx(PendingEffectRows, {
7134
+ instance: instance,
7135
+ now: now
7136
+ }), history.shown.map(h => /* @__PURE__ */ jsxRuntime.jsx(HistoryRow, {
7137
+ entry: h,
7138
+ now: now,
7139
+ titles: titles
7140
+ }, h._key)), windowed && history.overflows ? /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
7141
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
7142
+ fontSize: 1,
7143
+ mode: "bleed",
7144
+ onClick: () => setExpanded(!expanded),
7145
+ padding: 2,
7146
+ text: expanded ? "Show less history" : "Show all history"
7147
+ })
7148
+ }) : null ]
7149
+ });
7150
+ }
7151
+
7152
+ function FeedStamp({at: at, now: now}) {
7153
+ /* @__PURE__ */
7154
+ return jsxRuntime.jsxs(ui.Flex, {
7155
+ align: "center",
7156
+ flex: "none",
7157
+ gap: 1,
7158
+ children: [
7159
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
7160
+ muted: !0,
7161
+ size: 1,
7162
+ children: "·"
7163
+ }),
7164
+ /* @__PURE__ */ jsxRuntime.jsx(HoverHint, {
7165
+ text: formatDateTime(at),
7166
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
7167
+ muted: !0,
7168
+ size: 1,
7169
+ style: {
7170
+ whiteSpace: "nowrap"
7171
+ },
7172
+ children: formatShortAgo(at, now)
7173
+ })
7174
+ }) ]
7175
+ });
7176
+ }
7177
+
7178
+ function HistoryRow({entry: entry, now: now, titles: titles}) {
7179
+ const line = historyLine(entry, titles);
7180
+ /* @__PURE__ */
7181
+ return jsxRuntime.jsxs(ui.Flex, {
7182
+ align: "center",
7183
+ gap: 2,
7184
+ children: [ line.actorId === void 0 ? /* @__PURE__ */ jsxRuntime.jsx(FeedGlyph, {
7185
+ hint: "The workflow",
7186
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Cog.CogIcon, {})
7187
+ }) : /* @__PURE__ */ jsxRuntime.jsx(UserAvatar, {
7188
+ id: line.actorId
7189
+ }),
7190
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
7191
+ align: "center",
7192
+ flex: 1,
7193
+ gap: 1,
7194
+ style: {
7195
+ minWidth: 0
7196
+ },
7197
+ children: [
7198
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
7199
+ style: {
7200
+ minWidth: 0
7201
+ },
7202
+ children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, {
7203
+ muted: !0,
7204
+ size: 1,
7205
+ textOverflow: "ellipsis",
7206
+ children: [ line.actorId === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
7207
+ children: [
7208
+ /* @__PURE__ */ jsxRuntime.jsx(ActorNameSpan, {
7209
+ id: line.actorId
7210
+ }), " " ]
7211
+ }), line.parts.map((part, index) => typeof part == "string" ? part : /* @__PURE__ */ jsxRuntime.jsx(CodeChip, {
7212
+ value: part.code
7213
+ }, index)) ]
7214
+ })
7215
+ }),
7216
+ /* @__PURE__ */ jsxRuntime.jsx(FeedStamp, {
7217
+ at: entry.at,
7218
+ now: now
7219
+ }) ]
7220
+ }) ]
7221
+ });
7222
+ }
7223
+
7224
+ function ActorNameSpan({id: id}) {
7225
+ const {name: name} = useUserDisplay(id), {font: font} = ui.useTheme_v2();
7226
+ /* @__PURE__ */
7227
+ return jsxRuntime.jsx("span", {
7228
+ style: {
7229
+ fontWeight: font.text.weights.medium
7230
+ },
7231
+ children: name
7232
+ });
7233
+ }
7234
+
7235
+ function FeedGlyph({hint: hint, icon: icon}) {
7236
+ const size = useAvatarSize();
7237
+ /* @__PURE__ */
7238
+ return jsxRuntime.jsx(HoverHint, {
7239
+ text: hint,
7240
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
7241
+ align: "center",
7242
+ flex: "none",
7243
+ justify: "center",
7244
+ style: {
7245
+ height: size,
7246
+ width: size
7247
+ },
7248
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
7249
+ muted: !0,
7250
+ size: 1,
7251
+ children: icon
7252
+ })
7253
+ })
7254
+ });
7255
+ }
7256
+
7257
+ function InstanceHistoryDialog({entry: entry, onClose: onClose}) {
7258
+ const definition = useDefinition(entry), {instance: instance} = entry;
7259
+ /* @__PURE__ */
7260
+ return jsxRuntime.jsx(ui.Dialog, {
7261
+ header: /* @__PURE__ */ jsxRuntime.jsx(Breadcrumb, {
7262
+ emphasizeCurrent: !0,
7263
+ segments: [ instanceTitle(instance, definition), "History" ]
7264
+ }),
7265
+ id: `workflow-instance-history-${instance._id}`,
7266
+ onClose: onClose,
7267
+ width: 1,
7268
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
7269
+ padding: 4,
7270
+ children: /* @__PURE__ */ jsxRuntime.jsx(ActivityLog, {
7271
+ definition: definition,
7272
+ instance: instance,
7273
+ windowed: !1
7274
+ })
7275
+ })
7276
+ });
7277
+ }
7278
+
7279
+ function InstanceCardMenu({entry: entry, title: title}) {
7280
+ const [dialog, setDialog] = react.useState(void 0), menuId = react.useId(), close = () => setDialog(void 0);
7281
+ /* @__PURE__ */
7282
+ return jsxRuntime.jsxs(jsxRuntime.Fragment, {
7283
+ children: [
7284
+ /* @__PURE__ */ jsxRuntime.jsx(ui.MenuButton, {
7285
+ button:
7286
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
7287
+ "aria-label": `More options for ${title}`,
7288
+ fontSize: 1,
7289
+ icon: EllipsisHorizontal.EllipsisHorizontalIcon,
7290
+ mode: "bleed",
7291
+ padding: 2
7292
+ }),
7293
+ id: `workflow-instance-menu-${menuId}`,
7294
+ menu: /* @__PURE__ */ jsxRuntime.jsxs(ui.Menu, {
7295
+ children: [
7296
+ /* @__PURE__ */ jsxRuntime.jsx(ui.MenuItem, {
7297
+ onClick: () => setDialog("history"),
7298
+ text: "Workflow history"
7299
+ }), isLiveEntry(entry) ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
7300
+ children: [
7301
+ /* @__PURE__ */ jsxRuntime.jsx(ui.MenuDivider, {}),
7302
+ /* @__PURE__ */ jsxRuntime.jsx(ui.MenuItem, {
7303
+ onClick: () => setDialog("abort"),
7304
+ text: "Abort workflow…",
7305
+ tone: "critical"
7306
+ }) ]
7307
+ }) : null ]
7308
+ }),
7309
+ popover: {
7310
+ placement: "bottom-end",
7311
+ portal: !0
7312
+ }
7313
+ }), dialog === "history" ? /* @__PURE__ */ jsxRuntime.jsx(InstanceHistoryDialog, {
7314
+ entry: entry,
7315
+ onClose: close
7316
+ }) : null, dialog === "abort" ? /* @__PURE__ */ jsxRuntime.jsx(AbortWorkflowDialog, {
7317
+ entry: entry,
7318
+ onClose: close
7319
+ }) : null ]
7320
+ });
7321
+ }
7322
+
7323
+ function InstanceCard({entry: entry, children: children, defaultOpen: defaultOpen}) {
7324
+ 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();
7325
+ /* @__PURE__ */
7326
+ return jsxRuntime.jsxs(ui.Card, {
7327
+ border: !0,
7328
+ overflow: "hidden",
7329
+ radius: 4,
7330
+ children: [
7331
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Box, {
7332
+ style: {
7333
+ position: "relative"
7334
+ },
7335
+ children: [
7336
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Card, {
7337
+ "aria-expanded": open,
7338
+ as: "button",
7339
+ onClick: () => setOpen(value => !value),
7340
+ padding: 3,
7341
+ style: {
7342
+ display: "block",
7343
+ textAlign: "left",
7344
+ width: "100%"
7345
+ },
7346
+ ...open ? {
7347
+ tone: "transparent"
7348
+ } : {},
7349
+ children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
7350
+ align: "center",
7351
+ gap: 3,
7352
+ children: [
7353
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
7354
+ muted: !0,
7355
+ size: 1,
7356
+ children: open ? /* @__PURE__ */ jsxRuntime.jsx(ChevronDown.ChevronDownIcon, {}) : /* @__PURE__ */ jsxRuntime.jsx(ChevronRight.ChevronRightIcon, {})
7357
+ }),
7358
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
7359
+ flex: 1,
7360
+ gap: 2,
7361
+ style: {
7362
+ minWidth: 0
7363
+ },
7364
+ children: [
7365
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
7366
+ size: 1,
7367
+ textOverflow: "ellipsis",
7368
+ weight: "medium",
7369
+ children: title
7370
+ }),
7371
+ /* @__PURE__ */ jsxRuntime.jsx(HeaderStage, {
7372
+ entry: entry
7373
+ }) ]
7374
+ }),
7375
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
7376
+ align: "center",
7377
+ flex: "none",
7378
+ children: [
7379
+ /* @__PURE__ */ jsxRuntime.jsx(HeaderBadges, {
7380
+ instance: instance,
7381
+ settled: settled
7382
+ }),
7383
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
7384
+ flex: "none",
7385
+ style: {
7386
+ width: menuSlot
7387
+ }
7388
+ }) ]
7389
+ }) ]
7390
+ })
7391
+ }),
7392
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
7393
+ align: "center",
7394
+ style: {
7395
+ bottom: 0,
7396
+ position: "absolute",
7397
+ right: 0,
7398
+ top: 0
7399
+ },
7400
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
7401
+ paddingRight: 3,
7402
+ children: /* @__PURE__ */ jsxRuntime.jsx(InstanceCardMenu, {
7403
+ entry: entry,
7404
+ title: title
7405
+ })
7406
+ })
7407
+ }) ]
7408
+ }), open ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
7409
+ children: [
7410
+ /* @__PURE__ */ jsxRuntime.jsx(Hairline, {
7411
+ weight: 1
7412
+ }),
7413
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
7414
+ padding: 3,
7415
+ children: children
7416
+ }) ]
7417
+ }) : null ]
6670
7418
  });
6671
7419
  }
6672
7420
 
6673
- function StageGlyph(props) {
7421
+ function HeaderStage({entry: entry}) {
7422
+ const definition = useDefinition(entry), badgeTrim = useBadgeCapTrim(), face = instanceStageFace({
7423
+ definition: definition,
7424
+ instance: entry.instance
7425
+ });
6674
7426
  /* @__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,
6683
- 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
- }) ]
7427
+ return jsxRuntime.jsx(ui.Flex, {
7428
+ align: "center",
7429
+ children: face === void 0 ? /* @__PURE__ */ jsxRuntime.jsx(StartIncompleteBadge, {
7430
+ style: badgeTrim
7431
+ }) : /* @__PURE__ */ jsxRuntime.jsx(StageFace, {
7432
+ ...face.detail === void 0 ? {} : {
7433
+ detail: face.detail
7434
+ },
7435
+ completed: face.completed,
7436
+ glyph: !1,
7437
+ title: face.title
7438
+ })
6696
7439
  });
6697
7440
  }
6698
7441
 
6699
- function StageFace({completed: completed = !1, detail: detail, title: title}) {
6700
- const tone = completed ? "default" : "primary";
7442
+ function HeaderBadges({instance: instance, settled: settled}) {
7443
+ const badgeTrim = useBadgeCapTrim();
6701
7444
  /* @__PURE__ */
6702
7445
  return jsxRuntime.jsxs(ui.Flex, {
6703
7446
  align: "center",
6704
- as: "span",
7447
+ flex: "none",
6705
7448
  gap: 2,
7449
+ style: badgeTrim,
6706
7450
  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
7451
+ /* @__PURE__ */ jsxRuntime.jsx(AbortedBadge, {
7452
+ instance: instance
7453
+ }), settled ? null : /* @__PURE__ */ jsxRuntime.jsx(OlderDefinitionBadge, {
7454
+ instance: instance
6729
7455
  }) ]
6730
7456
  });
6731
7457
  }
6732
7458
 
6733
- function StageChip({completed: completed = !1, detail: detail, interactive: interactive = !1, title: title}) {
6734
- const {color: color} = ui.useTheme_v2();
7459
+ function PartOfBand({instance: instance}) {
7460
+ const parentRef = instance.ancestors.at(-1), parentId = parentRef ? workflowEngine.toBareId(parentRef.id) : null, parentEntry = useWorkflowInstanceEntry(parentId), parentDefinition = useDefinition(parentEntry);
7461
+ if (!parentId) return null;
7462
+ const title = parentEntry ? instanceTitle(parentEntry.instance, parentDefinition) : parentId;
6735
7463
  /* @__PURE__ */
6736
7464
  return jsxRuntime.jsx(ui.Card, {
7465
+ border: !0,
6737
7466
  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
- }
7467
+ radius: 3,
7468
+ tone: "primary",
7469
+ children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
7470
+ align: "center",
7471
+ gap: 2,
7472
+ children: [
7473
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
7474
+ size: 1,
7475
+ children: /* @__PURE__ */ jsxRuntime.jsx(ArrowUp.ArrowUpIcon, {})
7476
+ }),
7477
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, {
7478
+ size: 1,
7479
+ children: [ "Part of ",
7480
+ /* @__PURE__ */ jsxRuntime.jsx("strong", {
7481
+ children: title
7482
+ }) ]
7483
+ }) ]
6753
7484
  })
6754
7485
  });
6755
7486
  }
@@ -6796,20 +7527,23 @@ function SpineNodeView({definition: definition, node: node, transitions: transit
6796
7527
  transitions: transitions
6797
7528
  })
6798
7529
  });
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
- });
7530
+ if (node.state === "current") {
7531
+ const detail = roundDetail(node.round);
7532
+ /* @__PURE__ */
7533
+ return jsxRuntime.jsx(HoverHint, {
7534
+ content: card,
7535
+ "data-testid": `spine-node-${node.name}`,
7536
+ flush: !0,
7537
+ children: /* @__PURE__ */ jsxRuntime.jsx(StageChip, {
7538
+ ...detail === void 0 ? {} : {
7539
+ detail: detail
7540
+ },
7541
+ completed: node.completedAt !== void 0,
7542
+ interactive: !0,
7543
+ title: node.title
7544
+ })
7545
+ });
7546
+ }
6813
7547
  const Icon = NODE_ICON[node.state];
6814
7548
  /* @__PURE__ */
6815
7549
  return jsxRuntime.jsx(HoverHint, {
@@ -6960,20 +7694,13 @@ function StampLines({stamp: stamp}) {
6960
7694
 
6961
7695
  function WorkflowInstanceSection({defaultOpen: defaultOpen, entry: entry, onOpenActivity: onOpenActivity}) {
6962
7696
  /* @__PURE__ */
6963
- return jsxRuntime.jsx(InstanceAccordion, {
7697
+ return jsxRuntime.jsx(InstanceCard, {
6964
7698
  defaultOpen: defaultOpen,
6965
7699
  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
- }) ]
7700
+ children: /* @__PURE__ */ jsxRuntime.jsx(InstanceSnapshotBody, {
7701
+ entry: entry,
7702
+ onOpenActivity: onOpenActivity,
7703
+ surface: "document-view"
6977
7704
  })
6978
7705
  });
6979
7706
  }
@@ -7000,7 +7727,9 @@ function InstanceSnapshotBody({entry: entry, onOpenActivity: onOpenActivity, sur
7000
7727
  /* @__PURE__ */ jsxRuntime.jsx(ui.Card, {
7001
7728
  borderBottom: !0,
7002
7729
  padding: 2,
7003
- tone: definition ? "neutral" : "caution",
7730
+ ...definition ? {} : {
7731
+ tone: "caution"
7732
+ },
7004
7733
  children: definition ? /* @__PURE__ */ jsxRuntime.jsx(WorkflowSpine, {
7005
7734
  definition: definition,
7006
7735
  evaluation: entry.evaluation,
@@ -7175,30 +7904,6 @@ function openActivityGone(args) {
7175
7904
  return evaluation !== void 0 && !evaluation.currentStage.activities.some(a => a.activity.name === target.activityName);
7176
7905
  }
7177
7906
 
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
7907
  function subjectGdr(ctx) {
7203
7908
  return !ctx.subjectDocId || !ctx.mapping ? null : subjectGdrRef({
7204
7909
  mapping: ctx.mapping,
@@ -8018,7 +8723,7 @@ function DiscoverySpinner() {
8018
8723
  });
8019
8724
  }
8020
8725
 
8021
- const BOOT_CUE_DELAY_MS = 400, GROUP_GAP = 1;
8726
+ const BOOT_CUE_DELAY_MS = 400, GROUP_GAP = 2;
8022
8727
 
8023
8728
  function useWorkflowsTab() {
8024
8729
  const {params: params, setParams: setParams} = structure.usePaneRouter();
@@ -8899,27 +9604,19 @@ function logOnce(messages, logged) {
8899
9604
  }
8900
9605
 
8901
9606
  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
- };
9607
+ const [open, setOpen] = react.useState(!1), remove = index => onChange(value.filter((_, i) => i !== index));
8911
9608
  /* @__PURE__ */
8912
9609
  return jsxRuntime.jsxs(ui.Stack, {
8913
9610
  gap: 2,
8914
9611
  children: [ value.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
8915
9612
  gap: 2,
8916
9613
  wrap: "wrap",
8917
- children: value.map((a, i) => /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
9614
+ children: value.map((assignee, index) => /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
8918
9615
  align: "center",
8919
9616
  gap: 1,
8920
9617
  children: [
8921
9618
  /* @__PURE__ */ jsxRuntime.jsx(AssigneeBadge, {
8922
- assignee: a
9619
+ assignee: assignee
8923
9620
  }),
8924
9621
  /* @__PURE__ */ jsxRuntime.jsx(HoverHint, {
8925
9622
  text: "Remove",
@@ -8928,60 +9625,33 @@ function AssigneesInput({value: value, onChange: onChange}) {
8928
9625
  fontSize: 1,
8929
9626
  icon: Close.CloseIcon,
8930
9627
  mode: "bleed",
8931
- onClick: () => remove(i),
9628
+ onClick: () => remove(index),
8932
9629
  padding: 2
8933
9630
  })
8934
9631
  }) ]
8935
- }, a.type === "user" ? `user:${a.id}` : `role:${a.role}`))
9632
+ }, assignee.type === "user" ? `user:${assignee.id}` : `role:${assignee.role}`))
8936
9633
  }) : null,
8937
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
9634
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
8938
9635
  align: "center",
8939
9636
  gap: 2,
8940
9637
  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
9638
+ children: /* @__PURE__ */ jsxRuntime.jsx(DismissablePopover, {
9639
+ content: /* @__PURE__ */ jsxRuntime.jsx(AssigneePicker, {
9640
+ onChange: next => onChange([ ...next ]),
9641
+ value: value
8946
9642
  }),
8947
- onDismiss: () => setMembersOpen(!1),
8948
- open: membersOpen,
9643
+ onDismiss: () => setOpen(!1),
9644
+ open: open,
8949
9645
  placement: "bottom-start",
8950
9646
  children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
8951
9647
  fontSize: 1,
8952
9648
  icon: User.UserIcon,
8953
9649
  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",
9650
+ onClick: () => setOpen(v => !v),
8963
9651
  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))
9652
+ text: "Assign"
8979
9653
  })
8980
- }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
8981
- muted: !0,
8982
- size: 1,
8983
- children: "No project roles found"
8984
- }) ]
9654
+ })
8985
9655
  }) ]
8986
9656
  });
8987
9657
  }
@@ -9911,17 +10581,6 @@ function makePerspectiveBadge(documentId) {
9911
10581
  return WorkflowPerspectiveBadge;
9912
10582
  }
9913
10583
 
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
10584
  const GLANCE_CAP = 3;
9926
10585
 
9927
10586
  function AssignedTasksHint({work: work}) {
@@ -10433,15 +11092,19 @@ function WorkflowRootInput(props) {
10433
11092
  });
10434
11093
  }
10435
11094
 
11095
+ exports.AbortWorkflowDialog = AbortWorkflowDialog;
11096
+
10436
11097
  exports.ActivityDetailDialog = ActivityDetailDialog;
10437
11098
 
11099
+ exports.ActivityLog = ActivityLog;
11100
+
10438
11101
  exports.ActivityRow = ActivityRow;
10439
11102
 
10440
11103
  exports.BreadcrumbTail = BreadcrumbTail;
10441
11104
 
10442
11105
  exports.CautionNote = CautionNote;
10443
11106
 
10444
- exports.CollapsibleBand = CollapsibleBand;
11107
+ exports.CodeChip = CodeChip;
10445
11108
 
10446
11109
  exports.CountedLabel = CountedLabel;
10447
11110
 
@@ -10457,8 +11120,6 @@ exports.ForMeEmptyState = ForMeEmptyState;
10457
11120
 
10458
11121
  exports.Hairline = Hairline;
10459
11122
 
10460
- exports.HintedMenuButton = HintedMenuButton;
10461
-
10462
11123
  exports.HoverHint = HoverHint;
10463
11124
 
10464
11125
  exports.InstanceSnapshotBody = InstanceSnapshotBody;
@@ -10485,20 +11146,12 @@ exports.TOOL_TABS = TOOL_TABS;
10485
11146
 
10486
11147
  exports.TabSwitch = TabSwitch;
10487
11148
 
10488
- exports.TrailingHairline = TrailingHairline;
10489
-
10490
11149
  exports.UnreadableDocsNote = UnreadableDocsNote;
10491
11150
 
10492
- exports.UserAvatar = UserAvatar;
10493
-
10494
11151
  exports.WORKFLOW_API_VERSION = WORKFLOW_API_VERSION;
10495
11152
 
10496
11153
  exports.WORKFLOW_PAGE_TABS = WORKFLOW_PAGE_TABS;
10497
11154
 
10498
- exports.WorkflowAbortDialogOpened = WorkflowAbortDialogOpened;
10499
-
10500
- exports.WorkflowAbortDialogSubmitted = WorkflowAbortDialogSubmitted;
10501
-
10502
11155
  exports.WorkflowBoardWorkflowSelected = WorkflowBoardWorkflowSelected;
10503
11156
 
10504
11157
  exports.WorkflowDefinitionDetailViewed = WorkflowDefinitionDetailViewed;
@@ -10513,7 +11166,7 @@ exports.WorkflowToolOpened = WorkflowToolOpened;
10513
11166
 
10514
11167
  exports.activityRowProps = activityRowProps;
10515
11168
 
10516
- exports.assigneeUserIdsOf = assigneeUserIdsOf;
11169
+ exports.assigneesOf = assigneesOf;
10517
11170
 
10518
11171
  exports.backToTabLabel = backToTabLabel;
10519
11172
 
@@ -10537,10 +11190,6 @@ exports.findActivityNode = findActivityNode;
10537
11190
 
10538
11191
  exports.formatDate = formatDate;
10539
11192
 
10540
- exports.formatDateTime = formatDateTime;
10541
-
10542
- exports.formatShortAgo = formatShortAgo;
10543
-
10544
11193
  exports.formatShortDateTime = formatShortDateTime;
10545
11194
 
10546
11195
  exports.formatTimeAgo = formatTimeAgo;
@@ -10591,8 +11240,6 @@ exports.toolTabState = toolTabState;
10591
11240
 
10592
11241
  exports.useAssignmentIdentity = useAssignmentIdentity;
10593
11242
 
10594
- exports.useAvatarSize = useAvatarSize;
10595
-
10596
11243
  exports.useBadgeCapTrim = useBadgeCapTrim;
10597
11244
 
10598
11245
  exports.useContainerToken = useContainerToken;
@@ -10607,8 +11254,6 @@ exports.useProjectMembers = useProjectMembers;
10607
11254
 
10608
11255
  exports.useSpaceToken = useSpaceToken;
10609
11256
 
10610
- exports.useUserDisplay = useUserDisplay;
10611
-
10612
11257
  exports.useUserDisplays = useUserDisplays;
10613
11258
 
10614
11259
  exports.useWorkflowContext = useWorkflowContext;