@sanity/workflow-studio-plugin 0.29.0 → 0.31.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.
@@ -291,7 +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", WORKFLOW_INTENT = "workflow";
294
+ const WORKFLOWS_TOOL_NAME = "workflows", WORKFLOW_INTENT = "workflow", RUN_SEARCH_PARAM = "run";
295
295
 
296
296
  function pathSegmentName(args) {
297
297
  return args.names.find(name => name === args.segment);
@@ -303,9 +303,10 @@ function handlesWorkflowIntent(intent, params) {
303
303
 
304
304
  function workflowIntentState(intent, params) {
305
305
  const instanceId = params.instanceId;
306
- return intent === WORKFLOW_INTENT && typeof instanceId == "string" ? {
307
- instanceId: instanceId
308
- } : null;
306
+ return intent !== WORKFLOW_INTENT || typeof instanceId != "string" ? null : {
307
+ workflowsTab: "overview",
308
+ _searchParams: [ [ RUN_SEARCH_PARAM, instanceId ] ]
309
+ };
309
310
  }
310
311
 
311
312
  const pad2 = n => String(n).padStart(2, "0"), DUE_DATE_FIELD_KINDS = [ "dueDate", "dueDatetime" ], DATE_FIELD_KINDS = [ "date", "datetime", ...DUE_DATE_FIELD_KINDS ], DATE_FIELD_KIND_SET = new Set(DATE_FIELD_KINDS), DUE_DATE_FIELD_KIND_SET = new Set(DUE_DATE_FIELD_KINDS);
@@ -402,14 +403,22 @@ function formatTimeAgo(value) {
402
403
  }
403
404
 
404
405
  function formatShortAgo(value, now) {
405
- const d = new Date(value);
406
- if (Number.isNaN(d.getTime())) return "—";
407
- const seconds = Math.floor((now.getTime() - d.getTime()) / 1e3);
408
- if (seconds < 60) return "just now";
406
+ const span = formatShortSpan(value, now);
407
+ return span === "—" ? "—" : span === "now" ? "just now" : `${span} ago`;
408
+ }
409
+
410
+ function formatShortSpan(value, now) {
411
+ return shortSpanOf(new Date(value), now);
412
+ }
413
+
414
+ function shortSpanOf(from, now) {
415
+ if (from === void 0 || Number.isNaN(from.getTime())) return "—";
416
+ const seconds = Math.floor((now.getTime() - from.getTime()) / 1e3);
417
+ if (seconds < 60) return "now";
409
418
  const minutes = Math.floor(seconds / 60);
410
- if (minutes < 60) return `${minutes}m ago`;
419
+ if (minutes < 60) return `${minutes}m`;
411
420
  const hours = Math.floor(minutes / 60);
412
- return hours < 24 ? `${hours}h ago` : `${Math.floor(hours / 24)}d ago`;
421
+ return hours < 24 ? `${hours}h` : `${Math.floor(hours / 24)}d`;
413
422
  }
414
423
 
415
424
  function stampFace(verb, at) {
@@ -633,7 +642,7 @@ function todoFieldEditability(args) {
633
642
  }
634
643
 
635
644
  function itemRow(args) {
636
- const {item: item, items: items, field: field, source: source, ticks: ticks, editability: editability} = args, tick = ticks.get(tickKey(field.name, item._key));
645
+ const {item: item, items: items, field: field, source: source, ticks: ticks, editability: editability} = args, tick = ticks.get(tickKey(field.name, item._key)), eligibleAssigneeRoles = field.of.find(column => column.name === "assignee" && column.type === "assignee")?.roles;
637
646
  return {
638
647
  item: item,
639
648
  items: items,
@@ -648,6 +657,9 @@ function itemRow(args) {
648
657
  ...editability.editDisabledReason ? {
649
658
  editDisabledReason: editability.editDisabledReason
650
659
  } : {},
660
+ ...eligibleAssigneeRoles === void 0 ? {} : {
661
+ eligibleAssigneeRoles: eligibleAssigneeRoles
662
+ },
651
663
  ...tick ? {
652
664
  tick: tick
653
665
  } : {}
@@ -716,6 +728,10 @@ function assigneesOf(entries) {
716
728
  return entries.flatMap(entry => entry._type === "assignees" ? entry.value : []);
717
729
  }
718
730
 
731
+ function userIdsOf(assignees) {
732
+ return assignees.flatMap(assignee => assignee.type === "user" ? [ assignee.id ] : []);
733
+ }
734
+
719
735
  function assigneeEdit(current, next) {
720
736
  const changed = changedAssignee(current, next);
721
737
  if (changed !== void 0) return next.some(item => workflowComponents.sameAssignee(item, changed)) ? {
@@ -895,8 +911,15 @@ const ACTIVITY_STATUS_LABEL = {
895
911
  skipped: "Skipped"
896
912
  };
897
913
 
914
+ function isHandsOff(args) {
915
+ return args.classification === "autonomous" && args.completesWithoutCaller === "yes";
916
+ }
917
+
898
918
  function showsAutomatedPill(activityEval) {
899
- return !workflowEngine.isTerminalActivityStatus(activityEval.status) && activityEval.classification === "autonomous" && activityEval.autonomy.completesWithoutCaller === "yes";
919
+ return !workflowEngine.isTerminalActivityStatus(activityEval.status) && isHandsOff({
920
+ classification: activityEval.classification,
921
+ completesWithoutCaller: activityEval.autonomy.completesWithoutCaller
922
+ });
900
923
  }
901
924
 
902
925
  function showsBlockedTag(activityEval) {
@@ -1047,24 +1070,10 @@ function dateValuesOf(state, matches) {
1047
1070
  return state.filter(entry => matches(entry._type)).map(entry => entry.value).filter(value => typeof value == "string" && value !== "");
1048
1071
  }
1049
1072
 
1050
- function datesOf(state) {
1051
- return dateValuesOf(state, isDateFieldKind);
1052
- }
1053
-
1054
1073
  function dueDatesOf(state) {
1055
1074
  return dateValuesOf(state, isDueDateFieldKind);
1056
1075
  }
1057
1076
 
1058
- function committedRowFace(row) {
1059
- return {
1060
- activityName: row.activityName,
1061
- title: row.title,
1062
- status: row.status,
1063
- automated: !1,
1064
- blocked: !1
1065
- };
1066
- }
1067
-
1068
1077
  function activityRowProps(args) {
1069
1078
  const {activityEval: activityEval, activityState: activityState, editableFields: editableFields} = args, state = activityState.get(activityEval.activity.name) ?? [], controlArgs = {
1070
1079
  activity: activityEval.activity,
@@ -1163,15 +1172,15 @@ function useWorkflowInstanceEntry(instanceId, options = {}) {
1163
1172
  }
1164
1173
 
1165
1174
  const WorkflowToolOpened = telemetry.defineEvent({
1166
- name: "Editorial Workflows Studio Plugin Tool Opened",
1167
- version: 2,
1175
+ name: "Workflows Studio Plugin Tool Opened",
1176
+ version: 3,
1168
1177
  description: "The Workflows tool was opened or its tab was switched"
1169
1178
  }), WorkflowDocumentViewOpened = telemetry.defineEvent({
1170
- name: "Editorial Workflows Studio Plugin Document View Opened",
1179
+ name: "Workflows Studio Plugin Document View Opened",
1171
1180
  version: 1,
1172
1181
  description: "The Workflows document view was opened or its tab was switched"
1173
1182
  }), WorkflowInstanceDetailViewed = telemetry.defineEvent({
1174
- name: "Editorial Workflows Studio Plugin Instance Detail Viewed",
1183
+ name: "Workflows Studio Plugin Instance Detail Viewed",
1175
1184
  version: 1,
1176
1185
  description: "The Workflows tool's per-instance detail view was opened"
1177
1186
  });
@@ -1184,67 +1193,63 @@ function definitionFingerprint(definition) {
1184
1193
  }
1185
1194
 
1186
1195
  const WorkflowDefinitionDetailViewed = telemetry.defineEvent({
1187
- name: "Editorial Workflows Studio Plugin Definition Detail Viewed",
1196
+ name: "Workflows Studio Plugin Definition Detail Viewed",
1188
1197
  version: 1,
1189
1198
  description: "A workflow's definition page was opened in the Workflows tool"
1190
1199
  }), WorkflowFormStripClicked = telemetry.defineEvent({
1191
- name: "Editorial Workflows Studio Plugin Form Strip Clicked",
1200
+ name: "Workflows Studio Plugin Form Strip Clicked",
1192
1201
  version: 1,
1193
1202
  description: "The form strip's instance line was clicked, opening the document view"
1194
1203
  }), WorkflowDocumentLinkClicked = telemetry.defineEvent({
1195
- name: "Editorial Workflows Studio Plugin Document Link Clicked",
1196
- version: 2,
1204
+ name: "Workflows Studio Plugin Document Link Clicked",
1205
+ version: 3,
1197
1206
  description: "A document link was clicked, opening the referenced document's editor"
1198
1207
  }), WorkflowStartDialogOpened = telemetry.defineEvent({
1199
- name: "Editorial Workflows Studio Plugin Start Dialog Opened",
1208
+ name: "Workflows Studio Plugin Start Dialog Opened",
1200
1209
  version: 1,
1201
1210
  description: "The start-workflow dialog was opened"
1202
1211
  }), WorkflowStartDialogSubmitted = telemetry.defineEvent({
1203
- name: "Editorial Workflows Studio Plugin Start Dialog Submitted",
1212
+ name: "Workflows Studio Plugin Start Dialog Submitted",
1204
1213
  version: 1,
1205
1214
  description: "The start-workflow dialog's confirm was pressed"
1206
1215
  }), WorkflowAutoStartRan = telemetry.defineEvent({
1207
- name: "Editorial Workflows Studio Plugin Auto Start Ran",
1216
+ name: "Workflows Studio Plugin Auto Start Ran",
1208
1217
  version: 1,
1209
1218
  description: "A fresh document's auto-start ran — one start request per configured workflow"
1210
1219
  }), WorkflowActionControlUsed = telemetry.defineEvent({
1211
- name: "Editorial Workflows Studio Plugin Action Control Used",
1212
- version: 2,
1220
+ name: "Workflows Studio Plugin Action Control Used",
1221
+ version: 3,
1213
1222
  description: "An action-firing control was used, attributed to its UI surface"
1214
1223
  }), WorkflowFieldControlUsed = telemetry.defineEvent({
1215
- name: "Editorial Workflows Studio Plugin Field Control Used",
1216
- version: 1,
1224
+ name: "Workflows Studio Plugin Field Control Used",
1225
+ version: 2,
1217
1226
  description: "A field-editing control committed an edit, attributed to its UI surface"
1218
1227
  }), WorkflowActivityDialogOpened = telemetry.defineEvent({
1219
- name: "Editorial Workflows Studio Plugin Activity Dialog Opened",
1220
- version: 1,
1228
+ name: "Workflows Studio Plugin Activity Dialog Opened",
1229
+ version: 2,
1221
1230
  description: "The activity detail dialog was opened"
1222
- }), WorkflowTaskFiltersApplied = telemetry.defineEvent({
1223
- name: "Editorial Workflows Studio Plugin Task Filters Applied",
1224
- version: 1,
1225
- description: "The tool's task-filter menu closed with a changed selection"
1226
1231
  }), WorkflowBoardWorkflowSelected = telemetry.defineEvent({
1227
- name: "Editorial Workflows Studio Plugin Board Workflow Selected",
1228
- version: 2,
1229
- description: "The workflow documents page settled on the workflow it's showing"
1232
+ name: "Workflows Studio Plugin Board Workflow Selected",
1233
+ version: 3,
1234
+ description: "The Overview's board display settled on the workflow it's showing"
1230
1235
  }), WorkflowTitleSeedDrifted = telemetry.defineEvent({
1231
- name: "Editorial Workflows Studio Plugin Title Seed Drifted",
1236
+ name: "Workflows Studio Plugin Title Seed Drifted",
1232
1237
  version: 1,
1233
1238
  description: "A cold-start seeded preview title diverged from the live preview pipeline"
1234
1239
  }), WorkflowTodoToggled = telemetry.defineEvent({
1235
- name: "Editorial Workflows Studio Plugin Todo Toggled",
1240
+ name: "Workflows Studio Plugin Todo Toggled",
1236
1241
  version: 1,
1237
1242
  description: "A todo checkbox was toggled, attributed to its UI surface and write seam"
1238
1243
  }), WorkflowTodoEdited = telemetry.defineEvent({
1239
- name: "Editorial Workflows Studio Plugin Todo Edited",
1244
+ name: "Workflows Studio Plugin Todo Edited",
1240
1245
  version: 1,
1241
1246
  description: "A non-toggle todo-list write, attributed to its UI surface and gesture"
1242
1247
  }), WorkflowAbortDialogOpened = telemetry.defineEvent({
1243
- name: "Editorial Workflows Studio Plugin Abort Dialog Opened",
1248
+ name: "Workflows Studio Plugin Abort Dialog Opened",
1244
1249
  version: 1,
1245
1250
  description: "The abort-workflow confirm was opened"
1246
1251
  }), WorkflowAbortDialogSubmitted = telemetry.defineEvent({
1247
- name: "Editorial Workflows Studio Plugin Abort Dialog Submitted",
1252
+ name: "Workflows Studio Plugin Abort Dialog Submitted",
1248
1253
  version: 1,
1249
1254
  description: "The abort-workflow confirm was submitted, carrying the attempt's outcome"
1250
1255
  });
@@ -1280,6 +1285,12 @@ function scalarValidationIssue(args) {
1280
1285
  return issues === void 0 ? void 0 : `${args.label}: ${issues.join("; ")}`;
1281
1286
  }
1282
1287
 
1288
+ function countBy(rows, keysOf) {
1289
+ const counts = /* @__PURE__ */ new Map;
1290
+ for (const row of rows) for (const key of keysOf(row)) counts.set(key, (counts.get(key) ?? 0) + 1);
1291
+ return counts;
1292
+ }
1293
+
1283
1294
  function personActor(user) {
1284
1295
  const roles = user.roles.map(role => typeof role == "string" ? role : role.name);
1285
1296
  return {
@@ -1311,10 +1322,20 @@ function userDisplayFor(args) {
1311
1322
  return {
1312
1323
  id: args.id,
1313
1324
  name: member?.displayName ?? self?.name ?? args.id,
1314
- imageUrl: member?.imageUrl ?? self?.profileImage ?? void 0
1325
+ imageUrl: member?.imageUrl ?? self?.profileImage ?? void 0,
1326
+ loginProvider: member?.loginProvider
1315
1327
  };
1316
1328
  }
1317
1329
 
1330
+ function disambiguatedNames(displays) {
1331
+ const counts = countBy(displays, display => [ display.name ]);
1332
+ return displays.map(display => (counts.get(display.name) ?? 0) < 2 || display.loginProvider === void 0 ? display.name : `${display.name} (${workflowComponents.providerTitle(display.loginProvider) ?? display.loginProvider})`);
1333
+ }
1334
+
1335
+ function uniqueIds(ids) {
1336
+ return [ ...new Set(ids) ];
1337
+ }
1338
+
1318
1339
  function useUserDisplays(ids) {
1319
1340
  const {members: members} = useProjectMembers(), {users: users} = workflowStudio.useStudioProjectUsers(), meRaw = sanity.useCurrentUser(), me = react.useMemo(() => meRaw === null ? null : {
1320
1341
  ...meRaw,
@@ -1397,6 +1418,10 @@ function identityOf(state) {
1397
1418
  return state.kind === "resolved" ? state.identity : void 0;
1398
1419
  }
1399
1420
 
1421
+ function useCurrentUserId() {
1422
+ return identityOf(useAssignmentIdentity())?.userId;
1423
+ }
1424
+
1400
1425
  const projectMembersByUsers = /* @__PURE__ */ new WeakMap;
1401
1426
 
1402
1427
  function projectMembersFrom(users) {
@@ -1787,23 +1812,27 @@ function MemberPicker({selectedIds: selectedIds, onSelect: onSelect, unassignRow
1787
1812
  });
1788
1813
  }
1789
1814
 
1790
- function AssigneePicker({value: value, onChange: onChange}) {
1815
+ function AssigneePicker({value: value, onChange: onChange, eligibleRoles: eligibleRoles, roleAliases: roleAliases}) {
1791
1816
  const state = useProjectMembers();
1792
1817
  /* @__PURE__ */
1793
1818
  return jsxRuntime.jsx(workflowComponents.AssigneePicker, {
1794
1819
  ...state,
1820
+ eligibleRoles: eligibleRoles,
1795
1821
  onChange: onChange,
1822
+ roleAliases: roleAliases,
1796
1823
  value: value
1797
1824
  });
1798
1825
  }
1799
1826
 
1800
- function SingleAssigneePicker({current: current, onPick: onPick}) {
1827
+ function SingleAssigneePicker({current: current, onPick: onPick, eligibleRoles: eligibleRoles, roleAliases: roleAliases}) {
1801
1828
  /* @__PURE__ */
1802
1829
  return jsxRuntime.jsx(AssigneePicker, {
1830
+ eligibleRoles: eligibleRoles,
1803
1831
  onChange: next => {
1804
1832
  const picked = singleAssigneePick(current, next);
1805
1833
  picked !== void 0 && onPick(picked);
1806
1834
  },
1835
+ roleAliases: roleAliases,
1807
1836
  value: current ? [ current ] : []
1808
1837
  });
1809
1838
  }
@@ -2116,7 +2145,6 @@ const TOAST_ID = {
2116
2145
  effectResolve: "workflow-effect-resolve",
2117
2146
  effectsDrain: "workflow-effects-drain",
2118
2147
  effectsIncomplete: "workflow-effects-incomplete",
2119
- orphanSettle: "workflow-orphan-settle",
2120
2148
  start: "workflow-start"
2121
2149
  };
2122
2150
 
@@ -2976,8 +3004,7 @@ function PendingDocFace({bareId: bareId, layout: layout}) {
2976
3004
  children: id
2977
3005
  });
2978
3006
  }
2979
- return compact ?
2980
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
3007
+ return compact ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
2981
3008
  align: "center",
2982
3009
  gap: 2,
2983
3010
  children: [
@@ -3651,9 +3678,11 @@ function AssigneeField({field: field, instanceId: instanceId, onSave: onSave, on
3651
3678
  children: /* @__PURE__ */ jsxRuntime.jsx(DismissablePopover, {
3652
3679
  content: /* @__PURE__ */ jsxRuntime.jsx(SingleAssigneePicker, {
3653
3680
  current: cur,
3681
+ eligibleRoles: field.roles,
3654
3682
  onPick: picked => {
3655
3683
  setOpen(!1), pick(picked);
3656
- }
3684
+ },
3685
+ roleAliases: field.roleAliases
3657
3686
  }),
3658
3687
  onDismiss: () => setOpen(!1),
3659
3688
  open: open,
@@ -4332,6 +4361,12 @@ function useSpaceToken(index) {
4332
4361
  return value;
4333
4362
  }
4334
4363
 
4364
+ function useRadiusToken(index) {
4365
+ const value = ui.useTheme_v2().radius[index];
4366
+ if (value === void 0) throw new Error(`theme is missing radius token ${index}`);
4367
+ return value;
4368
+ }
4369
+
4335
4370
  function useContainerToken(index) {
4336
4371
  const value = ui.useTheme_v2().container[index];
4337
4372
  if (value === void 0) throw new Error(`theme is missing container token ${index}`);
@@ -4372,10 +4407,9 @@ function useBadgeCapTrim() {
4372
4407
  };
4373
4408
  }
4374
4409
 
4375
- function SpinnerSlot({busy: busy}) {
4410
+ function SpinnerSlot({busy: busy, reserve: reserve = !0}) {
4376
4411
  const size = useTextIconSize(), trim = useCapTrimFor(size), spinning = useDelayedFlag(busy, LOADING_CUE_DELAY_MS);
4377
- /* @__PURE__ */
4378
- return jsxRuntime.jsx(ui.Flex, {
4412
+ return !spinning && !reserve ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
4379
4413
  align: "center",
4380
4414
  flex: "none",
4381
4415
  justify: "center",
@@ -4464,13 +4498,12 @@ function AvatarButton({avatar: avatar, onClick: onClick, onMouseDown: onMouseDow
4464
4498
  }
4465
4499
 
4466
4500
  function RowAssignees({assignees: assignees, hint: hint}) {
4467
- const ids = assignees.flatMap(item => item.type === "user" ? [ item.id ] : []), vocabulary = useProjectMembers(), roles = assignees.flatMap(item => item.type === "role" ? [ workflowComponents.memberRoleFor(vocabulary, item.role) ] : []), displays = useUserDisplays(ids);
4501
+ const ids = userIdsOf(assignees), vocabulary = useProjectMembers(), roles = assignees.flatMap(item => item.type === "role" ? [ workflowComponents.memberRoleFor(vocabulary, item.role) ] : []), displays = useUserDisplays(ids);
4468
4502
  if (ids.length === 0 && roles.length === 0) return null;
4469
4503
  const bothKinds = roles.length > 0 && displays.length > 0;
4470
4504
  /* @__PURE__ */
4471
4505
  return jsxRuntime.jsx(HoverHint, {
4472
- content:
4473
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
4506
+ content: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
4474
4507
  gap: 3,
4475
4508
  children: [ roles.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(HintSection, {
4476
4509
  names: roles.map(workflowComponents.roleLabel),
@@ -4478,7 +4511,7 @@ function RowAssignees({assignees: assignees, hint: hint}) {
4478
4511
  label: "Roles"
4479
4512
  } : {}
4480
4513
  }) : null, displays.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(HintSection, {
4481
- names: displays.map(display => display.name),
4514
+ names: disambiguatedNames(displays),
4482
4515
  ...bothKinds ? {
4483
4516
  label: "Members"
4484
4517
  } : {}
@@ -4557,8 +4590,7 @@ function AssignActivityControl({instanceId: instanceId, state: state, surface: s
4557
4590
  }
4558
4591
  }, handleClick = e => {
4559
4592
  e.stopPropagation(), setOpen(v => !v);
4560
- }, button = assignees.length > 0 ?
4561
- /* @__PURE__ */ jsxRuntime.jsx(AvatarButton, {
4593
+ }, button = assignees.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(AvatarButton, {
4562
4594
  "aria-label": "Assignees",
4563
4595
  as: "span",
4564
4596
  avatar: /* @__PURE__ */ jsxRuntime.jsx(RowAssignees, {
@@ -4588,9 +4620,11 @@ function AssignActivityControl({instanceId: instanceId, state: state, surface: s
4588
4620
  label: "Loading…",
4589
4621
  padding: 3
4590
4622
  }) : /* @__PURE__ */ jsxRuntime.jsx(AssigneePicker, {
4623
+ eligibleRoles: state.field.roles,
4591
4624
  onChange: next => {
4592
4625
  change(next);
4593
4626
  },
4627
+ roleAliases: state.field.roleAliases,
4594
4628
  value: current
4595
4629
  })
4596
4630
  }),
@@ -4692,8 +4726,7 @@ function DueDate({dueDate: dueDate, hintDisabled: hintDisabled, overdue: overdue
4692
4726
  const face = hintFace({
4693
4727
  overdue: overdue,
4694
4728
  reason: reason
4695
- }), text = overdue ?
4696
- /* @__PURE__ */ jsxRuntime.jsx(sanity.TextWithTone, {
4729
+ }), text = overdue ? /* @__PURE__ */ jsxRuntime.jsx(sanity.TextWithTone, {
4697
4730
  size: 1,
4698
4731
  tone: "caution",
4699
4732
  children: formatDate(dueDate)
@@ -4804,7 +4837,7 @@ function DueDateControl({item: item, editable: editable, onPatch: onPatch}) {
4804
4837
  }) : display;
4805
4838
  }
4806
4839
 
4807
- function AssigneeControl({item: item, editable: editable, onPatch: onPatch}) {
4840
+ function AssigneeControl({item: item, editable: editable, eligibleRoles: eligibleRoles, onPatch: onPatch, roleAliases: roleAliases}) {
4808
4841
  const [open, setOpen] = react.useState(!1), current = item.assignee ?? null, chip = current ? /* @__PURE__ */ jsxRuntime.jsx(RowAssignees, {
4809
4842
  assignees: [ current ]
4810
4843
  }) : null;
@@ -4812,11 +4845,13 @@ function AssigneeControl({item: item, editable: editable, onPatch: onPatch}) {
4812
4845
  content:
4813
4846
  /* @__PURE__ */ jsxRuntime.jsx(SingleAssigneePicker, {
4814
4847
  current: current,
4848
+ eligibleRoles: eligibleRoles,
4815
4849
  onPick: picked => {
4816
4850
  setOpen(!1), onPatch({
4817
4851
  assignee: picked
4818
4852
  });
4819
- }
4853
+ },
4854
+ roleAliases: roleAliases
4820
4855
  }),
4821
4856
  onDismiss: () => setOpen(!1),
4822
4857
  open: open,
@@ -4918,8 +4953,7 @@ function BreadcrumbTail({segments: segments, style: style}) {
4918
4953
  }
4919
4954
 
4920
4955
  function WorkRow({lead: lead, children: children, end: end, onOpen: onOpen}) {
4921
- const frame =
4922
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
4956
+ const frame = /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
4923
4957
  align: "center",
4924
4958
  children: [
4925
4959
  /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
@@ -4953,8 +4987,7 @@ function WorkRow({lead: lead, children: children, end: end, onOpen: onOpen}) {
4953
4987
  padding: 1,
4954
4988
  radius: 3,
4955
4989
  children: frame
4956
- }) :
4957
- /* @__PURE__ */ jsxRuntime.jsx(ui.Card, {
4990
+ }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Card, {
4958
4991
  as: "button",
4959
4992
  onClick: onOpen,
4960
4993
  padding: 1,
@@ -4966,7 +4999,7 @@ function WorkRow({lead: lead, children: children, end: end, onOpen: onOpen}) {
4966
4999
  });
4967
5000
  }
4968
5001
 
4969
- function TodoItemRowView({breadcrumb: breadcrumb, row: row, onToggle: onToggle, onPatch: onPatch, onRemove: onRemove}) {
5002
+ function TodoItemRowView({breadcrumb: breadcrumb, row: row, onToggle: onToggle, onPatch: onPatch, onRemove: onRemove, roleAliases: roleAliases}) {
4970
5003
  const {canClick: canClick, hint: hint} = rowInteractivity(row), editable = row.editTarget !== void 0, checkbox = /* @__PURE__ */ jsxRuntime.jsx(TodoCheckbox, {
4971
5004
  canClick: canClick,
4972
5005
  checked: isTodoDone(row.item),
@@ -4983,8 +5016,10 @@ function TodoItemRowView({breadcrumb: breadcrumb, row: row, onToggle: onToggle,
4983
5016
  }),
4984
5017
  /* @__PURE__ */ jsxRuntime.jsx(AssigneeControl, {
4985
5018
  editable: editable,
5019
+ eligibleRoles: row.eligibleAssigneeRoles,
4986
5020
  item: row.item,
4987
- onPatch: onPatch
5021
+ onPatch: onPatch,
5022
+ roleAliases: roleAliases
4988
5023
  }), onRemove === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(RemoveItemButton, {
4989
5024
  onClick: onRemove
4990
5025
  }) ]
@@ -5161,6 +5196,7 @@ function TodoItemsList({breadcrumb: breadcrumb, entry: entry, filter: filter, sh
5161
5196
  onToggle: () => {
5162
5197
  toggleRow(row);
5163
5198
  },
5199
+ roleAliases: definition?.roleAliases,
5164
5200
  row: row
5165
5201
  }, rowKey(row)))
5166
5202
  }), addControl === null ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
@@ -5719,6 +5755,13 @@ function GroupHeading({busy: busy, count: count, title: title, end: end}) {
5719
5755
 
5720
5756
  const EMPTY_METRIC_OPACITY = .5;
5721
5757
 
5758
+ function labelledImgProps(label) {
5759
+ return label === void 0 ? {} : {
5760
+ "aria-label": label,
5761
+ role: "img"
5762
+ };
5763
+ }
5764
+
5722
5765
  function MetricText({children: children, tone: tone}) {
5723
5766
  return tone === void 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
5724
5767
  muted: !0,
@@ -5731,34 +5774,42 @@ function MetricText({children: children, tone: tone}) {
5731
5774
  });
5732
5775
  }
5733
5776
 
5734
- function MetricPair({Icon: Icon, empty: empty, face: face, tone: tone, value: value}) {
5777
+ function MetricPair({face: face, ...lockup}) {
5735
5778
  /* @__PURE__ */
5736
5779
  return jsxRuntime.jsx(HoverHint, {
5737
5780
  ...face,
5738
- children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
5739
- align: "center",
5740
- gap: 2,
5741
- style: empty ? {
5742
- opacity: EMPTY_METRIC_OPACITY
5743
- } : void 0,
5744
- children: [
5745
- /* @__PURE__ */ jsxRuntime.jsx(MetricText, {
5746
- tone: tone,
5747
- children: /* @__PURE__ */ jsxRuntime.jsx(Icon, {
5748
- style: {
5749
- color: "inherit"
5750
- }
5751
- })
5752
- }),
5753
- /* @__PURE__ */ jsxRuntime.jsx(MetricText, {
5754
- tone: tone,
5755
- children: value
5756
- }) ]
5781
+ children: /* @__PURE__ */ jsxRuntime.jsx(MetricLockup, {
5782
+ ...lockup
5757
5783
  })
5758
5784
  });
5759
5785
  }
5760
5786
 
5761
- function AlertGlyph({Icon: Icon, hint: hint, tone: tone}) {
5787
+ function MetricLockup({Icon: Icon, empty: empty, label: label, tone: tone, value: value}) {
5788
+ /* @__PURE__ */
5789
+ return jsxRuntime.jsxs(ui.Flex, {
5790
+ align: "center",
5791
+ gap: 2,
5792
+ style: empty ? {
5793
+ opacity: EMPTY_METRIC_OPACITY
5794
+ } : void 0,
5795
+ ...labelledImgProps(label),
5796
+ children: [
5797
+ /* @__PURE__ */ jsxRuntime.jsx(MetricText, {
5798
+ tone: tone,
5799
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icon, {
5800
+ style: {
5801
+ color: "inherit"
5802
+ }
5803
+ })
5804
+ }),
5805
+ /* @__PURE__ */ jsxRuntime.jsx(MetricText, {
5806
+ tone: tone,
5807
+ children: value
5808
+ }) ]
5809
+ });
5810
+ }
5811
+
5812
+ function AlertGlyph({Icon: Icon, hint: hint, label: label, tone: tone}) {
5762
5813
  /* @__PURE__ */
5763
5814
  return jsxRuntime.jsx(HoverHint, {
5764
5815
  text: hint,
@@ -5766,6 +5817,7 @@ function AlertGlyph({Icon: Icon, hint: hint, tone: tone}) {
5766
5817
  size: 1,
5767
5818
  tone: tone,
5768
5819
  children: /* @__PURE__ */ jsxRuntime.jsx(Icon, {
5820
+ ...labelledImgProps(label),
5769
5821
  style: {
5770
5822
  color: "inherit"
5771
5823
  }
@@ -5774,6 +5826,37 @@ function AlertGlyph({Icon: Icon, hint: hint, tone: tone}) {
5774
5826
  });
5775
5827
  }
5776
5828
 
5829
+ function AlertChip({Icon: Icon, hint: hint, label: label, tone: tone}) {
5830
+ const glyph = useTextIconSize(), disc = glyph + useSpaceToken(1) * 2;
5831
+ /* @__PURE__ */
5832
+ return jsxRuntime.jsx(HoverHint, {
5833
+ text: hint,
5834
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Card, {
5835
+ radius: "full",
5836
+ style: {
5837
+ alignItems: "center",
5838
+ display: "flex",
5839
+ height: disc,
5840
+ justifyContent: "center",
5841
+ width: disc
5842
+ },
5843
+ tone: tone,
5844
+ children: /* @__PURE__ */ jsxRuntime.jsx(sanity.TextWithTone, {
5845
+ size: 1,
5846
+ tone: tone,
5847
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icon, {
5848
+ ...labelledImgProps(label),
5849
+ style: {
5850
+ color: "inherit",
5851
+ height: glyph,
5852
+ width: glyph
5853
+ }
5854
+ })
5855
+ })
5856
+ })
5857
+ });
5858
+ }
5859
+
5777
5860
  function ActivityDateControl({instanceId: instanceId, state: state, surface: surface, dueDates: dueDates}) {
5778
5861
  const editField = useEditField(surface), {save: save} = useSaveField({
5779
5862
  instanceId: instanceId
@@ -5939,8 +6022,7 @@ function ActivityRow({face: face, breadcrumb: breadcrumb, assignees: assignees,
5939
6022
  const settled = workflowEngine.isTerminalActivityStatus(face.status), dimmed = settledDim(settled);
5940
6023
  /* @__PURE__ */
5941
6024
  return jsxRuntime.jsxs(WorkRow, {
5942
- end:
5943
- /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
6025
+ end: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
5944
6026
  children: [
5945
6027
  /* @__PURE__ */ jsxRuntime.jsx(ActivityDateControl, {
5946
6028
  dueDates: dueDates,
@@ -5988,8 +6070,7 @@ function ActivityRow({face: face, breadcrumb: breadcrumb, assignees: assignees,
5988
6070
 
5989
6071
  function ActivitiesList({entry: entry, onOpenActivity: onOpenActivity, surface: surface}) {
5990
6072
  const activities = (entry.evaluation?.currentStage.activities ?? []).filter(t => !t.scopedOut), activityState = stateByActivity(entry.instance), fault = useInstanceFault(entry);
5991
- return activities.length === 0 ?
5992
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
6073
+ return activities.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
5993
6074
  paddingX: 1,
5994
6075
  paddingY: 3,
5995
6076
  children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
@@ -6017,8 +6098,7 @@ function ActivitiesList({entry: entry, onOpenActivity: onOpenActivity, surface:
6017
6098
 
6018
6099
  function instanceNotice(entry) {
6019
6100
  const {instance: instance, committed: committed, evaluation: evaluation} = entry, state = workflowEngine.terminalState(instance);
6020
- if (state !== "in-flight")
6021
- /* @__PURE__ */
6101
+ if (state !== "in-flight") /* @__PURE__ */
6022
6102
  return jsxRuntime.jsx(ui.Box, {
6023
6103
  paddingX: 1,
6024
6104
  paddingY: 2,
@@ -6206,7 +6286,7 @@ function UserAvatar({id: id}) {
6206
6286
  function UserAvatarGroup({ids: ids, hint: hint}) {
6207
6287
  const displays = useUserDisplays(ids);
6208
6288
  return displays.length === 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(HoverHint, {
6209
- text: displays.map(d => d.name).join(", "),
6289
+ text: disambiguatedNames(displays).join(", "),
6210
6290
  ...hint === void 0 ? {} : {
6211
6291
  description: hint
6212
6292
  },
@@ -6265,8 +6345,7 @@ function FieldPills({entry: entry, scope: scope, definition: definition, surface
6265
6345
  pill: pill,
6266
6346
  scope: scope,
6267
6347
  surface: surface
6268
- }, pill.name)), overflow > 0 ?
6269
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
6348
+ }, pill.name)), overflow > 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
6270
6349
  mode: "bleed",
6271
6350
  onClick: () => setExpanded(v => !v),
6272
6351
  padding: 2,
@@ -6391,7 +6470,7 @@ function AvatarCapAligned({children: children}) {
6391
6470
  }
6392
6471
 
6393
6472
  function AssigneesFace({assignees: assignees}) {
6394
- const vocabulary = useProjectMembers(), userIds = assignees.flatMap(a => a.type === "user" ? [ a.id ] : []), roles = assignees.flatMap(a => a.type === "role" ? [ workflowComponents.roleLabelFor(vocabulary, a.role) ] : []);
6473
+ const vocabulary = useProjectMembers(), userIds = userIdsOf(assignees), roles = assignees.flatMap(a => a.type === "role" ? [ workflowComponents.roleLabelFor(vocabulary, a.role) ] : []);
6395
6474
  /* @__PURE__ */
6396
6475
  return jsxRuntime.jsxs(jsxRuntime.Fragment, {
6397
6476
  children: [ userIds.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(AvatarCapAligned, {
@@ -6705,9 +6784,11 @@ function AssigneePill({entry: entry, pill: pill, editability: editability, surfa
6705
6784
  return jsxRuntime.jsx(PillPopover, {
6706
6785
  content: /* @__PURE__ */ jsxRuntime.jsx(SingleAssigneePicker, {
6707
6786
  current: current,
6787
+ eligibleRoles: editability.roles,
6708
6788
  onPick: picked => {
6709
6789
  setOpen(!1), pick(picked);
6710
- }
6790
+ },
6791
+ roleAliases: editability.roleAliases
6711
6792
  }),
6712
6793
  onDismiss: () => setOpen(!1),
6713
6794
  onToggle: () => setOpen(v => !v),
@@ -6721,13 +6802,15 @@ function AssigneesPill({entry: entry, pill: pill, editability: editability, surf
6721
6802
  entry: entry,
6722
6803
  editability: editability,
6723
6804
  surface: surface
6724
- }), current = pill.face.kind === "assignees" ? pill.face.assignees : [];
6805
+ }), current = pill.face.kind === "assignees" ? pill.face.assignees : [], change = next => {
6806
+ saving || save(() => set(next));
6807
+ };
6725
6808
  /* @__PURE__ */
6726
6809
  return jsxRuntime.jsx(PillPopover, {
6727
6810
  content: /* @__PURE__ */ jsxRuntime.jsx(AssigneePicker, {
6728
- onChange: next => {
6729
- saving || save(() => set(next));
6730
- },
6811
+ eligibleRoles: editability.roles,
6812
+ onChange: change,
6813
+ roleAliases: editability.roleAliases,
6731
6814
  value: current
6732
6815
  }),
6733
6816
  onDismiss: () => setOpen(!1),
@@ -7313,6 +7396,24 @@ function historyLine(h, titles) {
7313
7396
  return historyLiner[h._type](h, titles);
7314
7397
  }
7315
7398
 
7399
+ function AgoStamp({at: at, now: now}) {
7400
+ /* @__PURE__ */
7401
+ return jsxRuntime.jsx(ui.Flex, {
7402
+ align: "center",
7403
+ children: /* @__PURE__ */ jsxRuntime.jsx(HoverHint, {
7404
+ text: formatShortDateTime(at),
7405
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
7406
+ muted: !0,
7407
+ size: 1,
7408
+ style: {
7409
+ whiteSpace: "nowrap"
7410
+ },
7411
+ children: formatShortAgo(at, now)
7412
+ })
7413
+ })
7414
+ });
7415
+ }
7416
+
7316
7417
  function CodeChip({value: value}) {
7317
7418
  /* @__PURE__ */
7318
7419
  return jsxRuntime.jsx("code", {
@@ -7538,16 +7639,9 @@ function FeedStamp({at: at, now: now}) {
7538
7639
  size: 1,
7539
7640
  children: "·"
7540
7641
  }),
7541
- /* @__PURE__ */ jsxRuntime.jsx(HoverHint, {
7542
- text: formatDateTime(at),
7543
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
7544
- muted: !0,
7545
- size: 1,
7546
- style: {
7547
- whiteSpace: "nowrap"
7548
- },
7549
- children: formatShortAgo(at, now)
7550
- })
7642
+ /* @__PURE__ */ jsxRuntime.jsx(AgoStamp, {
7643
+ at: at,
7644
+ now: now
7551
7645
  }) ]
7552
7646
  });
7553
7647
  }
@@ -7656,8 +7750,7 @@ function InstanceCardMenu({entry: entry, title: title}) {
7656
7750
  return jsxRuntime.jsxs(jsxRuntime.Fragment, {
7657
7751
  children: [
7658
7752
  /* @__PURE__ */ jsxRuntime.jsx(ui.MenuButton, {
7659
- button:
7660
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
7753
+ button: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
7661
7754
  "aria-label": `More options for ${title}`,
7662
7755
  fontSize: 1,
7663
7756
  icon: EllipsisHorizontal.EllipsisHorizontalIcon,
@@ -7978,8 +8071,7 @@ function StageOverviewCard({overview: overview}) {
7978
8071
  size: 1,
7979
8072
  weight: "medium",
7980
8073
  children: overview.title
7981
- }), overview.description === void 0 ? null :
7982
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
8074
+ }), overview.description === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
7983
8075
  muted: !0,
7984
8076
  size: 1,
7985
8077
  style: {
@@ -8023,8 +8115,7 @@ function AdvanceCard({advance: advance}) {
8023
8115
  /* @__PURE__ */ jsxRuntime.jsx(InlineEmphasis, {
8024
8116
  children: advance.toTitle
8025
8117
  }), ADVANCE_TAILS[advance.kind] ]
8026
- }), advance.kind !== "conditions" ? null : advance.lines.map((line, index) =>
8027
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
8118
+ }), advance.kind !== "conditions" ? null : advance.lines.map((line, index) => /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
8028
8119
  muted: !0,
8029
8120
  size: 1,
8030
8121
  style: {
@@ -9078,8 +9169,7 @@ const VIEW_TAB_CODEC = workflowsTabCodec([ "overview", "for-me" ]), WorkflowsVie
9078
9169
  children: /* @__PURE__ */ jsxRuntime.jsx(InvalidDocNotice, {
9079
9170
  invalid: discoveryInvalid
9080
9171
  })
9081
- }) : resolved ?
9082
- /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
9172
+ }) : resolved ? /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
9083
9173
  direction: "column",
9084
9174
  height: "fill",
9085
9175
  padding: 4,
@@ -9381,7 +9471,10 @@ function resolveEntry(args) {
9381
9471
  }
9382
9472
  valid.push(name), definition && definitions.push({
9383
9473
  name: name,
9384
- fields: definition.fields
9474
+ fields: definition.fields,
9475
+ ...definition.roleAliases === void 0 ? {} : {
9476
+ roleAliases: definition.roleAliases
9477
+ }
9385
9478
  });
9386
9479
  }
9387
9480
  return {
@@ -9899,6 +9992,7 @@ function WorkflowProvider(props) {
9899
9992
  engine: engine,
9900
9993
  binding: binding,
9901
9994
  mappings: mappings,
9995
+ previewHydration: config.previewHydration,
9902
9996
  mappingIssues: issues,
9903
9997
  mappingStarts: starts,
9904
9998
  mappingFields: fields,
@@ -9906,7 +10000,7 @@ function WorkflowProvider(props) {
9906
10000
  effectHandlers: engine.effectHandlers,
9907
10001
  autoStartByType: autoStartByType,
9908
10002
  autoStartDefinitions: autoStartDefinitions
9909
- }), [ register, unregister, isDocResolved, entriesStore, actualTypes, requestInstance, releaseInstance, requestEvaluation, releaseEvaluation, seedInstance, openStartDialog, closeStartDialog, startRequest2, loading, discoveryInvalid, fireActionFor, editFieldFor, previewFieldFor, discardFieldPreviewFor, drainEffectsFor, completeEffectFor, engine, binding, mappings, issues, starts, fields, latestVersions, autoStartByType, autoStartDefinitions ]);
10003
+ }), [ register, unregister, isDocResolved, entriesStore, actualTypes, requestInstance, releaseInstance, requestEvaluation, releaseEvaluation, seedInstance, openStartDialog, closeStartDialog, startRequest2, loading, discoveryInvalid, fireActionFor, editFieldFor, previewFieldFor, discardFieldPreviewFor, drainEffectsFor, completeEffectFor, engine, binding, mappings, config.previewHydration, issues, starts, fields, latestVersions, autoStartByType, autoStartDefinitions ]);
9910
10004
  /* @__PURE__ */
9911
10005
  return jsxRuntime.jsxs(WorkflowContext.Provider, {
9912
10006
  value: value,
@@ -10008,7 +10102,7 @@ function logOnce(messages, logged) {
10008
10102
  for (const message of messages) logged.has(message) || (logged.add(message), console.warn(`[workflow-studio-plugin] ${message}`));
10009
10103
  }
10010
10104
 
10011
- function AssigneesInput({value: value, onChange: onChange}) {
10105
+ function AssigneesInput({value: value, onChange: onChange, eligibleRoles: eligibleRoles, roleAliases: roleAliases}) {
10012
10106
  const [open, setOpen] = react.useState(!1), remove = index => onChange(value.filter((_, i) => i !== index));
10013
10107
  /* @__PURE__ */
10014
10108
  return jsxRuntime.jsxs(ui.Stack, {
@@ -10042,7 +10136,9 @@ function AssigneesInput({value: value, onChange: onChange}) {
10042
10136
  wrap: "wrap",
10043
10137
  children: /* @__PURE__ */ jsxRuntime.jsx(DismissablePopover, {
10044
10138
  content: /* @__PURE__ */ jsxRuntime.jsx(AssigneePicker, {
10139
+ eligibleRoles: eligibleRoles,
10045
10140
  onChange: next => onChange([ ...next ]),
10141
+ roleAliases: roleAliases,
10046
10142
  value: value
10047
10143
  }),
10048
10144
  onDismiss: () => setOpen(!1),
@@ -10111,11 +10207,29 @@ function ChecklistInput({value: value, onChange: onChange}) {
10111
10207
  });
10112
10208
  }
10113
10209
 
10114
- function ReleasePicker({value: value, onChange: onChange}) {
10115
- const {binding: binding} = useWorkflowContext(), {data: data, loading: loading, error: error} = sanity.useActiveReleases(), releases = react.useMemo(() => data.filter(release => release.state === "active").map(release => ({
10210
+ function titleOf(release) {
10211
+ return release.metadata.title ?? release.name;
10212
+ }
10213
+
10214
+ function useReleaseTitles() {
10215
+ const {data: data} = sanity.useActiveReleases();
10216
+ return react.useMemo(() => new Map(data.map(release => [ release.name, titleOf(release) ])), [ data ]);
10217
+ }
10218
+
10219
+ function useActiveReleaseOptions() {
10220
+ const {data: data, loading: loading, error: error} = sanity.useActiveReleases(), releases = react.useMemo(() => data.filter(release => release.state === "active").map(release => ({
10116
10221
  name: release.name,
10117
- title: release.metadata.title ?? release.name
10118
- })).toSorted((a, b) => a.title.localeCompare(b.title)), [ data ]), labelOf = react.useMemo(() => {
10222
+ title: titleOf(release)
10223
+ })).toSorted((a, b) => a.title.localeCompare(b.title)), [ data ]);
10224
+ return {
10225
+ error: error,
10226
+ loading: loading,
10227
+ releases: releases
10228
+ };
10229
+ }
10230
+
10231
+ function ReleasePicker({value: value, onChange: onChange}) {
10232
+ const {binding: binding} = useWorkflowContext(), {error: error, loading: loading, releases: releases} = useActiveReleaseOptions(), labelOf = react.useMemo(() => {
10119
10233
  const m = new Map(releases.map(r => [ r.name, r.title ]));
10120
10234
  return name => m.get(name) ?? name;
10121
10235
  }, [ releases ]);
@@ -10383,8 +10497,10 @@ const docRefInput = ({entry: entry, docType: docType, releaseId: releaseId, valu
10383
10497
  onChange: onChange,
10384
10498
  value: value ?? []
10385
10499
  }),
10386
- assignees: ({value: value, onChange: onChange}) => /* @__PURE__ */ jsxRuntime.jsx(AssigneesInput, {
10500
+ assignees: ({entry: entry, roleAliases: roleAliases, value: value, onChange: onChange}) => /* @__PURE__ */ jsxRuntime.jsx(AssigneesInput, {
10501
+ eligibleRoles: entry.roles,
10387
10502
  onChange: onChange,
10503
+ roleAliases: roleAliases,
10388
10504
  value: value ?? []
10389
10505
  }),
10390
10506
  array: ({entry: entry, value: value, onChange: onChange}) => {
@@ -10426,7 +10542,7 @@ function FieldInput(props) {
10426
10542
  });
10427
10543
  }
10428
10544
 
10429
- function InitFieldRow({entry: entry, docType: docType, releaseId: releaseId, value: value, onChange: onChange}) {
10545
+ function InitFieldRow({entry: entry, docType: docType, releaseId: releaseId, roleAliases: roleAliases, value: value, onChange: onChange}) {
10430
10546
  const label = entry.title ?? entry.name;
10431
10547
  /* @__PURE__ */
10432
10548
  return jsxRuntime.jsxs(ui.Stack, {
@@ -10450,6 +10566,7 @@ function InitFieldRow({entry: entry, docType: docType, releaseId: releaseId, val
10450
10566
  entry: entry,
10451
10567
  onChange: onChange,
10452
10568
  releaseId: releaseId,
10569
+ roleAliases: roleAliases,
10453
10570
  value: value
10454
10571
  }) ]
10455
10572
  });
@@ -10499,7 +10616,7 @@ function StartFooter({canStart: canStart, starting: starting, startLabel: startL
10499
10616
  });
10500
10617
  }
10501
10618
 
10502
- function StartInputList({initFields: initFields, mapping: mapping, releaseId: releaseId, values: values, onChange: onChange}) {
10619
+ function StartInputList({initFields: initFields, mapping: mapping, releaseId: releaseId, roleAliases: roleAliases, values: values, onChange: onChange}) {
10503
10620
  return initFields.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
10504
10621
  muted: !0,
10505
10622
  size: 1,
@@ -10510,6 +10627,7 @@ function StartInputList({initFields: initFields, mapping: mapping, releaseId: re
10510
10627
  entry: entry,
10511
10628
  onChange: v => onChange(entry.name, v),
10512
10629
  releaseId: releaseId,
10630
+ roleAliases: roleAliases,
10513
10631
  value: values[entry.name] ?? null
10514
10632
  }, entry.name))
10515
10633
  });
@@ -10640,6 +10758,7 @@ function StartWorkflowForm({request: request, onClose: onClose}) {
10640
10758
  mapping: mapping,
10641
10759
  onChange: setValue,
10642
10760
  releaseId: releaseId,
10761
+ roleAliases: definition.roleAliases,
10643
10762
  values: values
10644
10763
  }),
10645
10764
  /* @__PURE__ */ jsxRuntime.jsx(StartFooter, {
@@ -10694,11 +10813,12 @@ function AutoStartInputDialog(props) {
10694
10813
  }),
10695
10814
  /* @__PURE__ */ jsxRuntime.jsx(ui.Stack, {
10696
10815
  gap: 4,
10697
- children: inputs.map(({entry: entry}) => /* @__PURE__ */ jsxRuntime.jsx(InitFieldRow, {
10816
+ children: inputs.map(({entry: entry, roleAliases: roleAliases}) => /* @__PURE__ */ jsxRuntime.jsx(InitFieldRow, {
10698
10817
  docType: docType,
10699
10818
  entry: entry,
10700
10819
  onChange: value => setValue(entry.name, value),
10701
10820
  releaseId: void 0,
10821
+ roleAliases: roleAliases,
10702
10822
  value: values[entry.name] ?? null
10703
10823
  }, entry.name))
10704
10824
  }),
@@ -10727,23 +10847,65 @@ function subjectEntry(definition) {
10727
10847
  return documentSubjectEntry(definition);
10728
10848
  }
10729
10849
 
10730
- function autoStartInputs(args) {
10850
+ function autoStartInputPlan(args) {
10731
10851
  const byName = /* @__PURE__ */ new Map;
10732
10852
  for (const name of args.workflows) {
10733
10853
  const definition = args.definitions.get(name);
10734
10854
  if (definition !== void 0) for (const entry of extraRequiredInputs(definition)) {
10735
- const existing = byName.get(entry.name);
10736
- existing === void 0 ? byName.set(entry.name, {
10855
+ const conflict = mergeAutoStartInput(byName, {
10737
10856
  entry: entry,
10738
- workflows: [ name ]
10739
- }) : existing.workflows.push(name);
10857
+ workflow: name,
10858
+ roleAliases: definition.roleAliases
10859
+ });
10860
+ if (conflict !== void 0) return {
10861
+ inputs: [],
10862
+ conflict: conflict
10863
+ };
10740
10864
  }
10741
10865
  }
10742
- return [ ...byName.values() ];
10866
+ return {
10867
+ inputs: [ ...byName.values() ]
10868
+ };
10869
+ }
10870
+
10871
+ function mergeAutoStartInput(byName, args) {
10872
+ const existing = byName.get(args.entry.name);
10873
+ if (existing === void 0) {
10874
+ byName.set(args.entry.name, {
10875
+ entry: args.entry,
10876
+ workflows: [ args.workflow ],
10877
+ ...args.roleAliases === void 0 ? {} : {
10878
+ roleAliases: args.roleAliases
10879
+ }
10880
+ });
10881
+ return;
10882
+ }
10883
+ if (!sameRoleSet(existing.entry.roles, args.entry.roles)) return `Auto-start input "${args.entry.name}" is shared by workflows "${existing.workflows.join('", "')}" and "${args.workflow}" with different role constraints`;
10884
+ existing.workflows.push(args.workflow), sameRoleAliases(existing.roleAliases, args.roleAliases) || delete existing.roleAliases;
10885
+ }
10886
+
10887
+ function sameRoleSet(left, right) {
10888
+ return roleSetKey(left) === roleSetKey(right);
10889
+ }
10890
+
10891
+ function roleSetKey(roles) {
10892
+ return roles === void 0 ? void 0 : JSON.stringify(sortedUnique(roles));
10893
+ }
10894
+
10895
+ function sameRoleAliases(left, right) {
10896
+ return roleAliasesKey(left) === roleAliasesKey(right);
10897
+ }
10898
+
10899
+ function roleAliasesKey(aliases) {
10900
+ if (aliases !== void 0) return JSON.stringify(Object.entries(aliases).map(([role, fulfillers]) => [ role, sortedUnique(fulfillers) ]).toSorted(([left], [right]) => left.localeCompare(right)));
10901
+ }
10902
+
10903
+ function sortedUnique(values) {
10904
+ return [ ...new Set(values) ].toSorted();
10743
10905
  }
10744
10906
 
10745
10907
  function autoStartAction(args) {
10746
- return args.fired ? args.settled ? "reveal" : "starting" : args.pendingCount === 0 ? "reveal" : args.resolved ? args.needsInput ? "collect" : "silent-start" : "wait";
10908
+ return args.fired ? args.settled ? "reveal" : "starting" : args.blocked || args.pendingCount === 0 ? "reveal" : args.resolved ? args.needsInput ? "collect" : "silent-start" : "wait";
10747
10909
  }
10748
10910
 
10749
10911
  function pendingWorkflows(workflows, live) {
@@ -10800,10 +10962,14 @@ function AutoStartDriver(props) {
10800
10962
  engine: engine
10801
10963
  }), {selectedReleaseId: selectedReleaseId} = sanity.usePerspective(), {entries: entries} = useWorkflowsForDocument(rawDocId), docId = csm.getPublishedId(rawDocId), valueRef = react.useRef(value);
10802
10964
  valueRef.current = value;
10803
- const pending = react.useMemo(() => pendingWorkflows(workflows, new Set(entries.map(entry => entry.instance.definition))), [ workflows, entries ]), inputs = react.useMemo(() => autoStartInputs({
10965
+ const pending = react.useMemo(() => pendingWorkflows(workflows, new Set(entries.map(entry => entry.instance.definition))), [ workflows, entries ]), inputPlan = react.useMemo(() => autoStartInputPlan({
10804
10966
  workflows: pending,
10805
10967
  definitions: autoStartDefinitions
10806
- }), [ pending, autoStartDefinitions ]), definitionsResolved = workflows.every(name => autoStartDefinitions.has(name)), pendingRef = react.useRef(pending);
10968
+ }), [ pending, autoStartDefinitions ]), inputs = inputPlan.inputs;
10969
+ react.useEffect(() => {
10970
+ inputPlan.conflict !== void 0 && console.warn(`[Workflows] Auto-start skipped. ${inputPlan.conflict}`);
10971
+ }, [ inputPlan.conflict ]);
10972
+ const definitionsResolved = workflows.every(name => autoStartDefinitions.has(name)), pendingRef = react.useRef(pending);
10807
10973
  pendingRef.current = pending;
10808
10974
  const instanceIds = react.useRef(/* @__PURE__ */ new Map), instanceIdFor = react.useCallback(workflow => {
10809
10975
  const held = instanceIds.current.get(workflow);
@@ -10855,6 +11021,7 @@ function AutoStartDriver(props) {
10855
11021
  resolved: definitionsResolved && isDocResolved(docId),
10856
11022
  pendingCount: pending.length,
10857
11023
  needsInput: inputs.length > 0,
11024
+ blocked: inputPlan.conflict !== void 0,
10858
11025
  fired: fired,
10859
11026
  settled: settled
10860
11027
  });
@@ -11300,19 +11467,13 @@ function StartWorkflowDialogHost() {
11300
11467
  }
11301
11468
 
11302
11469
  const TOOL_TAB_LABELS = {
11303
- overview: "Workflows",
11304
- "all-documents": "All documents",
11305
- "for-me": "For me"
11470
+ overview: "Overview",
11471
+ "for-me": "For me",
11472
+ definitions: "Definitions"
11306
11473
  }, TOOL_TAB_VALUES = Object.keys(TOOL_TAB_LABELS), TOOL_TABS = TOOL_TAB_VALUES.map(value => ({
11307
11474
  value: value,
11308
11475
  label: TOOL_TAB_LABELS[value]
11309
- })), LANDING_TAB = "overview", TASKS_TAB = "all-documents", WORKFLOW_PAGE_LABELS = {
11310
- workflow: "Documents",
11311
- definition: "Definition"
11312
- }, WORKFLOW_PAGE_VALUES = Object.keys(WORKFLOW_PAGE_LABELS), DEFAULT_WORKFLOW_PAGE = "workflow", WORKFLOW_PAGES = WORKFLOW_PAGE_VALUES.filter(page => page !== DEFAULT_WORKFLOW_PAGE), WORKFLOW_PAGE_TABS = WORKFLOW_PAGE_VALUES.map(value => ({
11313
- value: value,
11314
- label: WORKFLOW_PAGE_LABELS[value]
11315
- })), toolRouter = router.route.create("/", [ router.route.create("/instance/:instanceId"), router.route.create(`/${LANDING_TAB}/:workflowName`, [ router.route.create("/:workflowPage") ]), router.route.create("/:workflowsTab") ]);
11476
+ })), LANDING_TAB = "overview", DEFINITIONS_TAB = "definitions", toolRouter = router.route.create("/", [ router.route.create(`/${DEFINITIONS_TAB}/:workflowName`), router.route.create("/:workflowsTab") ]);
11316
11477
 
11317
11478
  function toolTabState(tab) {
11318
11479
  return {
@@ -11330,39 +11491,17 @@ function workflowState(workflowName) {
11330
11491
  };
11331
11492
  }
11332
11493
 
11333
- function instanceState(instanceId) {
11334
- return {
11335
- instanceId: instanceId
11336
- };
11337
- }
11338
-
11339
11494
  function tabSelectionNavigates(current, tab) {
11340
11495
  return !(current.kind === "home" && tab === current.tab);
11341
11496
  }
11342
11497
 
11343
- function toolTabLabel(tab) {
11344
- return TOOL_TAB_LABELS[tab];
11345
- }
11346
-
11347
- function backToTabLabel(tab) {
11348
- return `Back to ${toolTabLabel(tab)}`;
11349
- }
11350
-
11351
- function workflowPageState(page, workflowName) {
11352
- return page === DEFAULT_WORKFLOW_PAGE ? workflowState(workflowName) : {
11353
- ...workflowState(workflowName),
11354
- workflowPage: page
11355
- };
11356
- }
11357
-
11358
11498
  function toolRoute(state) {
11359
- const {instanceId: instanceId, workflowName: workflowName} = state;
11360
- if (typeof instanceId == "string") return {
11361
- kind: "instance",
11362
- instanceId: instanceId,
11363
- tab: TASKS_TAB
11499
+ const {workflowName: workflowName} = state;
11500
+ if (typeof workflowName == "string") return {
11501
+ kind: "definition",
11502
+ workflowName: workflowName,
11503
+ tab: DEFINITIONS_TAB
11364
11504
  };
11365
- if (typeof workflowName == "string") return workflowRoute(workflowName, state.workflowPage);
11366
11505
  const tab = pathSegmentName({
11367
11506
  segment: state.workflowsTab,
11368
11507
  names: TOOL_TAB_VALUES
@@ -11376,24 +11515,11 @@ function toolRoute(state) {
11376
11515
  };
11377
11516
  }
11378
11517
 
11379
- function workflowRoute(workflowName, pageSegment) {
11380
- if (pageSegment === void 0) return {
11381
- kind: "workflow",
11382
- workflowName: workflowName,
11383
- tab: LANDING_TAB
11384
- };
11385
- const page = pathSegmentName({
11386
- segment: pageSegment,
11387
- names: WORKFLOW_PAGES
11388
- });
11389
- return page === void 0 ? {
11390
- kind: "unnamed",
11391
- tab: LANDING_TAB
11392
- } : {
11393
- kind: page,
11394
- workflowName: workflowName,
11395
- tab: LANDING_TAB
11518
+ function definitionsRouteOf(route2) {
11519
+ if (route2.kind === "definition") return {
11520
+ workflowName: route2.workflowName
11396
11521
  };
11522
+ if (route2.kind === "home" && route2.tab === "definitions") return {};
11397
11523
  }
11398
11524
 
11399
11525
  const WorkflowsToolRoot = react.lazy(() => Promise.resolve().then(function() {
@@ -11513,11 +11639,11 @@ exports.ActivityDetailDialog = ActivityDetailDialog;
11513
11639
 
11514
11640
  exports.ActivityLog = ActivityLog;
11515
11641
 
11516
- exports.ActivityRow = ActivityRow;
11642
+ exports.AgoStamp = AgoStamp;
11517
11643
 
11518
- exports.AlertGlyph = AlertGlyph;
11644
+ exports.AlertChip = AlertChip;
11519
11645
 
11520
- exports.BreadcrumbTail = BreadcrumbTail;
11646
+ exports.AlertGlyph = AlertGlyph;
11521
11647
 
11522
11648
  exports.CodeChip = CodeChip;
11523
11649
 
@@ -11531,42 +11657,32 @@ exports.DocRefFace = DocRefFace;
11531
11657
 
11532
11658
  exports.EmptyState = EmptyState;
11533
11659
 
11534
- exports.ForMeEmptyState = ForMeEmptyState;
11535
-
11536
- exports.Hairline = Hairline;
11537
-
11538
11660
  exports.HoverHint = HoverHint;
11539
11661
 
11540
- exports.InlineEmphasis = InlineEmphasis;
11541
-
11542
11662
  exports.InstanceFaultNote = InstanceFaultNote;
11543
11663
 
11544
11664
  exports.InstanceSnapshotBody = InstanceSnapshotBody;
11545
11665
 
11546
11666
  exports.InvalidDocNotice = InvalidDocNotice;
11547
11667
 
11548
- exports.LinkChip = LinkChip;
11549
-
11550
11668
  exports.LoadingRow = LoadingRow;
11551
11669
 
11552
11670
  exports.LogEventOnMount = LogEventOnMount;
11553
11671
 
11554
11672
  exports.MetaRow = MetaRow;
11555
11673
 
11674
+ exports.MetricLockup = MetricLockup;
11675
+
11556
11676
  exports.MetricPair = MetricPair;
11557
11677
 
11558
11678
  exports.NoteBanner = NoteBanner;
11559
11679
 
11680
+ exports.RUN_SEARCH_PARAM = RUN_SEARCH_PARAM;
11681
+
11560
11682
  exports.RoleAssignedNotice = RoleAssignedNotice;
11561
11683
 
11562
11684
  exports.SpinnerSlot = SpinnerSlot;
11563
11685
 
11564
- exports.StageFace = StageFace;
11565
-
11566
- exports.StaleLock = StaleLock;
11567
-
11568
- exports.TOAST_ID = TOAST_ID;
11569
-
11570
11686
  exports.TOOL_TABS = TOOL_TABS;
11571
11687
 
11572
11688
  exports.TabSwitch = TabSwitch;
@@ -11575,46 +11691,34 @@ exports.UnreadableDocsNote = UnreadableDocsNote;
11575
11691
 
11576
11692
  exports.WORKFLOW_API_VERSION = WORKFLOW_API_VERSION;
11577
11693
 
11578
- exports.WORKFLOW_PAGE_TABS = WORKFLOW_PAGE_TABS;
11579
-
11580
11694
  exports.WorkflowBoardWorkflowSelected = WorkflowBoardWorkflowSelected;
11581
11695
 
11582
11696
  exports.WorkflowDefinitionDetailViewed = WorkflowDefinitionDetailViewed;
11583
11697
 
11584
11698
  exports.WorkflowInstanceDetailViewed = WorkflowInstanceDetailViewed;
11585
11699
 
11586
- exports.WorkflowTaskFiltersApplied = WorkflowTaskFiltersApplied;
11587
-
11588
11700
  exports.WorkflowTitleSeedDrifted = WorkflowTitleSeedDrifted;
11589
11701
 
11590
11702
  exports.WorkflowToolOpened = WorkflowToolOpened;
11591
11703
 
11592
- exports.activityRowProps = activityRowProps;
11704
+ exports.activityLabel = activityLabel;
11593
11705
 
11594
11706
  exports.assigneesOf = assigneesOf;
11595
11707
 
11596
- exports.backToTabLabel = backToTabLabel;
11597
-
11598
- exports.committedRowFace = committedRowFace;
11599
-
11600
- exports.createSubscribers = createSubscribers;
11601
-
11602
- exports.datesOf = datesOf;
11708
+ exports.countBy = countBy;
11603
11709
 
11604
11710
  exports.definitionFingerprint = definitionFingerprint;
11605
11711
 
11606
- exports.definitionSnapshotOf = definitionSnapshotOf;
11712
+ exports.definitionsRouteOf = definitionsRouteOf;
11607
11713
 
11608
11714
  exports.describeError = describeError;
11609
11715
 
11716
+ exports.disambiguatedNames = disambiguatedNames;
11717
+
11610
11718
  exports.dueDatesOf = dueDatesOf;
11611
11719
 
11612
11720
  exports.findActivity = findActivity;
11613
11721
 
11614
- exports.formatDate = formatDate;
11615
-
11616
- exports.formatShortAgo = formatShortAgo;
11617
-
11618
11722
  exports.formatShortDateTime = formatShortDateTime;
11619
11723
 
11620
11724
  exports.formatTimeAgo = formatTimeAgo;
@@ -11625,22 +11729,18 @@ exports.identityOf = identityOf;
11625
11729
 
11626
11730
  exports.instanceBreadcrumb = instanceBreadcrumb;
11627
11731
 
11628
- exports.instanceState = instanceState;
11629
-
11630
11732
  exports.instanceTitle = instanceTitle;
11631
11733
 
11632
- exports.isActivityAssignedTo = isActivityAssignedTo;
11633
-
11634
11734
  exports.isDueDatePast = isDueDatePast;
11635
11735
 
11636
11736
  exports.isEvaluationStale = isEvaluationStale;
11637
11737
 
11738
+ exports.isHandsOff = isHandsOff;
11739
+
11638
11740
  exports.isLiveEntry = isLiveEntry;
11639
11741
 
11640
11742
  exports.isOpenActivityStatus = isOpenActivityStatus;
11641
11743
 
11642
- exports.isRoleAssignedTo = isRoleAssignedTo;
11643
-
11644
11744
  exports.landingState = landingState;
11645
11745
 
11646
11746
  exports.mappingIssueDetail = mappingIssueDetail;
@@ -11655,24 +11755,28 @@ exports.parseStoredDateValue = parseStoredDateValue;
11655
11755
 
11656
11756
  exports.readDeployedDefinitions = readDeployedDefinitions;
11657
11757
 
11658
- exports.rowAssignControlState = rowAssignControlState;
11659
-
11660
- exports.rowDateControlState = rowDateControlState;
11758
+ exports.shortSpanOf = shortSpanOf;
11661
11759
 
11662
11760
  exports.stageTitle = stageTitle;
11663
11761
 
11664
- exports.stateByActivity = stateByActivity;
11665
-
11666
11762
  exports.tabSelectionNavigates = tabSelectionNavigates;
11667
11763
 
11668
11764
  exports.toolRoute = toolRoute;
11669
11765
 
11670
11766
  exports.toolTabState = toolTabState;
11671
11767
 
11768
+ exports.uniqueIds = uniqueIds;
11769
+
11672
11770
  exports.useAssignmentIdentity = useAssignmentIdentity;
11673
11771
 
11772
+ exports.useAvatarSize = useAvatarSize;
11773
+
11774
+ exports.useCapTrimFor = useCapTrimFor;
11775
+
11674
11776
  exports.useContainerToken = useContainerToken;
11675
11777
 
11778
+ exports.useCurrentUserId = useCurrentUserId;
11779
+
11676
11780
  exports.useDefinition = useDefinition;
11677
11781
 
11678
11782
  exports.useLogEventOnMount = useLogEventOnMount;
@@ -11681,20 +11785,24 @@ exports.useMinuteClock = useMinuteClock;
11681
11785
 
11682
11786
  exports.useProjectMembers = useProjectMembers;
11683
11787
 
11788
+ exports.useRadiusToken = useRadiusToken;
11789
+
11790
+ exports.useReleaseTitles = useReleaseTitles;
11791
+
11684
11792
  exports.useSpaceToken = useSpaceToken;
11685
11793
 
11794
+ exports.useTextIconSize = useTextIconSize;
11795
+
11686
11796
  exports.useUserDisplays = useUserDisplays;
11687
11797
 
11688
11798
  exports.useWorkflowContext = useWorkflowContext;
11689
11799
 
11690
11800
  exports.useWorkflowInstanceEntry = useWorkflowInstanceEntry;
11691
11801
 
11692
- exports.useWorkflowToast = useWorkflowToast;
11802
+ exports.userIdsOf = userIdsOf;
11693
11803
 
11694
11804
  exports.workflowDefaultDocumentNode = workflowDefaultDocumentNode;
11695
11805
 
11696
- exports.workflowPageState = workflowPageState;
11697
-
11698
11806
  exports.workflowState = workflowState;
11699
11807
 
11700
11808
  exports.workflowStudioPlugin = workflowStudioPlugin;