@sanity/workflow-studio-plugin 0.26.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.
@@ -2,7 +2,7 @@ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
2
 
3
3
  import { TimelineIcon } from "@sanity/icons/Timeline";
4
4
 
5
- import { Popover, Tooltip, Box, Stack, Text, useClickOutsideEvent, Flex, TextInput, Button, Select, Checkbox, Autocomplete, Card, TextArea, useToast, Dialog, Switch, TextSkeleton, Code, useTheme_v2, Spinner, Badge, MenuButton, Menu, MenuItem, useElementSize, TabList, Tab, TabPanel } from "@sanity/ui";
5
+ import { Popover, Tooltip, Box, Stack, Text, useClickOutsideEvent, Flex, TextInput, Button, Select, Checkbox, Autocomplete, Card, TextArea, useToast, Dialog, Switch, TextSkeleton, Code, useTheme_v2, Spinner, Badge, MenuButton, Menu, MenuItem, useElementSize, MenuDivider, TabList, Tab, TabPanel } from "@sanity/ui";
6
6
 
7
7
  import { editFieldTarget, useWorkflowTelemetry, useRefcountedIds } from "@sanity/workflow-react";
8
8
 
@@ -10,7 +10,7 @@ import { createContext, useContext, useEffect, useSyncExternalStore, useCallback
10
10
 
11
11
  import { usePaneRouter } from "sanity/structure";
12
12
 
13
- import { WORKFLOW_INSTANCE_TYPE, WORKFLOW_DEFINITION_TYPE, GUARD_DOC_TYPE, tryParseGdr, resourceFromParsed, latestDeployedDefinitions, isStartableDefinition, isSubjectEntry, isInputSourced, acceptsDocumentType, initialFieldIssues, gdrRef, releaseRef, refKindAcceptsTypes, rejectedRefTypes, ActionDisabledError, MutationGuardDeniedError, EditFieldDeniedError, errorMessage, terminalState, findOpenStageEntry, actionRendering, isTodoListEntry, isTodoListItem, isTerminalActivityStatus, describeCondition, sentenceCase, checklistLines, findCurrentActivityEntry, ENGINE_API_VERSION, scalarValidationIssues, classifyPrincipalId, toBareId, isSingleDocRefEntry, isGdr, resolveFieldEntry, isSingleDocRefKind, isNotesEntry, parseDefinitionSnapshot, isUnprimed, isTerminalStage, DEFAULT_TRANSITION_WHEN, instancesQuery, assertReadableModel, projectStartSliceRow, StartNotSettledError, StartNotAllowedError, humanize, unboundRequirementReads, explainStartRequirement, singleSubjectRequirementRefused, evaluateStartFilter, startKindOf, hasSingleSubjectRequirement, readsRootDocument, latestDefinitionsGroq, gdrFromResource, subscriptionDocumentsForInstance, aclPathForResource, definitionLookupGroq, instanceDocId, missingRequiredInputs, documentActionDenials } from "@sanity/workflow-engine";
13
+ import { WORKFLOW_INSTANCE_TYPE, WORKFLOW_DEFINITION_TYPE, GUARD_DOC_TYPE, tryParseGdr, resourceFromParsed, latestDeployedDefinitions, isStartableDefinition, isSubjectEntry, isInputSourced, acceptsDocumentType, initialFieldIssues, gdrRef, releaseRef, refKindAcceptsTypes, rejectedRefTypes, ActionDisabledError, MutationGuardDeniedError, EditFieldDeniedError, errorMessage, terminalState, findOpenStageEntry, actionRendering, isTodoListEntry, isTodoListItem, isTerminalActivityStatus, describeCondition, sentenceCase, checklistLines, findCurrentActivityEntry, ENGINE_API_VERSION, scalarValidationIssues, classifyPrincipalId, userLoginProvider, toBareId, isSingleDocRefEntry, isGdr, resolveFieldEntry, isSingleDocRefKind, isNotesEntry, parseDefinitionSnapshot, isUnprimed, isTerminalStage, DEFAULT_TRANSITION_WHEN, instancesQuery, assertReadableModel, projectStartSliceRow, StartNotSettledError, StartNotAllowedError, humanize, unboundRequirementReads, explainStartRequirement, singleSubjectRequirementRefused, evaluateStartFilter, startKindOf, hasSingleSubjectRequirement, readsRootDocument, latestDefinitionsGroq, gdrFromResource, subscriptionDocumentsForInstance, aclPathForResource, definitionLookupGroq, instanceDocId, missingRequiredInputs, documentActionDenials } from "@sanity/workflow-engine";
14
14
 
15
15
  import { CheckmarkIcon } from "@sanity/icons/Checkmark";
16
16
 
@@ -18,7 +18,7 @@ import { CloseIcon } from "@sanity/icons/Close";
18
18
 
19
19
  import { formatDistanceToNow } from "date-fns/formatDistanceToNow";
20
20
 
21
- import { sameAssignee, projectMemberRow, ClearableDatePicker, MemberPicker as MemberPicker$1, AssigneePicker as AssigneePicker$1, MemberAvatar, AssigneeBadges as AssigneeBadges$1, AssigneeBadge as AssigneeBadge$1, ProgressBar, MemberAvatarGroup, clampProgress, progressCaption, DatePicker, roleListLabel } from "@sanity/workflow-components";
21
+ import { sameAssignee, projectMemberRow, ClearableDatePicker, AssigneePicker as AssigneePicker$1, MemberPicker as MemberPicker$1, MemberAvatar, AssigneeBadges as AssigneeBadges$1, AssigneeBadge as AssigneeBadge$1, ProgressBar, memberRoleFor, AssigneeStack, roleLabel, clampProgress, MemberAvatarGroup, progressCaption, DatePicker, roleLabelFor, roleListLabel } from "@sanity/workflow-components";
22
22
 
23
23
  import { getPublishedId, getDraftId } from "@sanity/client/csm";
24
24
 
@@ -60,15 +60,21 @@ import { RemoveCircleIcon } from "@sanity/icons/RemoveCircle";
60
60
 
61
61
  import { AddIcon } from "@sanity/icons/Add";
62
62
 
63
+ import { UlistIcon } from "@sanity/icons/Ulist";
64
+
65
+ import { CheckmarkCircleIcon } from "@sanity/icons/CheckmarkCircle";
66
+
63
67
  import { BoltIcon } from "@sanity/icons/Bolt";
64
68
 
65
69
  import { ChevronDownIcon } from "@sanity/icons/ChevronDown";
66
70
 
67
- import { CheckmarkCircleIcon } from "@sanity/icons/CheckmarkCircle";
71
+ import pluralize from "pluralize-esm";
68
72
 
69
- import { UlistIcon } from "@sanity/icons/Ulist";
73
+ import { EllipsisHorizontalIcon } from "@sanity/icons/EllipsisHorizontal";
70
74
 
71
- import pluralize from "pluralize-esm";
75
+ import { ClockIcon } from "@sanity/icons/Clock";
76
+
77
+ import { CogIcon } from "@sanity/icons/Cog";
72
78
 
73
79
  import { ArrowUpIcon } from "@sanity/icons/ArrowUp";
74
80
 
@@ -359,13 +365,7 @@ function landingDefaultOpen(landing, instanceId) {
359
365
  if (!(landing === void 0 || !landing.instanceIds.includes(instanceId))) return instanceId === landing.focusedId;
360
366
  }
361
367
 
362
- const WORKFLOWS_TOOL_NAME = "workflows";
363
-
364
- function workflowsToolAvailable(tools) {
365
- return tools.some(tool => tool.name === WORKFLOWS_TOOL_NAME);
366
- }
367
-
368
- const WORKFLOW_INTENT = "workflow";
368
+ const WORKFLOWS_TOOL_NAME = "workflows", WORKFLOW_INTENT = "workflow";
369
369
 
370
370
  function pathSegmentName(args) {
371
371
  return args.names.find(name => name === args.segment);
@@ -438,6 +438,10 @@ function describeEditDisabledReason(reason) {
438
438
  return editDisabledSentence[reason.kind](reason);
439
439
  }
440
440
 
441
+ function reasonRestatesInstanceState(reason) {
442
+ return reason.kind === "instance-aborted" || reason.kind === "instance-completed";
443
+ }
444
+
441
445
  function formatDateTime(value) {
442
446
  if (!value) return "—";
443
447
  const d = new Date(value);
@@ -756,6 +760,11 @@ function changedAssignee(current, next) {
756
760
  return next.find(item => !current.some(existing => sameAssignee(item, existing))) ?? current.find(item => !next.some(existing => sameAssignee(item, existing)));
757
761
  }
758
762
 
763
+ function singleAssigneePick(current, next) {
764
+ const changed = changedAssignee(current ? [ current ] : [], next);
765
+ if (changed !== void 0) return current && sameAssignee(changed, current) ? null : changed;
766
+ }
767
+
759
768
  function isAssigneeShape(value) {
760
769
  if (typeof value != "object" || value === null) return !1;
761
770
  const {type: type, id: id, role: role} = value;
@@ -768,9 +777,19 @@ function isActorShape(value) {
768
777
  return typeof id != "string" ? !1 : roles === void 0 || Array.isArray(roles) && roles.every(r => typeof r == "string");
769
778
  }
770
779
 
771
- function assigneeUserIdsOf(entries) {
772
- 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 ] : [] : []);
773
- return [ ...new Set(ids) ];
780
+ function assigneesOf(entries) {
781
+ return entries.flatMap(entry => entry._type === "assignees" ? entry.value : []);
782
+ }
783
+
784
+ function assigneeEdit(current, next) {
785
+ const changed = changedAssignee(current, next);
786
+ if (changed !== void 0) return next.some(item => sameAssignee(item, changed)) ? {
787
+ mode: "append",
788
+ value: changed
789
+ } : {
790
+ mode: "set",
791
+ value: next
792
+ };
774
793
  }
775
794
 
776
795
  function isItemAssignedTo(item, who) {
@@ -1100,7 +1119,7 @@ function activityRowProps(args) {
1100
1119
  blocked: showsBlockedTag(activityEval)
1101
1120
  },
1102
1121
  assignState: rowAssignControlState(controlArgs),
1103
- assigneeIds: assigneeUserIdsOf(state),
1122
+ assignees: assigneesOf(state),
1104
1123
  dateState: rowDateControlState(controlArgs),
1105
1124
  dueDates: dueDatesOf(state),
1106
1125
  terminalActions: rowTerminalActions({
@@ -1408,7 +1427,9 @@ function projectMembersFrom(users) {
1408
1427
  sanityUserId: profile?.sanityUserId,
1409
1428
  displayName: profile?.displayName,
1410
1429
  email: profile?.email,
1411
- imageUrl: profile?.imageUrl ?? void 0
1430
+ imageUrl: profile?.imageUrl ?? void 0,
1431
+ loginProvider: userLoginProvider(profile),
1432
+ isCurrentUser: membership.isCurrentUser
1412
1433
  }));
1413
1434
  return projectMembersByUsers.set(users, members), members;
1414
1435
  }
@@ -1790,6 +1811,17 @@ function AssigneePicker({value: value, onChange: onChange}) {
1790
1811
  });
1791
1812
  }
1792
1813
 
1814
+ function SingleAssigneePicker({current: current, onPick: onPick}) {
1815
+ /* @__PURE__ */
1816
+ return jsx(AssigneePicker, {
1817
+ onChange: next => {
1818
+ const picked = singleAssigneePick(current, next);
1819
+ picked !== void 0 && onPick(picked);
1820
+ },
1821
+ value: current ? [ current ] : []
1822
+ });
1823
+ }
1824
+
1793
1825
  function MemberPickerButton({label: label = "Select member…", onChange: onChange, selectedIds: selectedIds, unassignRow: unassignRow = !1, value: value}) {
1794
1826
  const [open, setOpen] = useState(!1), {imageUrl: imageUrl} = useUserDisplay(value?.id ?? ""), selected = selectedIds ?? (value ? /* @__PURE__ */ new Set([ value.id ]) : /* @__PURE__ */ new Set), toggle = () => setOpen(v => !v);
1795
1827
  /* @__PURE__ */
@@ -1799,7 +1831,7 @@ function MemberPickerButton({label: label = "Select member…", onChange: onChan
1799
1831
  setOpen(!1), onChange(member && !selected.has(member.id) ? {
1800
1832
  id: member.id,
1801
1833
  displayName: member.displayName,
1802
- roles: member.roles
1834
+ roles: member.roles.map(role => role.name)
1803
1835
  } : null);
1804
1836
  },
1805
1837
  selectedIds: selected,
@@ -2487,7 +2519,7 @@ function Separator() {
2487
2519
  alignItems: "center",
2488
2520
  display: "inline-flex",
2489
2521
  height: "0.7em",
2490
- margin: "0 0.25em",
2522
+ margin: "0 0.5em",
2491
2523
  overflow: "hidden"
2492
2524
  },
2493
2525
  children: /* @__PURE__ */ jsx(ChevronRightIcon, {})
@@ -3606,18 +3638,18 @@ function ActorField({field: field, instanceId: instanceId, onSave: onSave, onUns
3606
3638
  }
3607
3639
 
3608
3640
  function useAssigneePick(args) {
3609
- const {current: current, onSave: onSave, onUnset: onUnset} = args, {saving: saving, save: save} = useSaveField({
3641
+ const {onSave: onSave, onUnset: onUnset} = args, {saving: saving, save: save} = useSaveField({
3610
3642
  instanceId: args.instanceId
3611
3643
  });
3612
3644
  return {
3613
3645
  saving: saving,
3614
- pick: assignee => {
3646
+ pick: picked => {
3615
3647
  if (!saving) {
3616
- if (current && sameAssignee(assignee, current)) {
3648
+ if (picked === null) {
3617
3649
  onUnset !== void 0 && save(onUnset);
3618
3650
  return;
3619
3651
  }
3620
- save(() => onSave(assignee));
3652
+ save(() => onSave(picked));
3621
3653
  }
3622
3654
  }
3623
3655
  };
@@ -3625,22 +3657,18 @@ function useAssigneePick(args) {
3625
3657
 
3626
3658
  function AssigneeField({field: field, instanceId: instanceId, onSave: onSave, onUnset: onUnset}) {
3627
3659
  const [open, setOpen] = useState(!1), cur = isAssigneeShape(field.value) ? field.value : null, {pick: pick} = useAssigneePick({
3628
- current: cur,
3629
3660
  instanceId: instanceId,
3630
3661
  onSave: onSave,
3631
3662
  onUnset: onUnset
3632
- }), pickAndClose = assignee => {
3633
- setOpen(!1), pick(assignee);
3634
- };
3663
+ });
3635
3664
  return field.editable ? /* @__PURE__ */ jsx(Flex, {
3636
3665
  align: "center",
3637
3666
  children: /* @__PURE__ */ jsx(DismissablePopover, {
3638
- content: /* @__PURE__ */ jsx(AssigneePicker, {
3639
- onChange: next => {
3640
- const changed = changedAssignee(cur ? [ cur ] : [], next);
3641
- changed && pickAndClose(changed);
3642
- },
3643
- value: cur ? [ cur ] : []
3667
+ content: /* @__PURE__ */ jsx(SingleAssigneePicker, {
3668
+ current: cur,
3669
+ onPick: picked => {
3670
+ setOpen(!1), pick(picked);
3671
+ }
3644
3672
  }),
3645
3673
  onDismiss: () => setOpen(!1),
3646
3674
  open: open,
@@ -4189,70 +4217,85 @@ function AvatarButton({avatar: avatar, onClick: onClick, onMouseDown: onMouseDow
4189
4217
  });
4190
4218
  }
4191
4219
 
4192
- function UserAvatar({id: id}) {
4193
- const {name: name, imageUrl: imageUrl} = useUserDisplay(id);
4220
+ function RowAssignees({assignees: assignees, hint: hint}) {
4221
+ const ids = assignees.flatMap(item => item.type === "user" ? [ item.id ] : []), {members: members} = useProjectMembers(), roles = assignees.flatMap(item => item.type === "role" ? [ memberRoleFor(members, item.role) ] : []), displays = useUserDisplays(ids);
4222
+ if (ids.length === 0 && roles.length === 0) return null;
4223
+ const bothKinds = roles.length > 0 && displays.length > 0;
4194
4224
  /* @__PURE__ */
4195
4225
  return jsx(HoverHint, {
4196
- text: name,
4197
- children: /* @__PURE__ */ jsx(MemberAvatar, {
4198
- imageUrl: imageUrl,
4199
- name: name
4200
- })
4201
- });
4202
- }
4203
-
4204
- function UserAvatarGroup({ids: ids, hint: hint}) {
4205
- const displays = useUserDisplays(ids);
4206
- return displays.length === 0 ? null : /* @__PURE__ */ jsx(HoverHint, {
4207
- text: displays.map(d => d.name).join(", "),
4208
- ...hint === void 0 ? {} : {
4209
- description: hint
4210
- },
4211
- children: /* @__PURE__ */ jsx(MemberAvatarGroup, {
4226
+ content:
4227
+ /* @__PURE__ */ jsxs(Stack, {
4228
+ gap: 3,
4229
+ children: [ roles.length > 0 ? /* @__PURE__ */ jsx(HintSection, {
4230
+ names: roles.map(roleLabel),
4231
+ ...bothKinds ? {
4232
+ label: "Roles"
4233
+ } : {}
4234
+ }) : null, displays.length > 0 ? /* @__PURE__ */ jsx(HintSection, {
4235
+ names: displays.map(display => display.name),
4236
+ ...bothKinds ? {
4237
+ label: "Members"
4238
+ } : {}
4239
+ }) : null, hint === void 0 ? null : /* @__PURE__ */ jsx(Text, {
4240
+ muted: !0,
4241
+ size: 1,
4242
+ children: hint
4243
+ }) ]
4244
+ }),
4245
+ children: /* @__PURE__ */ jsx(AssigneeStack, {
4212
4246
  members: displays.map(display => ({
4213
4247
  id: display.id,
4214
4248
  displayName: display.name,
4215
4249
  imageUrl: display.imageUrl
4216
- }))
4250
+ })),
4251
+ roles: roles
4217
4252
  })
4218
4253
  });
4219
4254
  }
4220
4255
 
4221
- function AssignActivityControl({instanceId: instanceId, state: state, surface: surface, assigneeIds: assigneeIds = []}) {
4256
+ function HintSection({label: label, names: names}) {
4257
+ /* @__PURE__ */
4258
+ return jsxs(Stack, {
4259
+ gap: 2,
4260
+ children: [ label === void 0 ? null : /* @__PURE__ */ jsx(Text, {
4261
+ size: 1,
4262
+ weight: "medium",
4263
+ children: label
4264
+ }),
4265
+ /* @__PURE__ */ jsx(Text, {
4266
+ size: 1,
4267
+ children: names.join(", ")
4268
+ }) ]
4269
+ });
4270
+ }
4271
+
4272
+ function AssignActivityControl({instanceId: instanceId, state: state, surface: surface, assignees: assignees = []}) {
4222
4273
  const editField = useEditField(surface), report = useRejectionReport(), [open, setOpen] = useState(!1), [busy, setBusy] = useState(!1);
4223
- if (state.kind === "none") return assigneeIds.length === 0 ? null : /* @__PURE__ */ jsx(AvatarDisplay, {
4274
+ if (state.kind === "none") return assignees.length === 0 ? null : /* @__PURE__ */ jsx(AvatarDisplay, {
4224
4275
  "aria-label": "Assignees",
4225
- avatar: /* @__PURE__ */ jsx(UserAvatarGroup, {
4226
- ids: assigneeIds
4276
+ avatar: /* @__PURE__ */ jsx(RowAssignees, {
4277
+ assignees: assignees
4227
4278
  })
4228
4279
  });
4229
- if (state.kind === "closed") return assigneeIds.length === 0 ? null : /* @__PURE__ */ jsx(AvatarButton, {
4280
+ if (state.kind === "closed") return assignees.length === 0 ? null : /* @__PURE__ */ jsx(AvatarButton, {
4230
4281
  "aria-label": "Assignees",
4231
4282
  as: "span",
4232
- avatar: /* @__PURE__ */ jsx(UserAvatarGroup, {
4233
- hint: state.reason,
4234
- ids: assigneeIds
4283
+ avatar: /* @__PURE__ */ jsx(RowAssignees, {
4284
+ assignees: assignees,
4285
+ hint: state.reason
4235
4286
  }),
4236
4287
  onClick: stopRowClick,
4237
4288
  onMouseDown: stopRowMouseDown
4238
4289
  });
4239
- 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 => {
4240
- if (!(busy || field === void 0)) {
4290
+ const field = state.kind === "editable" ? state.field : void 0, current = field?.value ?? [], change = async next => {
4291
+ const edit = assigneeEdit(current, next);
4292
+ if (!(busy || field === void 0 || edit === void 0)) {
4241
4293
  setBusy(!0);
4242
4294
  try {
4243
- selectedIds.has(memberId) ? await editField({
4295
+ await editField({
4244
4296
  instanceId: instanceId,
4245
4297
  field: field,
4246
- mode: "set",
4247
- value: members.filter(m => !(m.type === "user" && m.id === memberId))
4248
- }) : await editField({
4249
- instanceId: instanceId,
4250
- field: field,
4251
- mode: "append",
4252
- value: {
4253
- type: "user",
4254
- id: memberId
4255
- }
4298
+ ...edit
4256
4299
  }), report.dismiss(instanceToastId("assign", instanceId));
4257
4300
  } catch (err) {
4258
4301
  report.rejected({
@@ -4268,12 +4311,12 @@ function AssignActivityControl({instanceId: instanceId, state: state, surface: s
4268
4311
  }
4269
4312
  }, handleClick = e => {
4270
4313
  e.stopPropagation(), setOpen(v => !v);
4271
- }, button = assigneeIds.length > 0 ?
4314
+ }, button = assignees.length > 0 ?
4272
4315
  /* @__PURE__ */ jsx(AvatarButton, {
4273
4316
  "aria-label": "Assignees",
4274
4317
  as: "span",
4275
- avatar: /* @__PURE__ */ jsx(UserAvatarGroup, {
4276
- ids: assigneeIds
4318
+ avatar: /* @__PURE__ */ jsx(RowAssignees, {
4319
+ assignees: assignees
4277
4320
  }),
4278
4321
  onClick: handleClick,
4279
4322
  onMouseDown: stopRowMouseDown
@@ -4298,9 +4341,11 @@ function AssignActivityControl({instanceId: instanceId, state: state, surface: s
4298
4341
  children: state.kind === "loading" ? /* @__PURE__ */ jsx(LoadingRow, {
4299
4342
  label: "Loading…",
4300
4343
  padding: 3
4301
- }) : /* @__PURE__ */ jsx(MemberPicker, {
4302
- onSelect: member => member && void toggle(member.id),
4303
- selectedIds: selectedIds
4344
+ }) : /* @__PURE__ */ jsx(AssigneePicker, {
4345
+ onChange: next => {
4346
+ change(next);
4347
+ },
4348
+ value: current
4304
4349
  })
4305
4350
  }),
4306
4351
  onDismiss: () => setOpen(!1),
@@ -4332,6 +4377,58 @@ function canRemoveRow(args) {
4332
4377
  return editTarget === void 0 || appendTarget === void 0 ? !1 : editTarget.scope === appendTarget.scope && editTarget.field === appendTarget.field && editTarget.activity === appendTarget.activity;
4333
4378
  }
4334
4379
 
4380
+ function EmptyState({action: action, description: description, icon: icon, title: title}) {
4381
+ /* @__PURE__ */
4382
+ return jsx(Card, {
4383
+ border: !0,
4384
+ flex: 1,
4385
+ padding: 4,
4386
+ radius: 3,
4387
+ style: {
4388
+ alignItems: "center",
4389
+ display: "flex",
4390
+ justifyContent: "center"
4391
+ },
4392
+ children: /* @__PURE__ */ jsxs(Stack, {
4393
+ gap: 4,
4394
+ children: [
4395
+ /* @__PURE__ */ jsx(Text, {
4396
+ align: "center",
4397
+ size: 4,
4398
+ children: icon
4399
+ }),
4400
+ /* @__PURE__ */ jsxs(Stack, {
4401
+ gap: 3,
4402
+ children: [
4403
+ /* @__PURE__ */ jsx(Text, {
4404
+ align: "center",
4405
+ size: 1,
4406
+ weight: "medium",
4407
+ children: title
4408
+ }),
4409
+ /* @__PURE__ */ jsx(Text, {
4410
+ align: "center",
4411
+ muted: !0,
4412
+ size: 1,
4413
+ children: description
4414
+ }) ]
4415
+ }), action ? /* @__PURE__ */ jsx(Flex, {
4416
+ justify: "center",
4417
+ children: action
4418
+ }) : null ]
4419
+ })
4420
+ });
4421
+ }
4422
+
4423
+ function ForMeEmptyState() {
4424
+ /* @__PURE__ */
4425
+ return jsx(EmptyState, {
4426
+ description: "No activities or to-dos are assigned to you",
4427
+ icon: /* @__PURE__ */ jsx(CheckmarkCircleIcon, {}),
4428
+ title: "Nothing to do!"
4429
+ });
4430
+ }
4431
+
4335
4432
  function looksLikeDefinition(value) {
4336
4433
  return typeof value == "object" && value !== null && Array.isArray(value.stages);
4337
4434
  }
@@ -4489,22 +4586,18 @@ function DueDateControl({item: item, editable: editable, onPatch: onPatch}) {
4489
4586
  }
4490
4587
 
4491
4588
  function AssigneeControl({item: item, editable: editable, onPatch: onPatch}) {
4492
- const [open, setOpen] = useState(!1), assignedId = item.assignee?.type === "user" ? item.assignee.id : void 0, chip = assignedId ? /* @__PURE__ */ jsx(UserAvatar, {
4493
- id: assignedId
4589
+ const [open, setOpen] = useState(!1), current = item.assignee ?? null, chip = current ? /* @__PURE__ */ jsx(RowAssignees, {
4590
+ assignees: [ current ]
4494
4591
  }) : null;
4495
4592
  return editable ? /* @__PURE__ */ jsx(DismissablePopover, {
4496
4593
  content:
4497
- /* @__PURE__ */ jsx(MemberPicker, {
4498
- onSelect: member => {
4594
+ /* @__PURE__ */ jsx(SingleAssigneePicker, {
4595
+ current: current,
4596
+ onPick: picked => {
4499
4597
  setOpen(!1), onPatch({
4500
- assignee: member && member.id !== assignedId ? {
4501
- type: "user",
4502
- id: member.id
4503
- } : null
4598
+ assignee: picked
4504
4599
  });
4505
- },
4506
- selectedIds: assignedId ? /* @__PURE__ */ new Set([ assignedId ]) : /* @__PURE__ */ new Set,
4507
- unassignRow: !0
4600
+ }
4508
4601
  }),
4509
4602
  onDismiss: () => setOpen(!1),
4510
4603
  open: open,
@@ -4700,7 +4793,7 @@ function TodoItemRowView({breadcrumb: breadcrumb, row: row, onToggle: onToggle,
4700
4793
  });
4701
4794
  }
4702
4795
 
4703
- function TodoItemsList({breadcrumb: breadcrumb, entry: entry, filter: filter, surface: surface}) {
4796
+ function TodoItemsList({breadcrumb: breadcrumb, entry: entry, filter: filter, showEmpty: showEmpty = !1, surface: surface}) {
4704
4797
  const {instance: instance} = entry, definition = useDefinition(entry), {editFieldFor: editFieldFor, fireActionFor: fireActionFor} = useWorkflowContext(), telemetry = useWorkflowTelemetry(), report = useRejectionReport(), [busy, setBusy] = useState(!1), derivation = deriveTodoItems(entry), rows = derivation.rows.filter(row => rowMatches(row, filter)), appendTarget = appendTargetFor(derivation.appendTargets, filter), run = async op => {
4705
4798
  if (busy) return !1;
4706
4799
  setBusy(!0);
@@ -4796,8 +4889,28 @@ function TodoItemsList({breadcrumb: breadcrumb, entry: entry, filter: filter, su
4796
4889
  kind: "remove",
4797
4890
  success: success
4798
4891
  });
4799
- };
4800
- if (rows.length === 0 && !appendTarget) return null;
4892
+ }, empty = rows.length === 0;
4893
+ if (empty && !showEmpty) return null;
4894
+ const addControl = appendTarget ? /* @__PURE__ */ jsx(AddItemControl, {
4895
+ busy: busy,
4896
+ button: /* @__PURE__ */ jsx(Button, {
4897
+ fontSize: 1,
4898
+ icon: AddIcon,
4899
+ mode: "ghost",
4900
+ padding: 2,
4901
+ text: "Add item"
4902
+ }),
4903
+ onAdd: addItem
4904
+ }) : null;
4905
+ if (empty) /* @__PURE__ */
4906
+ return jsx(EmptyState, {
4907
+ ...addControl === null ? {} : {
4908
+ action: addControl
4909
+ },
4910
+ description: "Nothing has been added to this list",
4911
+ icon: /* @__PURE__ */ jsx(UlistIcon, {}),
4912
+ title: "No to-dos"
4913
+ });
4801
4914
  const rowKey = row => `${row.scope}:${row.activityName ?? ""}:${row.fieldName}:${row.item._key}`, rowBreadcrumb = row => {
4802
4915
  if (breadcrumb === void 0 || row.activityName === void 0) return breadcrumb;
4803
4916
  const {title: title} = findActivity({
@@ -4831,19 +4944,9 @@ function TodoItemsList({breadcrumb: breadcrumb, entry: entry, filter: filter, su
4831
4944
  },
4832
4945
  row: row
4833
4946
  }, rowKey(row)))
4834
- }), appendTarget ? /* @__PURE__ */ jsx(Flex, {
4835
- children: /* @__PURE__ */ jsx(AddItemControl, {
4836
- busy: busy,
4837
- button: /* @__PURE__ */ jsx(Button, {
4838
- fontSize: 1,
4839
- icon: AddIcon,
4840
- mode: "ghost",
4841
- padding: 2,
4842
- text: "Add item"
4843
- }),
4844
- onAdd: addItem
4845
- })
4846
- }) : null ]
4947
+ }), addControl === null ? null : /* @__PURE__ */ jsx(Flex, {
4948
+ children: addControl
4949
+ }) ]
4847
4950
  });
4848
4951
  }
4849
4952
 
@@ -5282,6 +5385,7 @@ function FieldRow({field: field, detail: detail, entry: entry, activityName: act
5282
5385
  field: field.name,
5283
5386
  activity: activityName
5284
5387
  },
5388
+ showEmpty: !0,
5285
5389
  surface: "activity-dialog"
5286
5390
  }) ]
5287
5391
  });
@@ -5338,58 +5442,6 @@ function blockedNotice(detail) {
5338
5442
  });
5339
5443
  }
5340
5444
 
5341
- function EmptyState({action: action, description: description, icon: icon, title: title}) {
5342
- /* @__PURE__ */
5343
- return jsx(Card, {
5344
- border: !0,
5345
- flex: 1,
5346
- padding: 4,
5347
- radius: 3,
5348
- style: {
5349
- alignItems: "center",
5350
- display: "flex",
5351
- justifyContent: "center"
5352
- },
5353
- children: /* @__PURE__ */ jsxs(Stack, {
5354
- gap: 4,
5355
- children: [
5356
- /* @__PURE__ */ jsx(Text, {
5357
- align: "center",
5358
- size: 4,
5359
- children: icon
5360
- }),
5361
- /* @__PURE__ */ jsxs(Stack, {
5362
- gap: 3,
5363
- children: [
5364
- /* @__PURE__ */ jsx(Text, {
5365
- align: "center",
5366
- size: 1,
5367
- weight: "medium",
5368
- children: title
5369
- }),
5370
- /* @__PURE__ */ jsx(Text, {
5371
- align: "center",
5372
- muted: !0,
5373
- size: 1,
5374
- children: description
5375
- }) ]
5376
- }), action ? /* @__PURE__ */ jsx(Flex, {
5377
- justify: "center",
5378
- children: action
5379
- }) : null ]
5380
- })
5381
- });
5382
- }
5383
-
5384
- function ForMeEmptyState() {
5385
- /* @__PURE__ */
5386
- return jsx(EmptyState, {
5387
- description: "No activities or to-dos are assigned to you",
5388
- icon: /* @__PURE__ */ jsx(CheckmarkCircleIcon, {}),
5389
- title: "Nothing to do!"
5390
- });
5391
- }
5392
-
5393
5445
  function CountedLabel({count: count, label: label}) {
5394
5446
  return count === void 0 || count === 0 ? /* @__PURE__ */ jsx(Fragment, {
5395
5447
  children: label
@@ -5590,17 +5642,13 @@ function TitleTag({hint: hint, tone: tone, children: children}) {
5590
5642
  });
5591
5643
  }
5592
5644
 
5593
- function ActivityRow({face: face, breadcrumb: breadcrumb, assigneeIds: assigneeIds, assignState: assignState, dateState: dateState, dueDates: dueDates, instanceId: instanceId, onOpen: onOpen, surface: surface, terminalActions: terminalActions = []}) {
5645
+ function ActivityRow({face: face, breadcrumb: breadcrumb, assignees: assignees, assignState: assignState, dateState: dateState, dueDates: dueDates, instanceId: instanceId, onOpen: onOpen, surface: surface, terminalActions: terminalActions = []}) {
5594
5646
  const settled = isTerminalActivityStatus(face.status), dimmed = settledDim(settled);
5595
5647
  /* @__PURE__ */
5596
5648
  return jsxs(WorkRow, {
5597
- end: /* @__PURE__ */ jsxs(Fragment, {
5598
- children: [ settled || terminalActions.length === 0 ? null : /* @__PURE__ */ jsx(RowTerminalActions, {
5599
- actions: terminalActions,
5600
- activity: face.activityName,
5601
- instanceId: instanceId,
5602
- surface: surface
5603
- }),
5649
+ end:
5650
+ /* @__PURE__ */ jsxs(Fragment, {
5651
+ children: [
5604
5652
  /* @__PURE__ */ jsx(ActivityDateControl, {
5605
5653
  dueDates: dueDates,
5606
5654
  instanceId: instanceId,
@@ -5608,10 +5656,15 @@ function ActivityRow({face: face, breadcrumb: breadcrumb, assigneeIds: assigneeI
5608
5656
  surface: surface
5609
5657
  }),
5610
5658
  /* @__PURE__ */ jsx(AssignActivityControl, {
5611
- assigneeIds: assigneeIds,
5659
+ assignees: assignees,
5612
5660
  instanceId: instanceId,
5613
5661
  state: assignState,
5614
5662
  surface: surface
5663
+ }), settled || terminalActions.length === 0 ? null : /* @__PURE__ */ jsx(RowTerminalActions, {
5664
+ actions: terminalActions,
5665
+ activity: face.activityName,
5666
+ instanceId: instanceId,
5667
+ surface: surface
5615
5668
  }) ]
5616
5669
  }),
5617
5670
  lead: /* @__PURE__ */ jsx(ActivityStatusLead, {
@@ -5835,6 +5888,35 @@ function deriveFieldPills(args) {
5835
5888
  });
5836
5889
  }
5837
5890
 
5891
+ function UserAvatar({id: id}) {
5892
+ const {name: name, imageUrl: imageUrl} = useUserDisplay(id);
5893
+ /* @__PURE__ */
5894
+ return jsx(HoverHint, {
5895
+ text: name,
5896
+ children: /* @__PURE__ */ jsx(MemberAvatar, {
5897
+ imageUrl: imageUrl,
5898
+ name: name
5899
+ })
5900
+ });
5901
+ }
5902
+
5903
+ function UserAvatarGroup({ids: ids, hint: hint}) {
5904
+ const displays = useUserDisplays(ids);
5905
+ return displays.length === 0 ? null : /* @__PURE__ */ jsx(HoverHint, {
5906
+ text: displays.map(d => d.name).join(", "),
5907
+ ...hint === void 0 ? {} : {
5908
+ description: hint
5909
+ },
5910
+ children: /* @__PURE__ */ jsx(MemberAvatarGroup, {
5911
+ members: displays.map(display => ({
5912
+ id: display.id,
5913
+ displayName: display.name,
5914
+ imageUrl: display.imageUrl
5915
+ }))
5916
+ })
5917
+ });
5918
+ }
5919
+
5838
5920
  function TodoFieldDialog({entry: entry, scope: scope, field: field, title: title, onClose: onClose}) {
5839
5921
  /* @__PURE__ */
5840
5922
  return jsx(Dialog, {
@@ -5851,6 +5933,7 @@ function TodoFieldDialog({entry: entry, scope: scope, field: field, title: title
5851
5933
  scope: scope,
5852
5934
  field: field
5853
5935
  },
5936
+ showEmpty: !0,
5854
5937
  surface: "todo-field-dialog"
5855
5938
  })
5856
5939
  })
@@ -5968,20 +6051,32 @@ function PillContent({pill: pill}) {
5968
6051
  children: [ lead,
5969
6052
  /* @__PURE__ */ jsx(FaceText, {
5970
6053
  muted: !0,
5971
- children: pill.editability?.editable === !0 ? `Set ${pill.title}` : pill.title
6054
+ children: pill.title
5972
6055
  }) ]
5973
6056
  }) : /* @__PURE__ */ jsxs(Fragment, {
5974
6057
  children: [ lead,
5975
- /* @__PURE__ */ jsx(SetFace, {
5976
- face: face
5977
- }) ]
5978
- });
5979
- }
5980
-
5981
- function AvatarCapAligned({children: children}) {
5982
- const trim = useAvatarCapTrim();
5983
- /* @__PURE__ */
5984
- return jsx(Flex, {
6058
+ /* @__PURE__ */ jsxs(Flex, {
6059
+ align: "center",
6060
+ gap: 1,
6061
+ style: {
6062
+ minWidth: 0
6063
+ },
6064
+ children: [
6065
+ /* @__PURE__ */ jsx(FaceText, {
6066
+ muted: !0,
6067
+ children: `${pill.title}:`
6068
+ }),
6069
+ /* @__PURE__ */ jsx(SetFace, {
6070
+ face: face
6071
+ }) ]
6072
+ }) ]
6073
+ });
6074
+ }
6075
+
6076
+ function AvatarCapAligned({children: children}) {
6077
+ const trim = useAvatarCapTrim();
6078
+ /* @__PURE__ */
6079
+ return jsx(Flex, {
5985
6080
  align: "center",
5986
6081
  style: {
5987
6082
  marginBottom: trim,
@@ -5993,7 +6088,7 @@ function AvatarCapAligned({children: children}) {
5993
6088
  }
5994
6089
 
5995
6090
  function AssigneesFace({assignees: assignees}) {
5996
- const userIds = assignees.flatMap(a => a.type === "user" ? [ a.id ] : []), roles = assignees.flatMap(a => a.type === "role" ? [ a.role ] : []);
6091
+ const {members: members} = useProjectMembers(), userIds = assignees.flatMap(a => a.type === "user" ? [ a.id ] : []), roles = assignees.flatMap(a => a.type === "role" ? [ roleLabelFor(members, a.role) ] : []);
5997
6092
  /* @__PURE__ */
5998
6093
  return jsxs(Fragment, {
5999
6094
  children: [ userIds.length > 0 ? /* @__PURE__ */ jsx(AvatarCapAligned, {
@@ -6026,14 +6121,11 @@ function usePillChrome(face) {
6026
6121
  }
6027
6122
 
6028
6123
  function PillHint({pill: pill, disabled: disabled = !1, children: children}) {
6124
+ const {description: description} = pill;
6029
6125
  /* @__PURE__ */
6030
6126
  return jsx(HoverHint, {
6031
- disabled: disabled,
6032
- text: pill.title,
6033
- textWeight: "medium",
6034
- ...pill.description === void 0 ? {} : {
6035
- description: pill.description
6036
- },
6127
+ disabled: disabled || description === void 0,
6128
+ text: description ?? "",
6037
6129
  children: children
6038
6130
  });
6039
6131
  }
@@ -6119,7 +6211,7 @@ function PillPopover({pill: pill, content: content, open: open, onToggle: onTogg
6119
6211
  }
6120
6212
 
6121
6213
  function ReadOnlyPill({pill: pill}) {
6122
- const [open, setOpen] = useState(!1), reason = pill.editability?.disabledReason;
6214
+ const [open, setOpen] = useState(!1), verdict = pill.editability?.disabledReason, reason = verdict !== void 0 && reasonRestatesInstanceState(verdict) ? void 0 : verdict;
6123
6215
  /* @__PURE__ */
6124
6216
  return jsx(PillPopover, {
6125
6217
  content: /* @__PURE__ */ jsx(Box, {
@@ -6302,19 +6394,17 @@ function AssigneePill({entry: entry, pill: pill, editability: editability, surfa
6302
6394
  editability: editability,
6303
6395
  surface: surface
6304
6396
  }), current = pill.entry?._type === "assignee" ? pill.entry.value : null, {pick: pick} = useAssigneePick({
6305
- current: current,
6306
6397
  instanceId: entry.instance._id,
6307
6398
  onSave: set,
6308
6399
  onUnset: unset
6309
6400
  });
6310
6401
  /* @__PURE__ */
6311
6402
  return jsx(PillPopover, {
6312
- content: /* @__PURE__ */ jsx(AssigneePicker, {
6313
- onChange: next => {
6314
- const changed = changedAssignee(current ? [ current ] : [], next);
6315
- changed && (setOpen(!1), pick(changed));
6316
- },
6317
- value: current ? [ current ] : []
6403
+ content: /* @__PURE__ */ jsx(SingleAssigneePicker, {
6404
+ current: current,
6405
+ onPick: picked => {
6406
+ setOpen(!1), pick(picked);
6407
+ }
6318
6408
  }),
6319
6409
  onDismiss: () => setOpen(!1),
6320
6410
  onToggle: () => setOpen(v => !v),
@@ -6443,165 +6533,6 @@ function instanceBreadcrumb(instance, definition) {
6443
6533
  return [ instanceTitle(instance, definition), stageTitle(definition, instance.currentStage) ];
6444
6534
  }
6445
6535
 
6446
- function Hairline({weight: weight, style: style}) {
6447
- const {color: color} = useTheme_v2();
6448
- /* @__PURE__ */
6449
- return jsx("div", {
6450
- style: {
6451
- borderTop: `${weight}px solid ${color.border}`,
6452
- ...style
6453
- }
6454
- });
6455
- }
6456
-
6457
- function CollapsibleBand({header: header, children: children, background: background = !1, defaultOpen: defaultOpen = !0, onToggle: onToggle, open: controlledOpen, sticky: sticky = !1, title: title}) {
6458
- const [heldOpen, setHeldOpen] = useState(defaultOpen), open = controlledOpen ?? heldOpen, toggle = onToggle ?? (() => setHeldOpen(value => !value)), verb = open ? "Collapse" : "Expand";
6459
- /* @__PURE__ */
6460
- return jsxs(Stack, {
6461
- gap: 1,
6462
- children: [
6463
- /* @__PURE__ */ jsx(Card, {
6464
- onDoubleClick: event => {
6465
- event.target instanceof Element && event.target.closest("a, button") || toggle();
6466
- },
6467
- padding: 1,
6468
- radius: 3,
6469
- style: {
6470
- userSelect: "none",
6471
- ...sticky ? {
6472
- position: "sticky",
6473
- top: 0,
6474
- zIndex: 1
6475
- } : {}
6476
- },
6477
- tone: background ? "transparent" : "inherit",
6478
- children: /* @__PURE__ */ jsxs(Flex, {
6479
- align: "center",
6480
- children: [
6481
- /* @__PURE__ */ jsx(Button, {
6482
- "aria-label": `${verb} ${title}`,
6483
- fontSize: 1,
6484
- icon: open ? ChevronDownIcon : ChevronRightIcon,
6485
- mode: "bleed",
6486
- onClick: toggle,
6487
- padding: 2
6488
- }), header ]
6489
- })
6490
- }), open ? children : null ]
6491
- });
6492
- }
6493
-
6494
- function TrailingHairline() {
6495
- /* @__PURE__ */
6496
- return jsx(Box, {
6497
- flex: 1,
6498
- paddingLeft: 1,
6499
- paddingRight: 1,
6500
- children: /* @__PURE__ */ jsx(Hairline, {
6501
- weight: .5
6502
- })
6503
- });
6504
- }
6505
-
6506
- function InstanceAccordion({entry: entry, children: children, defaultOpen: defaultOpen}) {
6507
- const definition = useDefinition(entry), {instance: instance} = entry, settled = !isLiveEntry(entry), title = instanceTitle(instance, definition), badgeTrim = useBadgeCapTrim();
6508
- /* @__PURE__ */
6509
- return jsx(CollapsibleBand, {
6510
- defaultOpen: defaultOpen ?? !settled,
6511
- title: title,
6512
- header: /* @__PURE__ */ jsxs(Fragment, {
6513
- children: [
6514
- /* @__PURE__ */ jsxs(Flex, {
6515
- align: "center",
6516
- gap: 2,
6517
- paddingLeft: 2,
6518
- style: {
6519
- minWidth: 0
6520
- },
6521
- children: [
6522
- /* @__PURE__ */ jsx(Text, {
6523
- size: 1,
6524
- style: {
6525
- minWidth: 0
6526
- },
6527
- textOverflow: "ellipsis",
6528
- weight: "medium",
6529
- children: title
6530
- }),
6531
- /* @__PURE__ */ jsxs(Flex, {
6532
- align: "center",
6533
- gap: 2,
6534
- style: badgeTrim,
6535
- children: [
6536
- /* @__PURE__ */ jsx(AbortedBadge, {
6537
- instance: instance
6538
- }), settled ? null : /* @__PURE__ */ jsx(OlderDefinitionBadge, {
6539
- instance: instance
6540
- }) ]
6541
- }) ]
6542
- }),
6543
- /* @__PURE__ */ jsx(TrailingHairline, {}) ]
6544
- }),
6545
- sticky: !0,
6546
- children: /* @__PURE__ */ jsx(Box, {
6547
- paddingBottom: 2,
6548
- paddingLeft: 5,
6549
- children: children
6550
- })
6551
- });
6552
- }
6553
-
6554
- function InstanceToolLink({entry: entry}) {
6555
- const {tools: tools} = useWorkspace(), instanceId = entry.instance._id, WorkflowIntentLink = useMemo(() => function(linkProps) {
6556
- /* @__PURE__ */
6557
- return jsx(IntentLink, {
6558
- ...linkProps,
6559
- intent: WORKFLOW_INTENT,
6560
- params: {
6561
- instanceId: instanceId
6562
- }
6563
- });
6564
- }, [ instanceId ]);
6565
- return workflowsToolAvailable(tools) ? /* @__PURE__ */ jsx(Flex, {
6566
- children: /* @__PURE__ */ jsx(Button, {
6567
- as: WorkflowIntentLink,
6568
- fontSize: 1,
6569
- mode: "bleed",
6570
- padding: 2,
6571
- text: "View workflow details"
6572
- })
6573
- }) : null;
6574
- }
6575
-
6576
- function PartOfBand({instance: instance}) {
6577
- const parentRef = instance.ancestors.at(-1), parentId = parentRef ? toBareId(parentRef.id) : null, parentEntry = useWorkflowInstanceEntry(parentId), parentDefinition = useDefinition(parentEntry);
6578
- if (!parentId) return null;
6579
- const title = parentEntry ? instanceTitle(parentEntry.instance, parentDefinition) : parentId;
6580
- /* @__PURE__ */
6581
- return jsx(Card, {
6582
- border: !0,
6583
- padding: 3,
6584
- radius: 3,
6585
- tone: "primary",
6586
- children: /* @__PURE__ */ jsxs(Flex, {
6587
- align: "center",
6588
- gap: 2,
6589
- children: [
6590
- /* @__PURE__ */ jsx(Text, {
6591
- size: 1,
6592
- children: /* @__PURE__ */ jsx(ArrowUpIcon, {})
6593
- }),
6594
- /* @__PURE__ */ jsxs(Text, {
6595
- size: 1,
6596
- children: [ "Part of ",
6597
- /* @__PURE__ */ jsx("strong", {
6598
- children: title
6599
- }) ]
6600
- }) ]
6601
- })
6602
- });
6603
- }
6604
-
6605
6536
  const UNCONDITIONAL_WHENS = /* @__PURE__ */ new Set([ "true", DEFAULT_TRANSITION_WHEN ]);
6606
6537
 
6607
6538
  function stageRounds(instance) {
@@ -6661,6 +6592,31 @@ function nodeState(args) {
6661
6592
  return args.name === args.instance.currentStage ? "current" : args.visits === 0 ? "upcoming" : args.currentIndex >= 0 && args.index > args.currentIndex ? "revisit" : "done";
6662
6593
  }
6663
6594
 
6595
+ function roundDetail(round) {
6596
+ return round === void 0 ? void 0 : `Round ${round}`;
6597
+ }
6598
+
6599
+ function instanceStageFace(args) {
6600
+ const {definition: definition, instance: instance} = args;
6601
+ if (isUnprimed(instance)) return;
6602
+ const current = definition === void 0 ? void 0 : deriveSpine({
6603
+ definition: definition,
6604
+ instance: instance
6605
+ }).find(node => node.state === "current");
6606
+ if (current === void 0) return {
6607
+ title: stageTitle(definition, instance.currentStage),
6608
+ completed: terminalState(instance) === "completed"
6609
+ };
6610
+ const detail = roundDetail(current.round);
6611
+ return {
6612
+ title: current.title,
6613
+ completed: current.completedAt !== void 0,
6614
+ ...detail === void 0 ? {} : {
6615
+ detail: detail
6616
+ }
6617
+ };
6618
+ }
6619
+
6664
6620
  function stageOverview(args) {
6665
6621
  const {definition: definition, node: node, transitions: transitions} = args, stage = definition.stages.find(s => s.name === node.name), advance = node.state === "current" ? advanceHint({
6666
6622
  definition: definition,
@@ -6727,97 +6683,878 @@ function advanceHint(args) {
6727
6683
  };
6728
6684
  }
6729
6685
 
6730
- function conditionLines(description) {
6731
- return description.checklist.kind === "group" && description.checklist.op === "all" ? description.checklist.items.flatMap(item => checklistLines({
6732
- ...description,
6733
- checklist: item
6734
- }, {
6735
- marks: !1
6736
- })) : checklistLines(description, {
6737
- marks: !1
6686
+ function conditionLines(description) {
6687
+ return description.checklist.kind === "group" && description.checklist.op === "all" ? description.checklist.items.flatMap(item => checklistLines({
6688
+ ...description,
6689
+ checklist: item
6690
+ }, {
6691
+ marks: !1
6692
+ })) : checklistLines(description, {
6693
+ marks: !1
6694
+ });
6695
+ }
6696
+
6697
+ function Hairline({weight: weight, style: style}) {
6698
+ const {color: color} = useTheme_v2();
6699
+ /* @__PURE__ */
6700
+ return jsx("div", {
6701
+ style: {
6702
+ borderTop: `${weight}px solid ${color.border}`,
6703
+ ...style
6704
+ }
6705
+ });
6706
+ }
6707
+
6708
+ function StageGlyph(props) {
6709
+ /* @__PURE__ */
6710
+ return jsxs("svg", {
6711
+ "data-sanity-icon": "stage",
6712
+ fill: "none",
6713
+ height: "1em",
6714
+ viewBox: "0 0 25 25",
6715
+ width: "1em",
6716
+ xmlns: "http://www.w3.org/2000/svg",
6717
+ ...props,
6718
+ children: [
6719
+ /* @__PURE__ */ jsx("path", {
6720
+ 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",
6721
+ fill: "currentColor"
6722
+ }),
6723
+ /* @__PURE__ */ jsx("path", {
6724
+ 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",
6725
+ fill: "currentColor"
6726
+ }),
6727
+ /* @__PURE__ */ jsx("path", {
6728
+ 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",
6729
+ fill: "currentColor"
6730
+ }) ]
6731
+ });
6732
+ }
6733
+
6734
+ function StageFace({completed: completed = !1, detail: detail, glyph: glyph = !0, title: title}) {
6735
+ const tone = completed ? "default" : "primary";
6736
+ /* @__PURE__ */
6737
+ return jsxs(Flex, {
6738
+ align: "center",
6739
+ as: "span",
6740
+ gap: 2,
6741
+ children: [ glyph ? /* @__PURE__ */ jsx(TextWithTone, {
6742
+ size: 1,
6743
+ tone: tone,
6744
+ children: completed ? /* @__PURE__ */ jsx(CheckmarkCircleFilledIcon, {
6745
+ style: {
6746
+ color: "inherit"
6747
+ }
6748
+ }) : /* @__PURE__ */ jsx(StageGlyph, {
6749
+ style: {
6750
+ color: "inherit"
6751
+ }
6752
+ })
6753
+ }) : null,
6754
+ /* @__PURE__ */ jsx(TextWithTone, {
6755
+ size: 1,
6756
+ tone: tone,
6757
+ weight: "medium",
6758
+ children: title
6759
+ }), detail === void 0 ? null : /* @__PURE__ */ jsx(Text, {
6760
+ muted: !0,
6761
+ size: 1,
6762
+ children: detail
6763
+ }) ]
6764
+ });
6765
+ }
6766
+
6767
+ function StageChip({completed: completed = !1, detail: detail, interactive: interactive = !1, title: title}) {
6768
+ const {color: color} = useTheme_v2();
6769
+ /* @__PURE__ */
6770
+ return jsx(Card, {
6771
+ padding: 3,
6772
+ radius: 4,
6773
+ style: {
6774
+ boxShadow: `inset 0 0 0 1px ${completed ? color.badge.default.fg : color.focusRing}`,
6775
+ cursor: interactive ? "help" : "default"
6776
+ },
6777
+ tone: completed ? "default" : "primary",
6778
+ ...interactive ? {
6779
+ tabIndex: 0
6780
+ } : {},
6781
+ children: /* @__PURE__ */ jsx(StageFace, {
6782
+ completed: completed,
6783
+ title: title,
6784
+ ...detail === void 0 ? {} : {
6785
+ detail: detail
6786
+ }
6787
+ })
6788
+ });
6789
+ }
6790
+
6791
+ function StartIncompleteBadge({style: style}) {
6792
+ /* @__PURE__ */
6793
+ return jsx(Badge, {
6794
+ fontSize: 1,
6795
+ mode: "outline",
6796
+ style: style,
6797
+ tone: "caution",
6798
+ children: "Start incomplete"
6799
+ });
6800
+ }
6801
+
6802
+ function normalizeAbortReason(raw) {
6803
+ const trimmed = raw.trim();
6804
+ return trimmed === "" ? void 0 : trimmed;
6805
+ }
6806
+
6807
+ function abortCommitReport(args) {
6808
+ return args.changed ? {
6809
+ outcome: "aborted",
6810
+ toast: abortedToast(args.title)
6811
+ } : {
6812
+ outcome: "already-settled",
6813
+ toast: abortAlreadySettledToast(args.title)
6814
+ };
6815
+ }
6816
+
6817
+ function abortedToast(title) {
6818
+ return {
6819
+ id: TOAST_ID.abort,
6820
+ status: "info",
6821
+ title: `Aborted “${title}”`
6822
+ };
6823
+ }
6824
+
6825
+ function abortAlreadySettledToast(title) {
6826
+ return {
6827
+ id: TOAST_ID.abort,
6828
+ status: "info",
6829
+ title: `“${title}” had already finished`,
6830
+ description: "Nothing was aborted — the workflow reached a terminal state first."
6831
+ };
6832
+ }
6833
+
6834
+ function abortUnconfirmedToast(args) {
6835
+ return {
6836
+ id: TOAST_ID.abort,
6837
+ status: "warning",
6838
+ title: `Couldn’t confirm “${args.title}” was aborted`,
6839
+ description: `${describeError(args.err)} — the abort may still have committed, so check the workflow’s state before trying again.`
6840
+ };
6841
+ }
6842
+
6843
+ function AbortWorkflowDialog({entry: entry, onClose: onClose}) {
6844
+ const {engine: engine} = useWorkflowContext(), definition = useDefinition(entry), toast = useWorkflowToast(), telemetry = useWorkflowTelemetry(), [typedReason, setTypedReason] = useState(""), [pending, setPending] = useState(!1), {instance: instance} = entry, title = instanceTitle(instance, definition), reason = normalizeAbortReason(typedReason), reasonInputId = `abort-workflow-reason-${instance._id}`;
6845
+ useLogEventOnMount(WorkflowAbortDialogOpened, {
6846
+ instanceId: instance._id
6847
+ });
6848
+ const confirm = async () => {
6849
+ if (reason === void 0) return;
6850
+ const log = outcome => telemetry.log(WorkflowAbortDialogSubmitted, {
6851
+ instanceId: instance._id,
6852
+ outcome: outcome
6853
+ });
6854
+ setPending(!0);
6855
+ try {
6856
+ const {changed: changed} = await engine.abortInstance({
6857
+ instanceId: instance._id,
6858
+ reason: reason
6859
+ }), report = abortCommitReport({
6860
+ title: title,
6861
+ changed: changed
6862
+ });
6863
+ toast.push(report.toast), log(report.outcome), onClose();
6864
+ } catch (err) {
6865
+ toast.push(abortUnconfirmedToast({
6866
+ title: title,
6867
+ err: err
6868
+ })), log("unconfirmed"), setPending(!1);
6869
+ }
6870
+ };
6871
+ /* @__PURE__ */
6872
+ return jsx(Dialog, {
6873
+ footer: /* @__PURE__ */ jsx(Box, {
6874
+ padding: 3,
6875
+ children: /* @__PURE__ */ jsxs(Flex, {
6876
+ gap: 2,
6877
+ justify: "flex-end",
6878
+ children: [
6879
+ /* @__PURE__ */ jsx(Button, {
6880
+ disabled: pending,
6881
+ fontSize: 1,
6882
+ mode: "bleed",
6883
+ onClick: onClose,
6884
+ padding: 2,
6885
+ text: "Cancel"
6886
+ }),
6887
+ /* @__PURE__ */ jsx(Button, {
6888
+ disabled: reason === void 0,
6889
+ fontSize: 1,
6890
+ loading: pending,
6891
+ onClick: () => {
6892
+ confirm();
6893
+ },
6894
+ padding: 2,
6895
+ text: "Abort workflow",
6896
+ tone: "critical"
6897
+ }) ]
6898
+ })
6899
+ }),
6900
+ header: "Abort workflow",
6901
+ id: `abort-workflow-${instance._id}`,
6902
+ onClose: () => {
6903
+ pending || onClose();
6904
+ },
6905
+ width: 0,
6906
+ children: /* @__PURE__ */ jsx(Box, {
6907
+ padding: 4,
6908
+ children: /* @__PURE__ */ jsxs(Stack, {
6909
+ gap: 5,
6910
+ children: [
6911
+ /* @__PURE__ */ jsxs(Text, {
6912
+ size: 1,
6913
+ children: [ "Abort the ",
6914
+ /* @__PURE__ */ jsx("strong", {
6915
+ children: title
6916
+ }), " workflow? This cannot be undone." ]
6917
+ }),
6918
+ /* @__PURE__ */ jsxs(Stack, {
6919
+ gap: 3,
6920
+ children: [
6921
+ /* @__PURE__ */ jsx(Text, {
6922
+ as: "label",
6923
+ htmlFor: reasonInputId,
6924
+ size: 1,
6925
+ weight: "medium",
6926
+ children: "Reason"
6927
+ }),
6928
+ /* @__PURE__ */ jsx(TextInput, {
6929
+ autoFocus: !0,
6930
+ fontSize: 1,
6931
+ id: reasonInputId,
6932
+ onChange: event => setTypedReason(event.currentTarget.value),
6933
+ placeholder: "Why is this workflow being stopped?",
6934
+ value: typedReason
6935
+ }) ]
6936
+ }) ]
6937
+ })
6938
+ })
6939
+ });
6940
+ }
6941
+
6942
+ function makeTitleResolver(definition) {
6943
+ const activities = (definition?.stages ?? []).flatMap(s => s.activities ?? []);
6944
+ return {
6945
+ action: (activityName, actionName) => activities.find(t => t.name === activityName)?.actions?.find(a => a.name === actionName)?.title ?? actionName,
6946
+ activity: name => activities.find(t => t.name === name)?.title ?? name,
6947
+ stage: name => stageTitle(definition, name)
6948
+ };
6949
+ }
6950
+
6951
+ function attributed(actor, ...parts) {
6952
+ if (actor) return {
6953
+ actorId: actor.id,
6954
+ parts: parts
6955
+ };
6956
+ const [first, ...rest] = parts;
6957
+ return typeof first != "string" ? {
6958
+ actorId: void 0,
6959
+ parts: parts
6960
+ } : {
6961
+ actorId: void 0,
6962
+ parts: [ first.charAt(0).toUpperCase() + first.slice(1), ...rest ]
6963
+ };
6964
+ }
6965
+
6966
+ function standalone(...parts) {
6967
+ return {
6968
+ actorId: void 0,
6969
+ parts: parts
6970
+ };
6971
+ }
6972
+
6973
+ const historyLiner = {
6974
+ stageEntered: (h, titles) => attributed(h.actor, `entered ${titles.stage(h.stage)}${h.fromStage ? ` from ${titles.stage(h.fromStage)}` : ""}`),
6975
+ stageExited: (h, titles) => attributed(h.actor, `left ${titles.stage(h.stage)} for ${titles.stage(h.toStage)}`),
6976
+ activityStatusChanged: (h, titles) => attributed(h.actor, `changed ${titles.activity(h.activity)}: ${h.from} → ${h.to}`),
6977
+ actionFired: (h, titles) => {
6978
+ const phrase = `fired ${titles.action(h.activity, h.action)} on ${titles.activity(h.activity)}`;
6979
+ return h.triggered ? standalone(`The workflow ${phrase}`) : attributed(h.actor, phrase);
6980
+ },
6981
+ transitionFired: (h, titles) => attributed(h.actor, `moved ${titles.stage(h.fromStage)} → ${titles.stage(h.toStage)}`),
6982
+ effectQueued: h => standalone("Effect ", {
6983
+ code: h.effect
6984
+ }, " queued"),
6985
+ effectCompleted: h => {
6986
+ const detail = h.detail ? ` — ${h.detail}` : "";
6987
+ return h.actor ? attributed(h.actor, "resolved effect ", {
6988
+ code: h.effect
6989
+ }, ` — ${h.status}${detail}`) : standalone("Effect ", {
6990
+ code: h.effect
6991
+ }, ` ${h.status}${detail}`);
6992
+ },
6993
+ effectClaimReleased: h => attributed(h.actor, "released a stale claim on effect ", {
6994
+ code: h.effect
6995
+ }, ` ${h.via === "sweep" ? "via the sweeper" : "via a drain takeover"}`),
6996
+ spawned: (h, titles) => attributed(h.actor, `spawned a child workflow from ${titles.activity(h.activity)}`),
6997
+ subworkflowAdopted: (h, titles) => standalone(`Re-adopted child workflow into ${titles.activity(h.activity)} on re-entering ${titles.stage(h.stage)}`),
6998
+ subworkflowResolved: (h, titles) => standalone(`Child workflow of ${titles.activity(h.activity)} ${h.status === "done" ? "completed" : "was aborted"}`),
6999
+ subworkflowOrphaned: h => standalone(`Orphaned child workflow reached terminal — ${h.detail}`),
7000
+ aborted: (h, titles) => attributed(h.actor, `aborted the workflow at ${titles.stage(h.stage)}${h.reason ? ` — ${h.reason}` : ""}`),
7001
+ 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 ", {
7002
+ code: h.opType
7003
+ }),
7004
+ fieldQueryDiscarded: h => standalone({
7005
+ code: JSON.stringify(h)
7006
+ })
7007
+ };
7008
+
7009
+ function historyLine(h, titles) {
7010
+ return historyLiner[h._type](h, titles);
7011
+ }
7012
+
7013
+ function CodeChip({value: value}) {
7014
+ /* @__PURE__ */
7015
+ return jsx("code", {
7016
+ style: {
7017
+ overflowWrap: "anywhere"
7018
+ },
7019
+ children: value
7020
+ });
7021
+ }
7022
+
7023
+ function HintedMenuButton({hint: hint, ...menuButtonProps}) {
7024
+ const [open, setOpen] = useState(!1), popover = {
7025
+ tone: "default",
7026
+ ...menuButtonProps.popover?.placement === void 0 ? {
7027
+ placement: "bottom-end",
7028
+ fallbackPlacements: [ "top-end" ]
7029
+ } : {},
7030
+ ...menuButtonProps.popover
7031
+ };
7032
+ return hint === void 0 ? /* @__PURE__ */ jsx(MenuButton, {
7033
+ ...menuButtonProps,
7034
+ popover: popover
7035
+ }) : /* @__PURE__ */ jsx(HoverHint, {
7036
+ disabled: open,
7037
+ text: hint,
7038
+ children: /* @__PURE__ */ jsx(MenuButton, {
7039
+ ...menuButtonProps,
7040
+ onClose: () => setOpen(!1),
7041
+ onOpen: () => setOpen(!0),
7042
+ popover: popover
7043
+ })
7044
+ });
7045
+ }
7046
+
7047
+ function historyWindow(args) {
7048
+ const {entries: entries, expanded: expanded} = args;
7049
+ return {
7050
+ overflows: entries.length > 6,
7051
+ shown: expanded ? entries : entries.slice(0, 6)
7052
+ };
7053
+ }
7054
+
7055
+ function PendingEffectRows({instance: instance, now: now}) {
7056
+ const {drainEffectsFor: drainEffectsFor, completeEffectFor: completeEffectFor, effectHandlers: effectHandlers} = useWorkflowContext(), toast = useWorkflowToast(), [busy, setBusy] = useState(!1), pending = instance.pendingEffects ?? [];
7057
+ if (pending.length === 0) return null;
7058
+ const runRegistered = async () => {
7059
+ setBusy(!0);
7060
+ try {
7061
+ await drainEffectsFor(instance._id), toast.push({
7062
+ id: TOAST_ID.effectsDrain,
7063
+ status: "info",
7064
+ title: "Ran the registered handlers"
7065
+ });
7066
+ } catch (err) {
7067
+ toast.push({
7068
+ id: TOAST_ID.effectsDrain,
7069
+ status: "error",
7070
+ title: "Failed to run pending effects",
7071
+ description: describeError(err)
7072
+ });
7073
+ } finally {
7074
+ setBusy(!1);
7075
+ }
7076
+ }, resolve = async (effectKey, status) => {
7077
+ setBusy(!0);
7078
+ try {
7079
+ await completeEffectFor(instance._id, {
7080
+ effectKey: effectKey,
7081
+ status: status,
7082
+ detail: "Resolved in Studio"
7083
+ }), toast.push({
7084
+ id: TOAST_ID.effectResolve,
7085
+ status: "info",
7086
+ title: `Effect marked as ${status}`
7087
+ });
7088
+ } catch (err) {
7089
+ toast.push({
7090
+ id: TOAST_ID.effectResolve,
7091
+ status: "error",
7092
+ title: "Failed to resolve the effect",
7093
+ description: describeError(err)
7094
+ });
7095
+ } finally {
7096
+ setBusy(!1);
7097
+ }
7098
+ };
7099
+ /* @__PURE__ */
7100
+ return jsx(Fragment, {
7101
+ children: pending.map(fx => /* @__PURE__ */ jsx(PendingEffectRow, {
7102
+ busy: busy,
7103
+ effect: fx,
7104
+ instanceId: instance._id,
7105
+ now: now,
7106
+ onResolve: status => resolve(fx._key, status),
7107
+ onRunHandlers: runRegistered,
7108
+ registered: fx.name in effectHandlers
7109
+ }, fx._key))
7110
+ });
7111
+ }
7112
+
7113
+ function PendingEffectRow({busy: busy, effect: effect, instanceId: instanceId, now: now, onResolve: onResolve, onRunHandlers: onRunHandlers, registered: registered}) {
7114
+ const label = effect.title ?? effect.name, avatarSize = useAvatarSize();
7115
+ /* @__PURE__ */
7116
+ return jsxs(Flex, {
7117
+ align: "center",
7118
+ gap: 2,
7119
+ children: [
7120
+ /* @__PURE__ */ jsx(FeedGlyph, {
7121
+ hint: "Waiting to run",
7122
+ icon: /* @__PURE__ */ jsx(ClockIcon, {})
7123
+ }),
7124
+ /* @__PURE__ */ jsxs(Flex, {
7125
+ align: "center",
7126
+ flex: 1,
7127
+ gap: 1,
7128
+ style: {
7129
+ minWidth: 0
7130
+ },
7131
+ children: [
7132
+ /* @__PURE__ */ jsx(Box, {
7133
+ style: {
7134
+ minWidth: 0
7135
+ },
7136
+ children: /* @__PURE__ */ jsxs(Text, {
7137
+ size: 1,
7138
+ textOverflow: "ellipsis",
7139
+ children: [ effect.title ?? /* @__PURE__ */ jsx(CodeChip, {
7140
+ value: effect.name
7141
+ }), registered ? " — ready to run in Studio" : " — waiting for the runtime" ]
7142
+ })
7143
+ }),
7144
+ /* @__PURE__ */ jsx(FeedStamp, {
7145
+ at: effect.queuedAt,
7146
+ now: now
7147
+ }) ]
7148
+ }),
7149
+ /* @__PURE__ */ jsx(Flex, {
7150
+ align: "center",
7151
+ flex: "none",
7152
+ style: {
7153
+ height: avatarSize
7154
+ },
7155
+ children: /* @__PURE__ */ jsx(HintedMenuButton, {
7156
+ button: /* @__PURE__ */ jsx(Button, {
7157
+ "aria-label": `Resolve ${label}`,
7158
+ disabled: busy,
7159
+ fontSize: 1,
7160
+ icon: EllipsisHorizontalIcon,
7161
+ mode: "bleed",
7162
+ padding: 2
7163
+ }),
7164
+ hint: "Resolve",
7165
+ id: `pending-effect-menu-${instanceId}-${effect._key}`,
7166
+ menu: /* @__PURE__ */ jsxs(Menu, {
7167
+ children: [ registered ? /* @__PURE__ */ jsx(MenuItem, {
7168
+ onClick: onRunHandlers,
7169
+ text: "Run registered handlers"
7170
+ }) : null,
7171
+ /* @__PURE__ */ jsx(MenuItem, {
7172
+ onClick: () => onResolve("done"),
7173
+ text: "Mark done"
7174
+ }),
7175
+ /* @__PURE__ */ jsx(MenuItem, {
7176
+ onClick: () => onResolve("failed"),
7177
+ text: "Mark failed",
7178
+ tone: "critical"
7179
+ }) ]
7180
+ }),
7181
+ popover: {
7182
+ placement: "bottom-end",
7183
+ portal: !0
7184
+ }
7185
+ })
7186
+ }) ]
7187
+ });
7188
+ }
7189
+
7190
+ function ActivityLog({instance: instance, definition: definition, windowed: windowed = !0}) {
7191
+ const titles = useMemo(() => makeTitleResolver(definition), [ definition ]), entries = useMemo(() => instance.history.toReversed(), [ instance.history ]), [now, setNow] = useState(() => /* @__PURE__ */ new Date), [expanded, setExpanded] = useState(!1);
7192
+ useEffect(() => {
7193
+ const timer = setInterval(() => setNow(/* @__PURE__ */ new Date), 6e4);
7194
+ return () => clearInterval(timer);
7195
+ }, []);
7196
+ const history = historyWindow({
7197
+ entries: entries,
7198
+ expanded: expanded || !windowed
7199
+ });
7200
+ return entries.length === 0 && (instance.pendingEffects ?? []).length === 0 ? /* @__PURE__ */ jsx(Text, {
7201
+ muted: !0,
7202
+ size: 1,
7203
+ children: "No activity yet"
7204
+ }) : /* @__PURE__ */ jsxs(Stack, {
7205
+ gap: 3,
7206
+ children: [
7207
+ /* @__PURE__ */ jsx(PendingEffectRows, {
7208
+ instance: instance,
7209
+ now: now
7210
+ }), history.shown.map(h => /* @__PURE__ */ jsx(HistoryRow, {
7211
+ entry: h,
7212
+ now: now,
7213
+ titles: titles
7214
+ }, h._key)), windowed && history.overflows ? /* @__PURE__ */ jsx(Flex, {
7215
+ children: /* @__PURE__ */ jsx(Button, {
7216
+ fontSize: 1,
7217
+ mode: "bleed",
7218
+ onClick: () => setExpanded(!expanded),
7219
+ padding: 2,
7220
+ text: expanded ? "Show less history" : "Show all history"
7221
+ })
7222
+ }) : null ]
7223
+ });
7224
+ }
7225
+
7226
+ function FeedStamp({at: at, now: now}) {
7227
+ /* @__PURE__ */
7228
+ return jsxs(Flex, {
7229
+ align: "center",
7230
+ flex: "none",
7231
+ gap: 1,
7232
+ children: [
7233
+ /* @__PURE__ */ jsx(Text, {
7234
+ muted: !0,
7235
+ size: 1,
7236
+ children: "·"
7237
+ }),
7238
+ /* @__PURE__ */ jsx(HoverHint, {
7239
+ text: formatDateTime(at),
7240
+ children: /* @__PURE__ */ jsx(Text, {
7241
+ muted: !0,
7242
+ size: 1,
7243
+ style: {
7244
+ whiteSpace: "nowrap"
7245
+ },
7246
+ children: formatShortAgo(at, now)
7247
+ })
7248
+ }) ]
7249
+ });
7250
+ }
7251
+
7252
+ function HistoryRow({entry: entry, now: now, titles: titles}) {
7253
+ const line = historyLine(entry, titles);
7254
+ /* @__PURE__ */
7255
+ return jsxs(Flex, {
7256
+ align: "center",
7257
+ gap: 2,
7258
+ children: [ line.actorId === void 0 ? /* @__PURE__ */ jsx(FeedGlyph, {
7259
+ hint: "The workflow",
7260
+ icon: /* @__PURE__ */ jsx(CogIcon, {})
7261
+ }) : /* @__PURE__ */ jsx(UserAvatar, {
7262
+ id: line.actorId
7263
+ }),
7264
+ /* @__PURE__ */ jsxs(Flex, {
7265
+ align: "center",
7266
+ flex: 1,
7267
+ gap: 1,
7268
+ style: {
7269
+ minWidth: 0
7270
+ },
7271
+ children: [
7272
+ /* @__PURE__ */ jsx(Box, {
7273
+ style: {
7274
+ minWidth: 0
7275
+ },
7276
+ children: /* @__PURE__ */ jsxs(Text, {
7277
+ muted: !0,
7278
+ size: 1,
7279
+ textOverflow: "ellipsis",
7280
+ children: [ line.actorId === void 0 ? null : /* @__PURE__ */ jsxs(Fragment, {
7281
+ children: [
7282
+ /* @__PURE__ */ jsx(ActorNameSpan, {
7283
+ id: line.actorId
7284
+ }), " " ]
7285
+ }), line.parts.map((part, index) => typeof part == "string" ? part : /* @__PURE__ */ jsx(CodeChip, {
7286
+ value: part.code
7287
+ }, index)) ]
7288
+ })
7289
+ }),
7290
+ /* @__PURE__ */ jsx(FeedStamp, {
7291
+ at: entry.at,
7292
+ now: now
7293
+ }) ]
7294
+ }) ]
7295
+ });
7296
+ }
7297
+
7298
+ function ActorNameSpan({id: id}) {
7299
+ const {name: name} = useUserDisplay(id), {font: font} = useTheme_v2();
7300
+ /* @__PURE__ */
7301
+ return jsx("span", {
7302
+ style: {
7303
+ fontWeight: font.text.weights.medium
7304
+ },
7305
+ children: name
7306
+ });
7307
+ }
7308
+
7309
+ function FeedGlyph({hint: hint, icon: icon}) {
7310
+ const size = useAvatarSize();
7311
+ /* @__PURE__ */
7312
+ return jsx(HoverHint, {
7313
+ text: hint,
7314
+ children: /* @__PURE__ */ jsx(Flex, {
7315
+ align: "center",
7316
+ flex: "none",
7317
+ justify: "center",
7318
+ style: {
7319
+ height: size,
7320
+ width: size
7321
+ },
7322
+ children: /* @__PURE__ */ jsx(Text, {
7323
+ muted: !0,
7324
+ size: 1,
7325
+ children: icon
7326
+ })
7327
+ })
7328
+ });
7329
+ }
7330
+
7331
+ function InstanceHistoryDialog({entry: entry, onClose: onClose}) {
7332
+ const definition = useDefinition(entry), {instance: instance} = entry;
7333
+ /* @__PURE__ */
7334
+ return jsx(Dialog, {
7335
+ header: /* @__PURE__ */ jsx(Breadcrumb, {
7336
+ emphasizeCurrent: !0,
7337
+ segments: [ instanceTitle(instance, definition), "History" ]
7338
+ }),
7339
+ id: `workflow-instance-history-${instance._id}`,
7340
+ onClose: onClose,
7341
+ width: 1,
7342
+ children: /* @__PURE__ */ jsx(Box, {
7343
+ padding: 4,
7344
+ children: /* @__PURE__ */ jsx(ActivityLog, {
7345
+ definition: definition,
7346
+ instance: instance,
7347
+ windowed: !1
7348
+ })
7349
+ })
7350
+ });
7351
+ }
7352
+
7353
+ function InstanceCardMenu({entry: entry, title: title}) {
7354
+ const [dialog, setDialog] = useState(void 0), menuId = useId(), close = () => setDialog(void 0);
7355
+ /* @__PURE__ */
7356
+ return jsxs(Fragment, {
7357
+ children: [
7358
+ /* @__PURE__ */ jsx(MenuButton, {
7359
+ button:
7360
+ /* @__PURE__ */ jsx(Button, {
7361
+ "aria-label": `More options for ${title}`,
7362
+ fontSize: 1,
7363
+ icon: EllipsisHorizontalIcon,
7364
+ mode: "bleed",
7365
+ padding: 2
7366
+ }),
7367
+ id: `workflow-instance-menu-${menuId}`,
7368
+ menu: /* @__PURE__ */ jsxs(Menu, {
7369
+ children: [
7370
+ /* @__PURE__ */ jsx(MenuItem, {
7371
+ onClick: () => setDialog("history"),
7372
+ text: "Workflow history"
7373
+ }), isLiveEntry(entry) ? /* @__PURE__ */ jsxs(Fragment, {
7374
+ children: [
7375
+ /* @__PURE__ */ jsx(MenuDivider, {}),
7376
+ /* @__PURE__ */ jsx(MenuItem, {
7377
+ onClick: () => setDialog("abort"),
7378
+ text: "Abort workflow…",
7379
+ tone: "critical"
7380
+ }) ]
7381
+ }) : null ]
7382
+ }),
7383
+ popover: {
7384
+ placement: "bottom-end",
7385
+ portal: !0
7386
+ }
7387
+ }), dialog === "history" ? /* @__PURE__ */ jsx(InstanceHistoryDialog, {
7388
+ entry: entry,
7389
+ onClose: close
7390
+ }) : null, dialog === "abort" ? /* @__PURE__ */ jsx(AbortWorkflowDialog, {
7391
+ entry: entry,
7392
+ onClose: close
7393
+ }) : null ]
6738
7394
  });
6739
7395
  }
6740
7396
 
6741
- function StageGlyph(props) {
7397
+ function InstanceCard({entry: entry, children: children, defaultOpen: defaultOpen}) {
7398
+ const definition = useDefinition(entry), {instance: instance} = entry, settled = !isLiveEntry(entry), [open, setOpen] = useState(defaultOpen ?? !settled), title = instanceTitle(instance, definition), menuSlot = useSpaceToken(2) * 2 + useTextIconSize();
6742
7399
  /* @__PURE__ */
6743
- return jsxs("svg", {
6744
- "data-sanity-icon": "stage",
6745
- fill: "none",
6746
- height: "1em",
6747
- viewBox: "0 0 25 25",
6748
- width: "1em",
6749
- xmlns: "http://www.w3.org/2000/svg",
6750
- ...props,
7400
+ return jsxs(Card, {
7401
+ border: !0,
7402
+ overflow: "hidden",
7403
+ radius: 4,
6751
7404
  children: [
6752
- /* @__PURE__ */ jsx("path", {
6753
- 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",
6754
- fill: "currentColor"
6755
- }),
6756
- /* @__PURE__ */ jsx("path", {
6757
- 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",
6758
- fill: "currentColor"
6759
- }),
6760
- /* @__PURE__ */ jsx("path", {
6761
- 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",
6762
- fill: "currentColor"
6763
- }) ]
7405
+ /* @__PURE__ */ jsxs(Box, {
7406
+ style: {
7407
+ position: "relative"
7408
+ },
7409
+ children: [
7410
+ /* @__PURE__ */ jsx(Card, {
7411
+ "aria-expanded": open,
7412
+ as: "button",
7413
+ onClick: () => setOpen(value => !value),
7414
+ padding: 3,
7415
+ style: {
7416
+ display: "block",
7417
+ textAlign: "left",
7418
+ width: "100%"
7419
+ },
7420
+ ...open ? {
7421
+ tone: "transparent"
7422
+ } : {},
7423
+ children: /* @__PURE__ */ jsxs(Flex, {
7424
+ align: "center",
7425
+ gap: 3,
7426
+ children: [
7427
+ /* @__PURE__ */ jsx(Text, {
7428
+ muted: !0,
7429
+ size: 1,
7430
+ children: open ? /* @__PURE__ */ jsx(ChevronDownIcon, {}) : /* @__PURE__ */ jsx(ChevronRightIcon, {})
7431
+ }),
7432
+ /* @__PURE__ */ jsxs(Stack, {
7433
+ flex: 1,
7434
+ gap: 2,
7435
+ style: {
7436
+ minWidth: 0
7437
+ },
7438
+ children: [
7439
+ /* @__PURE__ */ jsx(Text, {
7440
+ size: 1,
7441
+ textOverflow: "ellipsis",
7442
+ weight: "medium",
7443
+ children: title
7444
+ }),
7445
+ /* @__PURE__ */ jsx(HeaderStage, {
7446
+ entry: entry
7447
+ }) ]
7448
+ }),
7449
+ /* @__PURE__ */ jsxs(Flex, {
7450
+ align: "center",
7451
+ flex: "none",
7452
+ children: [
7453
+ /* @__PURE__ */ jsx(HeaderBadges, {
7454
+ instance: instance,
7455
+ settled: settled
7456
+ }),
7457
+ /* @__PURE__ */ jsx(Box, {
7458
+ flex: "none",
7459
+ style: {
7460
+ width: menuSlot
7461
+ }
7462
+ }) ]
7463
+ }) ]
7464
+ })
7465
+ }),
7466
+ /* @__PURE__ */ jsx(Flex, {
7467
+ align: "center",
7468
+ style: {
7469
+ bottom: 0,
7470
+ position: "absolute",
7471
+ right: 0,
7472
+ top: 0
7473
+ },
7474
+ children: /* @__PURE__ */ jsx(Box, {
7475
+ paddingRight: 3,
7476
+ children: /* @__PURE__ */ jsx(InstanceCardMenu, {
7477
+ entry: entry,
7478
+ title: title
7479
+ })
7480
+ })
7481
+ }) ]
7482
+ }), open ? /* @__PURE__ */ jsxs(Fragment, {
7483
+ children: [
7484
+ /* @__PURE__ */ jsx(Hairline, {
7485
+ weight: 1
7486
+ }),
7487
+ /* @__PURE__ */ jsx(Box, {
7488
+ padding: 3,
7489
+ children: children
7490
+ }) ]
7491
+ }) : null ]
6764
7492
  });
6765
7493
  }
6766
7494
 
6767
- function StageFace({completed: completed = !1, detail: detail, title: title}) {
6768
- const tone = completed ? "default" : "primary";
7495
+ function HeaderStage({entry: entry}) {
7496
+ const definition = useDefinition(entry), badgeTrim = useBadgeCapTrim(), face = instanceStageFace({
7497
+ definition: definition,
7498
+ instance: entry.instance
7499
+ });
7500
+ /* @__PURE__ */
7501
+ return jsx(Flex, {
7502
+ align: "center",
7503
+ children: face === void 0 ? /* @__PURE__ */ jsx(StartIncompleteBadge, {
7504
+ style: badgeTrim
7505
+ }) : /* @__PURE__ */ jsx(StageFace, {
7506
+ ...face.detail === void 0 ? {} : {
7507
+ detail: face.detail
7508
+ },
7509
+ completed: face.completed,
7510
+ glyph: !1,
7511
+ title: face.title
7512
+ })
7513
+ });
7514
+ }
7515
+
7516
+ function HeaderBadges({instance: instance, settled: settled}) {
7517
+ const badgeTrim = useBadgeCapTrim();
6769
7518
  /* @__PURE__ */
6770
7519
  return jsxs(Flex, {
6771
7520
  align: "center",
6772
- as: "span",
7521
+ flex: "none",
6773
7522
  gap: 2,
7523
+ style: badgeTrim,
6774
7524
  children: [
6775
- /* @__PURE__ */ jsx(TextWithTone, {
6776
- size: 1,
6777
- tone: tone,
6778
- children: completed ? /* @__PURE__ */ jsx(CheckmarkCircleFilledIcon, {
6779
- style: {
6780
- color: "inherit"
6781
- }
6782
- }) : /* @__PURE__ */ jsx(StageGlyph, {
6783
- style: {
6784
- color: "inherit"
6785
- }
6786
- })
6787
- }),
6788
- /* @__PURE__ */ jsx(TextWithTone, {
6789
- size: 1,
6790
- tone: tone,
6791
- weight: "medium",
6792
- children: title
6793
- }), detail === void 0 ? null : /* @__PURE__ */ jsx(Text, {
6794
- muted: !0,
6795
- size: 1,
6796
- children: detail
7525
+ /* @__PURE__ */ jsx(AbortedBadge, {
7526
+ instance: instance
7527
+ }), settled ? null : /* @__PURE__ */ jsx(OlderDefinitionBadge, {
7528
+ instance: instance
6797
7529
  }) ]
6798
7530
  });
6799
7531
  }
6800
7532
 
6801
- function StageChip({completed: completed = !1, detail: detail, interactive: interactive = !1, title: title}) {
6802
- const {color: color} = useTheme_v2();
7533
+ function PartOfBand({instance: instance}) {
7534
+ const parentRef = instance.ancestors.at(-1), parentId = parentRef ? toBareId(parentRef.id) : null, parentEntry = useWorkflowInstanceEntry(parentId), parentDefinition = useDefinition(parentEntry);
7535
+ if (!parentId) return null;
7536
+ const title = parentEntry ? instanceTitle(parentEntry.instance, parentDefinition) : parentId;
6803
7537
  /* @__PURE__ */
6804
7538
  return jsx(Card, {
7539
+ border: !0,
6805
7540
  padding: 3,
6806
- radius: 4,
6807
- style: {
6808
- boxShadow: `inset 0 0 0 1px ${completed ? color.badge.default.fg : color.focusRing}`,
6809
- cursor: interactive ? "help" : "default"
6810
- },
6811
- tone: completed ? "default" : "primary",
6812
- ...interactive ? {
6813
- tabIndex: 0
6814
- } : {},
6815
- children: /* @__PURE__ */ jsx(StageFace, {
6816
- completed: completed,
6817
- title: title,
6818
- ...detail === void 0 ? {} : {
6819
- detail: detail
6820
- }
7541
+ radius: 3,
7542
+ tone: "primary",
7543
+ children: /* @__PURE__ */ jsxs(Flex, {
7544
+ align: "center",
7545
+ gap: 2,
7546
+ children: [
7547
+ /* @__PURE__ */ jsx(Text, {
7548
+ size: 1,
7549
+ children: /* @__PURE__ */ jsx(ArrowUpIcon, {})
7550
+ }),
7551
+ /* @__PURE__ */ jsxs(Text, {
7552
+ size: 1,
7553
+ children: [ "Part of ",
7554
+ /* @__PURE__ */ jsx("strong", {
7555
+ children: title
7556
+ }) ]
7557
+ }) ]
6821
7558
  })
6822
7559
  });
6823
7560
  }
@@ -6864,20 +7601,23 @@ function SpineNodeView({definition: definition, node: node, transitions: transit
6864
7601
  transitions: transitions
6865
7602
  })
6866
7603
  });
6867
- if (node.state === "current") /* @__PURE__ */
6868
- return jsx(HoverHint, {
6869
- content: card,
6870
- "data-testid": `spine-node-${node.name}`,
6871
- flush: !0,
6872
- children: /* @__PURE__ */ jsx(StageChip, {
6873
- ...node.round === void 0 ? {} : {
6874
- detail: `Round ${node.round}`
6875
- },
6876
- completed: node.completedAt !== void 0,
6877
- interactive: !0,
6878
- title: node.title
6879
- })
6880
- });
7604
+ if (node.state === "current") {
7605
+ const detail = roundDetail(node.round);
7606
+ /* @__PURE__ */
7607
+ return jsx(HoverHint, {
7608
+ content: card,
7609
+ "data-testid": `spine-node-${node.name}`,
7610
+ flush: !0,
7611
+ children: /* @__PURE__ */ jsx(StageChip, {
7612
+ ...detail === void 0 ? {} : {
7613
+ detail: detail
7614
+ },
7615
+ completed: node.completedAt !== void 0,
7616
+ interactive: !0,
7617
+ title: node.title
7618
+ })
7619
+ });
7620
+ }
6881
7621
  const Icon = NODE_ICON[node.state];
6882
7622
  /* @__PURE__ */
6883
7623
  return jsx(HoverHint, {
@@ -7028,20 +7768,13 @@ function StampLines({stamp: stamp}) {
7028
7768
 
7029
7769
  function WorkflowInstanceSection({defaultOpen: defaultOpen, entry: entry, onOpenActivity: onOpenActivity}) {
7030
7770
  /* @__PURE__ */
7031
- return jsx(InstanceAccordion, {
7771
+ return jsx(InstanceCard, {
7032
7772
  defaultOpen: defaultOpen,
7033
7773
  entry: entry,
7034
- children: /* @__PURE__ */ jsxs(Stack, {
7035
- gap: 3,
7036
- children: [
7037
- /* @__PURE__ */ jsx(InstanceSnapshotBody, {
7038
- entry: entry,
7039
- onOpenActivity: onOpenActivity,
7040
- surface: "document-view"
7041
- }),
7042
- /* @__PURE__ */ jsx(InstanceToolLink, {
7043
- entry: entry
7044
- }) ]
7774
+ children: /* @__PURE__ */ jsx(InstanceSnapshotBody, {
7775
+ entry: entry,
7776
+ onOpenActivity: onOpenActivity,
7777
+ surface: "document-view"
7045
7778
  })
7046
7779
  });
7047
7780
  }
@@ -7068,7 +7801,9 @@ function InstanceSnapshotBody({entry: entry, onOpenActivity: onOpenActivity, sur
7068
7801
  /* @__PURE__ */ jsx(Card, {
7069
7802
  borderBottom: !0,
7070
7803
  padding: 2,
7071
- tone: definition ? "neutral" : "caution",
7804
+ ...definition ? {} : {
7805
+ tone: "caution"
7806
+ },
7072
7807
  children: definition ? /* @__PURE__ */ jsx(WorkflowSpine, {
7073
7808
  definition: definition,
7074
7809
  evaluation: entry.evaluation,
@@ -7243,30 +7978,6 @@ function openActivityGone(args) {
7243
7978
  return evaluation !== void 0 && !evaluation.currentStage.activities.some(a => a.activity.name === target.activityName);
7244
7979
  }
7245
7980
 
7246
- function HintedMenuButton({hint: hint, ...menuButtonProps}) {
7247
- const [open, setOpen] = useState(!1), popover = {
7248
- tone: "default",
7249
- ...menuButtonProps.popover?.placement === void 0 ? {
7250
- placement: "bottom-end",
7251
- fallbackPlacements: [ "top-end" ]
7252
- } : {},
7253
- ...menuButtonProps.popover
7254
- };
7255
- return hint === void 0 ? /* @__PURE__ */ jsx(MenuButton, {
7256
- ...menuButtonProps,
7257
- popover: popover
7258
- }) : /* @__PURE__ */ jsx(HoverHint, {
7259
- disabled: open,
7260
- text: hint,
7261
- children: /* @__PURE__ */ jsx(MenuButton, {
7262
- ...menuButtonProps,
7263
- onClose: () => setOpen(!1),
7264
- onOpen: () => setOpen(!0),
7265
- popover: popover
7266
- })
7267
- });
7268
- }
7269
-
7270
7981
  function subjectGdr(ctx) {
7271
7982
  return !ctx.subjectDocId || !ctx.mapping ? null : subjectGdrRef({
7272
7983
  mapping: ctx.mapping,
@@ -8086,7 +8797,7 @@ function DiscoverySpinner() {
8086
8797
  });
8087
8798
  }
8088
8799
 
8089
- const BOOT_CUE_DELAY_MS = 400, GROUP_GAP = 1;
8800
+ const BOOT_CUE_DELAY_MS = 400, GROUP_GAP = 2;
8090
8801
 
8091
8802
  function useWorkflowsTab() {
8092
8803
  const {params: params, setParams: setParams} = usePaneRouter();
@@ -8966,27 +9677,19 @@ function logOnce(messages, logged) {
8966
9677
  }
8967
9678
 
8968
9679
  function AssigneesInput({value: value, onChange: onChange}) {
8969
- const {members: members} = useProjectMembers(), [membersOpen, setMembersOpen] = useState(!1), roles = useMemo(() => [ ...new Set(members.flatMap(m => m.roles)) ].toSorted(), [ members ]), userIds = useMemo(() => new Set(value.flatMap(a => a.type === "user" ? [ a.id ] : [])), [ value ]), add = a => {
8970
- value.some(x => sameAssignee(x, a)) || onChange([ ...value, a ]);
8971
- }, remove = i => onChange(value.filter((_, idx) => idx !== i)), toggleUser = id => {
8972
- const user = {
8973
- type: "user",
8974
- id: id
8975
- };
8976
- userIds.has(id) ? onChange(value.filter(a => !sameAssignee(a, user))) : add(user);
8977
- };
9680
+ const [open, setOpen] = useState(!1), remove = index => onChange(value.filter((_, i) => i !== index));
8978
9681
  /* @__PURE__ */
8979
9682
  return jsxs(Stack, {
8980
9683
  gap: 2,
8981
9684
  children: [ value.length > 0 ? /* @__PURE__ */ jsx(Flex, {
8982
9685
  gap: 2,
8983
9686
  wrap: "wrap",
8984
- children: value.map((a, i) => /* @__PURE__ */ jsxs(Flex, {
9687
+ children: value.map((assignee, index) => /* @__PURE__ */ jsxs(Flex, {
8985
9688
  align: "center",
8986
9689
  gap: 1,
8987
9690
  children: [
8988
9691
  /* @__PURE__ */ jsx(AssigneeBadge, {
8989
- assignee: a
9692
+ assignee: assignee
8990
9693
  }),
8991
9694
  /* @__PURE__ */ jsx(HoverHint, {
8992
9695
  text: "Remove",
@@ -8995,60 +9698,33 @@ function AssigneesInput({value: value, onChange: onChange}) {
8995
9698
  fontSize: 1,
8996
9699
  icon: CloseIcon,
8997
9700
  mode: "bleed",
8998
- onClick: () => remove(i),
9701
+ onClick: () => remove(index),
8999
9702
  padding: 2
9000
9703
  })
9001
9704
  }) ]
9002
- }, a.type === "user" ? `user:${a.id}` : `role:${a.role}`))
9705
+ }, assignee.type === "user" ? `user:${assignee.id}` : `role:${assignee.role}`))
9003
9706
  }) : null,
9004
- /* @__PURE__ */ jsxs(Flex, {
9707
+ /* @__PURE__ */ jsx(Flex, {
9005
9708
  align: "center",
9006
9709
  gap: 2,
9007
9710
  wrap: "wrap",
9008
- children: [
9009
- /* @__PURE__ */ jsx(DismissablePopover, {
9010
- content: /* @__PURE__ */ jsx(MemberPicker, {
9011
- onSelect: member => member && toggleUser(member.id),
9012
- selectedIds: userIds
9711
+ children: /* @__PURE__ */ jsx(DismissablePopover, {
9712
+ content: /* @__PURE__ */ jsx(AssigneePicker, {
9713
+ onChange: next => onChange([ ...next ]),
9714
+ value: value
9013
9715
  }),
9014
- onDismiss: () => setMembersOpen(!1),
9015
- open: membersOpen,
9716
+ onDismiss: () => setOpen(!1),
9717
+ open: open,
9016
9718
  placement: "bottom-start",
9017
9719
  children: /* @__PURE__ */ jsx(Button, {
9018
9720
  fontSize: 1,
9019
9721
  icon: UserIcon,
9020
9722
  mode: "ghost",
9021
- onClick: () => setMembersOpen(v => !v),
9723
+ onClick: () => setOpen(v => !v),
9022
9724
  padding: 2,
9023
- text: "Add member"
9024
- })
9025
- }), roles.length > 0 ? /* @__PURE__ */ jsx(MenuButton, {
9026
- button: /* @__PURE__ */ jsx(Button, {
9027
- fontSize: 1,
9028
- icon: AddIcon,
9029
- mode: "ghost",
9030
- padding: 2,
9031
- text: "Add role"
9032
- }),
9033
- id: "assignees-add-role",
9034
- menu: /* @__PURE__ */ jsx(Menu, {
9035
- style: {
9036
- maxHeight: 280,
9037
- overflowY: "auto"
9038
- },
9039
- children: roles.map(r => /* @__PURE__ */ jsx(MenuItem, {
9040
- onClick: () => add({
9041
- type: "role",
9042
- role: r
9043
- }),
9044
- text: `Role: ${r}`
9045
- }, r))
9725
+ text: "Assign"
9046
9726
  })
9047
- }) : /* @__PURE__ */ jsx(Text, {
9048
- muted: !0,
9049
- size: 1,
9050
- children: "No project roles found"
9051
- }) ]
9727
+ })
9052
9728
  }) ]
9053
9729
  });
9054
9730
  }
@@ -9978,17 +10654,6 @@ function makePerspectiveBadge(documentId) {
9978
10654
  return WorkflowPerspectiveBadge;
9979
10655
  }
9980
10656
 
9981
- function StartIncompleteBadge({style: style}) {
9982
- /* @__PURE__ */
9983
- return jsx(Badge, {
9984
- fontSize: 1,
9985
- mode: "outline",
9986
- style: style,
9987
- tone: "caution",
9988
- children: "Start incomplete"
9989
- });
9990
- }
9991
-
9992
10657
  const GLANCE_CAP = 3;
9993
10658
 
9994
10659
  function AssignedTasksHint({work: work}) {
@@ -10498,4 +11163,4 @@ function WorkflowRootInput(props) {
10498
11163
  });
10499
11164
  }
10500
11165
 
10501
- export { ActivityDetailDialog, ActivityRow, BreadcrumbTail, CautionNote, CollapsibleBand, CountedLabel, DismissablePopover, DocPreviewLink, DocRefFace, EmptyState, ForMeEmptyState, Hairline, HintedMenuButton, HoverHint, InstanceSnapshotBody, InvalidDocNotice, LinkChip, LoadingRow, LogEventOnMount, MetaRow, SpinnerSlot, StageFace, StaleLock, TOAST_ID, TOOL_TABS, TabSwitch, TrailingHairline, UnreadableDocsNote, UserAvatar, WORKFLOW_API_VERSION, WORKFLOW_PAGE_TABS, WorkflowAbortDialogOpened, WorkflowAbortDialogSubmitted, WorkflowBoardWorkflowSelected, WorkflowDefinitionDetailViewed, WorkflowInstanceDetailViewed, WorkflowTaskFiltersApplied, WorkflowTitleSeedDrifted, WorkflowToolOpened, activityRowProps, assigneeUserIdsOf, backToTabLabel, committedRowFace, createSubscribers, datesOf, definitionFingerprint, definitionSnapshotOf, describeError, dueDatesOf, findActivity, findActivityNode, formatDate, formatDateTime, formatShortAgo, formatShortDateTime, formatTimeAgo, gdrLocality, instanceBreadcrumb, instanceState, instanceTitle, isActivityAssignedTo, isEvaluationStale, isLiveEntry, isOpenActivityStatus, landingState, mappingIssueDetail, namesNoDeployedDefinition, openActivityGone, openableSchemaType, parseStoredDateValue, readDeployedDefinitions, rowAssignControlState, rowDateControlState, stageTitle, stateByActivity, tabSelectionNavigates, toolRoute, toolTabState, useAssignmentIdentity, useAvatarSize, useBadgeCapTrim, useContainerToken, useDefinition, useDelayedFlag, useLogEventOnMount, useProjectMembers, useSpaceToken, useUserDisplay, useUserDisplays, useWorkflowContext, useWorkflowInstanceEntry, useWorkflowToast, workflowDefaultDocumentNode, workflowPageState, workflowState, workflowStudioPlugin, workflowsView };
11166
+ export { AbortWorkflowDialog, ActivityDetailDialog, ActivityLog, ActivityRow, BreadcrumbTail, CautionNote, CodeChip, CountedLabel, DismissablePopover, DocPreviewLink, DocRefFace, EmptyState, ForMeEmptyState, Hairline, HoverHint, InstanceSnapshotBody, InvalidDocNotice, LinkChip, LoadingRow, LogEventOnMount, MetaRow, SpinnerSlot, StageFace, StaleLock, TOAST_ID, TOOL_TABS, TabSwitch, UnreadableDocsNote, WORKFLOW_API_VERSION, WORKFLOW_PAGE_TABS, WorkflowBoardWorkflowSelected, WorkflowDefinitionDetailViewed, WorkflowInstanceDetailViewed, WorkflowTaskFiltersApplied, WorkflowTitleSeedDrifted, WorkflowToolOpened, activityRowProps, assigneesOf, backToTabLabel, committedRowFace, createSubscribers, datesOf, definitionFingerprint, definitionSnapshotOf, describeError, dueDatesOf, findActivity, findActivityNode, formatDate, formatShortDateTime, formatTimeAgo, gdrLocality, instanceBreadcrumb, instanceState, instanceTitle, isActivityAssignedTo, isEvaluationStale, isLiveEntry, isOpenActivityStatus, landingState, mappingIssueDetail, namesNoDeployedDefinition, openActivityGone, openableSchemaType, parseStoredDateValue, readDeployedDefinitions, rowAssignControlState, rowDateControlState, stageTitle, stateByActivity, tabSelectionNavigates, toolRoute, toolTabState, useAssignmentIdentity, useBadgeCapTrim, useContainerToken, useDefinition, useDelayedFlag, useLogEventOnMount, useProjectMembers, useSpaceToken, useUserDisplays, useWorkflowContext, useWorkflowInstanceEntry, useWorkflowToast, workflowDefaultDocumentNode, workflowPageState, workflowState, workflowStudioPlugin, workflowsView };