@sanity/workflow-studio-plugin 0.30.0 → 0.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
 
3
- var jsxRuntime = require("react/jsx-runtime"), Timeline = require("@sanity/icons/Timeline"), ui = require("@sanity/ui"), workflowReact = require("@sanity/workflow-react"), react = require("react"), structure = require("sanity/structure"), workflowEngine = require("@sanity/workflow-engine"), Checkmark = require("@sanity/icons/Checkmark"), Close = require("@sanity/icons/Close"), formatDistanceToNow = require("date-fns/formatDistanceToNow"), workflowComponents = require("@sanity/workflow-components"), csm = require("@sanity/client/csm"), telemetry = require("@sanity/telemetry"), workflowStudio = require("@sanity/workflow-studio"), sanity = require("sanity"), Calendar = require("@sanity/icons/Calendar"), User = require("@sanity/icons/User"), Search = require("@sanity/icons/Search"), ChevronRight = require("@sanity/icons/ChevronRight"), Edit = require("@sanity/icons/Edit"), content = require("@sanity/util/content"), InfoOutline = require("@sanity/icons/InfoOutline"), Document = require("@sanity/icons/Document"), WarningOutline = require("@sanity/icons/WarningOutline"), router = require("sanity/router"), types = require("@sanity/types"), Launch = require("@sanity/icons/Launch"), ErrorOutline = require("@sanity/icons/ErrorOutline"), Empty$1 = require("@sanity/icons/Empty"), ErrorFilled = require("@sanity/icons/ErrorFilled"), RemoveCircle = require("@sanity/icons/RemoveCircle"), Add = require("@sanity/icons/Add"), Ulist = require("@sanity/icons/Ulist"), CheckmarkCircle = require("@sanity/icons/CheckmarkCircle"), Bolt = require("@sanity/icons/Bolt"), ChevronDown = require("@sanity/icons/ChevronDown"), pluralize = require("pluralize-esm"), EllipsisHorizontal = require("@sanity/icons/EllipsisHorizontal"), Clock = require("@sanity/icons/Clock"), Cog = require("@sanity/icons/Cog"), ArrowUp = require("@sanity/icons/ArrowUp"), rxjs = require("rxjs"), operators = require("rxjs/operators"), Transfer = require("@sanity/icons/Transfer");
3
+ var jsxRuntime = require("react/jsx-runtime"), Timeline = require("@sanity/icons/Timeline"), ui = require("@sanity/ui"), workflowReact = require("@sanity/workflow-react"), react = require("react"), structure = require("sanity/structure"), workflowEngine = require("@sanity/workflow-engine"), Checkmark = require("@sanity/icons/Checkmark"), Close = require("@sanity/icons/Close"), formatDistanceToNow = require("date-fns/formatDistanceToNow"), workflowComponents = require("@sanity/workflow-components"), csm = require("@sanity/client/csm"), telemetry = require("@sanity/telemetry"), workflowStudio = require("@sanity/workflow-studio"), sanity = require("sanity"), Calendar = require("@sanity/icons/Calendar"), User = require("@sanity/icons/User"), Search = require("@sanity/icons/Search"), Edit = require("@sanity/icons/Edit"), content = require("@sanity/util/content"), InfoOutline = require("@sanity/icons/InfoOutline"), Document = require("@sanity/icons/Document"), WarningOutline = require("@sanity/icons/WarningOutline"), router = require("sanity/router"), types = require("@sanity/types"), Launch = require("@sanity/icons/Launch"), ErrorOutline = require("@sanity/icons/ErrorOutline"), Empty$1 = require("@sanity/icons/Empty"), ErrorFilled = require("@sanity/icons/ErrorFilled"), RemoveCircle = require("@sanity/icons/RemoveCircle"), AddUser = require("@sanity/icons/AddUser"), Add = require("@sanity/icons/Add"), Ulist = require("@sanity/icons/Ulist"), CheckmarkCircle = require("@sanity/icons/CheckmarkCircle"), Bolt = require("@sanity/icons/Bolt"), ChevronDown = require("@sanity/icons/ChevronDown"), pluralize = require("pluralize-esm"), ChevronRight = require("@sanity/icons/ChevronRight"), styledComponents = require("styled-components"), EllipsisHorizontal = require("@sanity/icons/EllipsisHorizontal"), Clock = require("@sanity/icons/Clock"), Cog = require("@sanity/icons/Cog"), ArrowUp = require("@sanity/icons/ArrowUp"), rxjs = require("rxjs"), operators = require("rxjs/operators"), Transfer = require("@sanity/icons/Transfer");
4
4
 
5
5
  function _interopDefaultCompat(e) {
6
6
  return e && typeof e == "object" && "default" in e ? e : {
@@ -408,9 +408,12 @@ function formatShortAgo(value, now) {
408
408
  }
409
409
 
410
410
  function formatShortSpan(value, now) {
411
- const d = new Date(value);
412
- if (Number.isNaN(d.getTime())) return "—";
413
- const seconds = Math.floor((now.getTime() - d.getTime()) / 1e3);
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);
414
417
  if (seconds < 60) return "now";
415
418
  const minutes = Math.floor(seconds / 60);
416
419
  if (minutes < 60) return `${minutes}m`;
@@ -438,6 +441,14 @@ function formatDate(value) {
438
441
  });
439
442
  }
440
443
 
444
+ function formatDueMoment(value) {
445
+ return storedDateKind(value) === "date" ? formatDate(value) : formatShortDateTime(value);
446
+ }
447
+
448
+ function dueMomentSentence(value, now) {
449
+ return `${isDueDatePast(value, now) ? "Was due" : "Due"} ${formatDueMoment(value)}`;
450
+ }
451
+
441
452
  function formatBoolean(value) {
442
453
  return value ? "True" : "False";
443
454
  }
@@ -696,19 +707,10 @@ function isOpenActivityStatus(status) {
696
707
  return !workflowEngine.isTerminalActivityStatus(status);
697
708
  }
698
709
 
699
- function assigneeMatches(member, who) {
700
- return member.type === "user" ? member.id === who.userId : who.roles.includes(member.role);
701
- }
702
-
703
710
  function changedAssignee(current, next) {
704
711
  return next.find(item => !current.some(existing => workflowComponents.sameAssignee(item, existing))) ?? current.find(item => !next.some(existing => workflowComponents.sameAssignee(item, existing)));
705
712
  }
706
713
 
707
- function singleAssigneePick(current, next) {
708
- const changed = changedAssignee(current ? [ current ] : [], next);
709
- if (changed !== void 0) return current && workflowComponents.sameAssignee(changed, current) ? null : changed;
710
- }
711
-
712
714
  function isAssigneeShape(value) {
713
715
  if (typeof value != "object" || value === null) return !1;
714
716
  const {type: type, id: id, role: role} = value;
@@ -722,7 +724,11 @@ function isActorShape(value) {
722
724
  }
723
725
 
724
726
  function assigneesOf(entries) {
725
- return entries.flatMap(entry => entry._type === "assignees" ? entry.value : []);
727
+ return [ ...workflowEngine.assignmentMembers(entries) ];
728
+ }
729
+
730
+ function userIdsOf(assignees) {
731
+ return assignees.flatMap(assignee => assignee.type === "user" ? [ assignee.id ] : []);
726
732
  }
727
733
 
728
734
  function assigneeEdit(current, next) {
@@ -736,43 +742,36 @@ function assigneeEdit(current, next) {
736
742
  };
737
743
  }
738
744
 
739
- function isItemAssignedTo(item, who) {
740
- return item.assignee != null && assigneeMatches(item.assignee, who);
741
- }
742
-
743
- function matchingAssignees(state, who) {
744
- return state.flatMap(entry => entry._type === "assignees" ? entry.value.filter(a => assigneeMatches(a, who)) : entry._type === "assignee" && entry.value !== null && assigneeMatches(entry.value, who) ? [ entry.value ] : []);
745
+ function assignmentHolding(assignees, who) {
746
+ const match = workflowComponents.assignmentMatch(assignees, who);
747
+ return match === void 0 ? "other" : match === "user" ? "you" : "role";
745
748
  }
746
749
 
747
- function isActivityAssignedTo(args) {
748
- return matchingAssignees(args.state, args.who).length > 0;
750
+ function holdingMatchesAssignment(holding, assignment) {
751
+ return assignment === void 0 ? holding !== "other" : holding === assignment;
749
752
  }
750
753
 
751
- function isRoleAssignedTo(args) {
752
- return matchingAssignees(args.state, args.who).some(member => member.type === "role");
754
+ function activityHolding(args) {
755
+ return assignmentHolding(assigneesOf(args.state), args.who);
753
756
  }
754
757
 
755
- function isItemRoleAssignedTo(item, who) {
756
- return isItemAssignedTo(item, who) && item.assignee?.type === "role";
758
+ function itemHolding(item, who) {
759
+ return assignmentHolding(item.assignee ?? [], who);
757
760
  }
758
761
 
759
762
  function assignedWork(args) {
760
- const {instance: instance, committed: committed, who: who} = args, evaluation = args.staleEvaluation === "keep" || isEvaluationCurrent(args) ? args.evaluation : void 0, byActivity = stateByActivity(instance), stateOf = t => byActivity.get(t.activity.name) ?? [], activities = (evaluation?.currentStage.activities ?? []).filter(t => isActivityAssignedTo({
763
+ const {instance: instance, committed: committed, who: who} = args, evaluation = args.staleEvaluation === "keep" || isEvaluationCurrent(args) ? args.evaluation : void 0, byActivity = stateByActivity(instance), stateOf = t => byActivity.get(t.activity.name) ?? [], activities = (evaluation?.currentStage.activities ?? []).filter(t => holdingMatchesAssignment(activityHolding({
761
764
  state: stateOf(t),
762
765
  who: who
763
- })), items = deriveTodoItems({
766
+ }), args.assignment)), items = deriveTodoItems({
764
767
  instance: instance,
765
768
  committed: committed,
766
769
  evaluation: evaluation
767
- }).rows.filter(row => isItemAssignedTo(row.item, who));
770
+ }).rows.filter(row => holdingMatchesAssignment(itemHolding(row.item, who), args.assignment));
768
771
  return {
769
772
  activities: activities,
770
773
  openItems: items.filter(row => !isTodoDone(row.item)),
771
- doneItems: items.filter(row => isTodoDone(row.item)),
772
- roleMatched: activities.some(t => isRoleAssignedTo({
773
- state: stateOf(t),
774
- who: who
775
- })) || items.some(row => isItemRoleAssignedTo(row.item, who))
774
+ doneItems: items.filter(row => isTodoDone(row.item))
776
775
  };
777
776
  }
778
777
 
@@ -797,11 +796,18 @@ function hasOpenAssignedWork(work) {
797
796
  }
798
797
 
799
798
  function assignedTaskCount(args) {
800
- return openAssignedCount(assignedWork(args));
799
+ return openAssignedCount(assignedWork({
800
+ ...args,
801
+ assignment: "you"
802
+ }));
803
+ }
804
+
805
+ function hasForMeRows(work) {
806
+ return work.some(({shown: shown}) => hasAssignedRows(shown));
801
807
  }
802
808
 
803
809
  function forMeWorkOf(entries, identity) {
804
- const work = identity ? entries.map(entry => {
810
+ const section = assignment => identity === void 0 ? [] : entries.map(entry => {
805
811
  const base = {
806
812
  instance: entry.instance,
807
813
  committed: entry.committed,
@@ -811,18 +817,22 @@ function forMeWorkOf(entries, identity) {
811
817
  return {
812
818
  entry: entry,
813
819
  who: identity,
814
- count: assignedTaskCount(base),
820
+ count: openAssignedCount(assignedWork({
821
+ ...base,
822
+ assignment: assignment
823
+ })),
815
824
  shown: assignedWork({
816
825
  ...base,
826
+ assignment: assignment,
817
827
  staleEvaluation: "keep"
818
828
  })
819
829
  };
820
- }) : [];
830
+ }), assignedToUser = section("you"), assignedToRoles = section("role");
821
831
  return {
822
- work: work,
823
- count: work.reduce((n, {count: count}) => n + count, 0),
824
- hasRows: work.some(({shown: shown}) => hasAssignedRows(shown)),
825
- hasRoleMatched: work.some(({shown: shown}) => shown.roleMatched)
832
+ assignedToUser: assignedToUser,
833
+ assignedToRoles: assignedToRoles,
834
+ count: assignedToUser.reduce((n, {count: count}) => n + count, 0),
835
+ hasRows: hasForMeRows([ ...assignedToUser, ...assignedToRoles ])
826
836
  };
827
837
  }
828
838
 
@@ -902,10 +912,29 @@ const ACTIVITY_STATUS_LABEL = {
902
912
  done: "Done",
903
913
  failed: "Failed",
904
914
  skipped: "Skipped"
915
+ }, TASK_STATUS_LABEL = {
916
+ ...ACTIVITY_STATUS_LABEL,
917
+ active: "In progress"
918
+ }, HOLDING_SUFFIX = {
919
+ you: "with you",
920
+ role: "with your role",
921
+ other: void 0
905
922
  };
906
923
 
924
+ function taskStatusLine(args) {
925
+ const label = TASK_STATUS_LABEL[args.status], suffix = workflowEngine.isTerminalActivityStatus(args.status) ? void 0 : HOLDING_SUFFIX[args.holding];
926
+ return suffix === void 0 ? label : `${label} · ${suffix}`;
927
+ }
928
+
929
+ function isHandsOff(args) {
930
+ return args.classification === "autonomous" && args.completesWithoutCaller === "yes";
931
+ }
932
+
907
933
  function showsAutomatedPill(activityEval) {
908
- return !workflowEngine.isTerminalActivityStatus(activityEval.status) && activityEval.classification === "autonomous" && activityEval.autonomy.completesWithoutCaller === "yes";
934
+ return !workflowEngine.isTerminalActivityStatus(activityEval.status) && isHandsOff({
935
+ classification: activityEval.classification,
936
+ completesWithoutCaller: activityEval.autonomy.completesWithoutCaller
937
+ });
909
938
  }
910
939
 
911
940
  function showsBlockedTag(activityEval) {
@@ -983,9 +1012,10 @@ function deriveActivityPresentation(args) {
983
1012
  }), blockedReason = status === "active" && actions.length > 0 && actions.every(a => !a.allowed) ? actions.find(a => a.disabledReason)?.disabledReason : void 0, ticks = tickActionNames({
984
1013
  actions: actions,
985
1014
  state: args.state
986
- }), buttonActions = visibleActions.filter(a => !ticks.has(a.action.name)), settled = workflowEngine.isTerminalActivityStatus(status);
1015
+ }), buttonActions = visibleActions.filter(a => !ticks.has(a.action.name)), settled = workflowEngine.isTerminalActivityStatus(status), holderGate = settled ? void 0 : args.activityEval.actions.find(action => action.holderGate !== void 0)?.holderGate;
987
1016
  return {
988
1017
  blockedReason: blockedReason,
1018
+ holderGate: holderGate?.holders,
989
1019
  settled: settled,
990
1020
  triggeredActions: settled ? [] : args.activityEval.actions.filter(a => a.triggered === !0),
991
1021
  manualTarget: kind === "manual" ? manualLink(activity) : void 0,
@@ -1113,7 +1143,7 @@ function deriveActivityDetail(args) {
1113
1143
  title: activityLabel(activityEval.activity),
1114
1144
  state: state,
1115
1145
  editableByName: new Map(activityEditables.map(f => [ f.name, f ])),
1116
- assignFields: new Map(activityEditables.filter(f => f.type === "assignees" && f.editable).map(f => [ f.name, f ]))
1146
+ assignFields: new Map(activityEditables.filter(f => (f.type === "assignee" || f.type === "assignees") && f.editable).map(f => [ f.name, f ]))
1117
1147
  };
1118
1148
  }
1119
1149
 
@@ -1157,6 +1187,35 @@ function useWorkflowInstanceEntry(instanceId, options = {}) {
1157
1187
  }, [ instanceId, evaluate, requestEvaluation, releaseEvaluation ]), useHeldWorkflowEntry(instanceId);
1158
1188
  }
1159
1189
 
1190
+ const DIM = {
1191
+ opacity: .6
1192
+ };
1193
+
1194
+ function Breadcrumb({segments: segments, emphasizeCurrent: emphasizeCurrent = !1}) {
1195
+ /* @__PURE__ */
1196
+ return jsxRuntime.jsx(jsxRuntime.Fragment, {
1197
+ children: segments.map((segment, i) => /* @__PURE__ */ jsxRuntime.jsxs(react.Fragment, {
1198
+ children: [ i > 0 ? /* @__PURE__ */ jsxRuntime.jsx(Separator, {}) : null,
1199
+ /* @__PURE__ */ jsxRuntime.jsx("span", {
1200
+ style: emphasizeCurrent && i < segments.length - 1 ? DIM : void 0,
1201
+ children: segment
1202
+ }) ]
1203
+ }, `${i}-${segment}`))
1204
+ });
1205
+ }
1206
+
1207
+ function Separator() {
1208
+ /* @__PURE__ */
1209
+ return jsxRuntime.jsx("span", {
1210
+ "aria-hidden": !0,
1211
+ style: {
1212
+ ...DIM,
1213
+ margin: "0 0.35em"
1214
+ },
1215
+ children: "/"
1216
+ });
1217
+ }
1218
+
1160
1219
  const WorkflowToolOpened = telemetry.defineEvent({
1161
1220
  name: "Workflows Studio Plugin Tool Opened",
1162
1221
  version: 3,
@@ -1188,7 +1247,7 @@ const WorkflowDefinitionDetailViewed = telemetry.defineEvent({
1188
1247
  description: "The form strip's instance line was clicked, opening the document view"
1189
1248
  }), WorkflowDocumentLinkClicked = telemetry.defineEvent({
1190
1249
  name: "Workflows Studio Plugin Document Link Clicked",
1191
- version: 3,
1250
+ version: 4,
1192
1251
  description: "A document link was clicked, opening the referenced document's editor"
1193
1252
  }), WorkflowStartDialogOpened = telemetry.defineEvent({
1194
1253
  name: "Workflows Studio Plugin Start Dialog Opened",
@@ -1204,15 +1263,15 @@ const WorkflowDefinitionDetailViewed = telemetry.defineEvent({
1204
1263
  description: "A fresh document's auto-start ran — one start request per configured workflow"
1205
1264
  }), WorkflowActionControlUsed = telemetry.defineEvent({
1206
1265
  name: "Workflows Studio Plugin Action Control Used",
1207
- version: 3,
1266
+ version: 4,
1208
1267
  description: "An action-firing control was used, attributed to its UI surface"
1209
1268
  }), WorkflowFieldControlUsed = telemetry.defineEvent({
1210
1269
  name: "Workflows Studio Plugin Field Control Used",
1211
- version: 2,
1270
+ version: 3,
1212
1271
  description: "A field-editing control committed an edit, attributed to its UI surface"
1213
1272
  }), WorkflowActivityDialogOpened = telemetry.defineEvent({
1214
1273
  name: "Workflows Studio Plugin Activity Dialog Opened",
1215
- version: 2,
1274
+ version: 3,
1216
1275
  description: "The activity detail dialog was opened"
1217
1276
  }), WorkflowBoardWorkflowSelected = telemetry.defineEvent({
1218
1277
  name: "Workflows Studio Plugin Board Workflow Selected",
@@ -1224,11 +1283,11 @@ const WorkflowDefinitionDetailViewed = telemetry.defineEvent({
1224
1283
  description: "A cold-start seeded preview title diverged from the live preview pipeline"
1225
1284
  }), WorkflowTodoToggled = telemetry.defineEvent({
1226
1285
  name: "Workflows Studio Plugin Todo Toggled",
1227
- version: 1,
1286
+ version: 2,
1228
1287
  description: "A todo checkbox was toggled, attributed to its UI surface and write seam"
1229
1288
  }), WorkflowTodoEdited = telemetry.defineEvent({
1230
1289
  name: "Workflows Studio Plugin Todo Edited",
1231
- version: 1,
1290
+ version: 2,
1232
1291
  description: "A non-toggle todo-list write, attributed to its UI surface and gesture"
1233
1292
  }), WorkflowAbortDialogOpened = telemetry.defineEvent({
1234
1293
  name: "Workflows Studio Plugin Abort Dialog Opened",
@@ -1251,26 +1310,6 @@ function LogEventOnMount(props) {
1251
1310
  return useLogEventOnMount(props.event, props.data), null;
1252
1311
  }
1253
1312
 
1254
- function isEmptyValue(value) {
1255
- return value == null || value === "" || Array.isArray(value) && value.length === 0;
1256
- }
1257
-
1258
- function effectiveValidation(kind, validation) {
1259
- return kind !== "progress" ? validation : {
1260
- min: validation?.min ?? 0,
1261
- max: validation?.max ?? 100
1262
- };
1263
- }
1264
-
1265
- function scalarValidationIssue(args) {
1266
- const issues = workflowEngine.scalarValidationIssues({
1267
- entryType: args.kind,
1268
- validation: effectiveValidation(args.kind, args.validation),
1269
- value: args.value
1270
- });
1271
- return issues === void 0 ? void 0 : `${args.label}: ${issues.join("; ")}`;
1272
- }
1273
-
1274
1313
  function countBy(rows, keysOf) {
1275
1314
  const counts = /* @__PURE__ */ new Map;
1276
1315
  for (const row of rows) for (const key of keysOf(row)) counts.set(key, (counts.get(key) ?? 0) + 1);
@@ -1318,6 +1357,10 @@ function disambiguatedNames(displays) {
1318
1357
  return displays.map(display => (counts.get(display.name) ?? 0) < 2 || display.loginProvider === void 0 ? display.name : `${display.name} (${workflowComponents.providerTitle(display.loginProvider) ?? display.loginProvider})`);
1319
1358
  }
1320
1359
 
1360
+ function uniqueIds(ids) {
1361
+ return [ ...new Set(ids) ];
1362
+ }
1363
+
1321
1364
  function useUserDisplays(ids) {
1322
1365
  const {members: members} = useProjectMembers(), {users: users} = workflowStudio.useStudioProjectUsers(), meRaw = sanity.useCurrentUser(), me = react.useMemo(() => meRaw === null ? null : {
1323
1366
  ...meRaw,
@@ -1384,16 +1427,18 @@ function useSelfActor() {
1384
1427
  }
1385
1428
 
1386
1429
  function useAssignmentIdentity() {
1387
- const state = useSelfState();
1388
- if (state.kind !== "resolved") return state;
1389
- const {id: id, roles: roles} = state.self;
1390
- return {
1430
+ const state = useSelfState(), id = state.kind === "resolved" ? state.self.id : void 0, roles = state.kind === "resolved" ? state.self.roles : void 0;
1431
+ return react.useMemo(() => id === void 0 || roles === void 0 ? state.kind === "pending" ? {
1432
+ kind: "pending"
1433
+ } : {
1434
+ kind: "unavailable"
1435
+ } : {
1391
1436
  kind: "resolved",
1392
1437
  identity: {
1393
1438
  userId: id,
1394
- roles: roles.map(r => r.name)
1439
+ roles: roles.map(role => role.name)
1395
1440
  }
1396
- };
1441
+ }, [ id, roles, state.kind ]);
1397
1442
  }
1398
1443
 
1399
1444
  function identityOf(state) {
@@ -1423,15 +1468,35 @@ function projectMembersFrom(users) {
1423
1468
  }
1424
1469
 
1425
1470
  function useProjectMembers() {
1426
- const {users: users, roles: roles, loading: loading, error: error} = workflowStudio.useStudioProjectUsers();
1427
- return {
1428
- members: react.useMemo(() => projectMembersFrom(users), [ users ]),
1471
+ const {users: users, roles: roles, loading: loading, error: error} = workflowStudio.useStudioProjectUsers(), members = react.useMemo(() => projectMembersFrom(users), [ users ]), message = react.useMemo(() => error === void 0 ? void 0 : workflowEngine.errorMessage(error), [ error ]);
1472
+ return react.useMemo(() => ({
1473
+ members: members,
1429
1474
  roles: roles,
1430
1475
  loading: loading,
1431
- error: error === void 0 ? void 0 : workflowEngine.errorMessage(error)
1476
+ error: message
1477
+ }), [ loading, members, message, roles ]);
1478
+ }
1479
+
1480
+ function isEmptyValue(value) {
1481
+ return value == null || value === "" || Array.isArray(value) && value.length === 0;
1482
+ }
1483
+
1484
+ function effectiveValidation(kind, validation) {
1485
+ return kind !== "progress" ? validation : {
1486
+ min: validation?.min ?? 0,
1487
+ max: validation?.max ?? 100
1432
1488
  };
1433
1489
  }
1434
1490
 
1491
+ function scalarValidationIssue(args) {
1492
+ const issues = workflowEngine.scalarValidationIssues({
1493
+ entryType: args.kind,
1494
+ validation: effectiveValidation(args.kind, args.validation),
1495
+ value: args.value
1496
+ });
1497
+ return issues === void 0 ? void 0 : `${args.label}: ${issues.join("; ")}`;
1498
+ }
1499
+
1435
1500
  const passthrough = raw => ({
1436
1501
  value: raw
1437
1502
  }), paramConverter = {
@@ -1794,31 +1859,19 @@ function MemberPicker({selectedIds: selectedIds, onSelect: onSelect, unassignRow
1794
1859
  });
1795
1860
  }
1796
1861
 
1797
- function AssigneePicker({value: value, onChange: onChange, eligibleRoles: eligibleRoles, roleAliases: roleAliases}) {
1862
+ function AssigneePicker({value: value, onChange: onChange, eligibleRoles: eligibleRoles, roleAliases: roleAliases, maxUsers: maxUsers}) {
1798
1863
  const state = useProjectMembers();
1799
1864
  /* @__PURE__ */
1800
1865
  return jsxRuntime.jsx(workflowComponents.AssigneePicker, {
1801
1866
  ...state,
1802
1867
  eligibleRoles: eligibleRoles,
1868
+ maxUsers: maxUsers,
1803
1869
  onChange: onChange,
1804
1870
  roleAliases: roleAliases,
1805
1871
  value: value
1806
1872
  });
1807
1873
  }
1808
1874
 
1809
- function SingleAssigneePicker({current: current, onPick: onPick, eligibleRoles: eligibleRoles, roleAliases: roleAliases}) {
1810
- /* @__PURE__ */
1811
- return jsxRuntime.jsx(AssigneePicker, {
1812
- eligibleRoles: eligibleRoles,
1813
- onChange: next => {
1814
- const picked = singleAssigneePick(current, next);
1815
- picked !== void 0 && onPick(picked);
1816
- },
1817
- roleAliases: roleAliases,
1818
- value: current ? [ current ] : []
1819
- });
1820
- }
1821
-
1822
1875
  function MemberPickerButton({label: label = "Select member…", onChange: onChange, selectedIds: selectedIds, unassignRow: unassignRow = !1, value: value}) {
1823
1876
  const [open, setOpen] = react.useState(!1), {imageUrl: imageUrl} = useUserDisplay(value?.id ?? ""), selected = selectedIds ?? (value ? /* @__PURE__ */ new Set([ value.id ]) : /* @__PURE__ */ new Set), toggle = () => setOpen(v => !v);
1824
1877
  /* @__PURE__ */
@@ -2489,39 +2542,6 @@ function ParamsActionButton({actionEval: actionEval, instanceId: instanceId, act
2489
2542
  });
2490
2543
  }
2491
2544
 
2492
- const DIM = {
2493
- opacity: .6
2494
- };
2495
-
2496
- function Breadcrumb({segments: segments, emphasizeCurrent: emphasizeCurrent = !1}) {
2497
- /* @__PURE__ */
2498
- return jsxRuntime.jsx(jsxRuntime.Fragment, {
2499
- children: segments.map((segment, i) => /* @__PURE__ */ jsxRuntime.jsxs(react.Fragment, {
2500
- children: [ i > 0 ? /* @__PURE__ */ jsxRuntime.jsx(Separator, {}) : null,
2501
- /* @__PURE__ */ jsxRuntime.jsx("span", {
2502
- style: emphasizeCurrent && i < segments.length - 1 ? DIM : void 0,
2503
- children: segment
2504
- }) ]
2505
- }, `${i}-${segment}`))
2506
- });
2507
- }
2508
-
2509
- function Separator() {
2510
- /* @__PURE__ */
2511
- return jsxRuntime.jsx("span", {
2512
- "aria-hidden": !0,
2513
- style: {
2514
- ...DIM,
2515
- alignItems: "center",
2516
- display: "inline-flex",
2517
- height: "0.7em",
2518
- margin: "0 0.5em",
2519
- overflow: "hidden"
2520
- },
2521
- children: /* @__PURE__ */ jsxRuntime.jsx(ChevronRight.ChevronRightIcon, {})
2522
- });
2523
- }
2524
-
2525
2545
  function stageTitle(definition, stageName) {
2526
2546
  return workflowEngine.findStageNode({
2527
2547
  definition: definition,
@@ -2736,10 +2756,81 @@ function docFaceChrome(args) {
2736
2756
  }
2737
2757
  }
2738
2758
 
2759
+ function useEditIntentLink(bareId) {
2760
+ return react.useMemo(() => bareId === void 0 ? void 0 : function(linkProps) {
2761
+ /* @__PURE__ */
2762
+ return jsxRuntime.jsx(router.IntentLink, {
2763
+ ...linkProps,
2764
+ intent: "edit",
2765
+ params: {
2766
+ id: bareId
2767
+ }
2768
+ });
2769
+ }, [ bareId ]);
2770
+ }
2771
+
2772
+ function useSpaceToken(index) {
2773
+ const value = ui.useTheme_v2().space[index];
2774
+ if (value === void 0) throw new Error(`theme is missing space token ${index}`);
2775
+ return value;
2776
+ }
2777
+
2778
+ function useRadiusToken(index) {
2779
+ const value = ui.useTheme_v2().radius[index];
2780
+ if (value === void 0) throw new Error(`theme is missing radius token ${index}`);
2781
+ return value;
2782
+ }
2783
+
2784
+ function useContainerToken(index) {
2785
+ const value = ui.useTheme_v2().container[index];
2786
+ if (value === void 0) throw new Error(`theme is missing container token ${index}`);
2787
+ return value;
2788
+ }
2789
+
2790
+ function useTextCapHeight() {
2791
+ const textSize = ui.useTheme_v2().font.text.sizes[1];
2792
+ if (!textSize) throw new Error("useTextCapHeight: theme is missing text size 1");
2793
+ return textSize.lineHeight - textSize.ascenderHeight - textSize.descenderHeight;
2794
+ }
2795
+
2796
+ function useCapTrimFor(size) {
2797
+ return (useTextCapHeight() - size) / 2;
2798
+ }
2799
+
2800
+ function useTextIconSize() {
2801
+ const textSize = ui.useTheme_v2().font.text.sizes[1];
2802
+ if (!textSize) throw new Error("useTextIconSize: theme is missing text size 1");
2803
+ return textSize.iconSize;
2804
+ }
2805
+
2806
+ function useAvatarSize() {
2807
+ const avatarSize = ui.useTheme_v2().avatar.sizes[0];
2808
+ if (!avatarSize) throw new Error("useAvatarSize: theme is missing avatar size 0");
2809
+ return avatarSize.size;
2810
+ }
2811
+
2812
+ function useAvatarCapTrim() {
2813
+ return useCapTrimFor(useAvatarSize());
2814
+ }
2815
+
2816
+ function useBadgeCapTrim() {
2817
+ const badgePadding = useSpaceToken(1);
2818
+ return {
2819
+ marginBottom: -badgePadding,
2820
+ marginTop: -badgePadding
2821
+ };
2822
+ }
2823
+
2739
2824
  function chipPadding(fill) {
2740
2825
  return fill ? 3 : 2;
2741
2826
  }
2742
2827
 
2828
+ function useChipTrim() {
2829
+ return {
2830
+ margin: -useSpaceToken(chipPadding(!1))
2831
+ };
2832
+ }
2833
+
2743
2834
  function LinkChip({hint: hint, children: children, as: as = "a", fill: fill = !1, ...anchorProps}) {
2744
2835
  /* @__PURE__ */
2745
2836
  return jsxRuntime.jsx(HoverHint, {
@@ -2938,12 +3029,18 @@ function InlineChipFace({bareId: bareId, schemaType: schemaType}) {
2938
3029
  return jsxRuntime.jsxs(ui.Flex, {
2939
3030
  align: "center",
2940
3031
  gap: 2,
3032
+ style: {
3033
+ minWidth: 0
3034
+ },
2941
3035
  children: [
2942
3036
  /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
2943
3037
  size: 1,
2944
3038
  children: renderTypeIcon(schemaType.icon)
2945
3039
  }), preview.isLoading ? /* @__PURE__ */ jsxRuntime.jsx(TitleSkeleton, {}) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
2946
3040
  size: 1,
3041
+ style: {
3042
+ minWidth: 0
3043
+ },
2947
3044
  textOverflow: "ellipsis",
2948
3045
  weight: "medium",
2949
3046
  children: preview.value?.title ?? /* @__PURE__ */ jsxRuntime.jsx("em", {
@@ -3004,16 +3101,7 @@ function DocRefShell({face: face, layout: layout, source: source}) {
3004
3101
  e.stopPropagation(), telemetry2.log(WorkflowDocumentLinkClicked, {
3005
3102
  source: source
3006
3103
  });
3007
- }, EditIntentLink = react.useMemo(() => bareId === void 0 ? void 0 : function(linkProps) {
3008
- /* @__PURE__ */
3009
- return jsxRuntime.jsx(router.IntentLink, {
3010
- ...linkProps,
3011
- intent: "edit",
3012
- params: {
3013
- id: bareId
3014
- }
3015
- });
3016
- }, [ bareId ]);
3104
+ }, EditIntentLink = useEditIntentLink(bareId);
3017
3105
  if (isCompact(layout)) /* @__PURE__ */
3018
3106
  return jsxRuntime.jsx(CompactDocRef, {
3019
3107
  face: face,
@@ -3176,8 +3264,8 @@ const fieldValueRenderer = {
3176
3264
  array: field => /* @__PURE__ */ jsxRuntime.jsx(ArrayValueRows, {
3177
3265
  rows: field.value
3178
3266
  }),
3179
- assignee: field => field.value ? /* @__PURE__ */ jsxRuntime.jsx(AssigneeBadges, {
3180
- assignees: [ field.value ]
3267
+ assignee: field => field.value.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(AssigneeBadges, {
3268
+ assignees: field.value
3181
3269
  }) : /* @__PURE__ */ jsxRuntime.jsx(Empty, {}),
3182
3270
  assignees: field => field.value.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(AssigneeBadges, {
3183
3271
  assignees: field.value
@@ -3348,8 +3436,8 @@ function ReadOnlyAssigneeValue({value: value}) {
3348
3436
  padding: 2,
3349
3437
  radius: 2,
3350
3438
  tone: "transparent",
3351
- children: value ? /* @__PURE__ */ jsxRuntime.jsx(AssigneeBadges, {
3352
- assignees: [ value ]
3439
+ children: value.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(AssigneeBadges, {
3440
+ assignees: value
3353
3441
  }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
3354
3442
  muted: !0,
3355
3443
  size: 1,
@@ -3388,7 +3476,7 @@ function ReadOnlyValueFace({entry: entry}) {
3388
3476
  });
3389
3477
  }
3390
3478
 
3391
- const VALUE_FACE_KINDS = /* @__PURE__ */ new Set([ "assignees", "object", "array" ]);
3479
+ const VALUE_FACE_KINDS = /* @__PURE__ */ new Set([ "assignee", "assignees", "object", "array" ]);
3392
3480
 
3393
3481
  function ReadOnlyField({entry: entry}) {
3394
3482
  return workflowEngine.isSingleDocRefEntry(entry) ? /* @__PURE__ */ jsxRuntime.jsx(DocPicker, {
@@ -3404,8 +3492,6 @@ function ReadOnlyField({entry: entry}) {
3404
3492
  value: entry.value?.releaseName ?? ""
3405
3493
  }) : entry._type === "actor" ? /* @__PURE__ */ jsxRuntime.jsx(ReadOnlyActorValue, {
3406
3494
  value: entry.value
3407
- }) : entry._type === "assignee" ? /* @__PURE__ */ jsxRuntime.jsx(ReadOnlyAssigneeValue, {
3408
- value: entry.value
3409
3495
  }) : VALUE_FACE_KINDS.has(entry._type) ? /* @__PURE__ */ jsxRuntime.jsx(ReadOnlyValueFace, {
3410
3496
  entry: entry
3411
3497
  }) : /* @__PURE__ */ jsxRuntime.jsx(FieldInput$1, {
@@ -3631,49 +3717,30 @@ function ActorField({field: field, instanceId: instanceId, onSave: onSave, onUns
3631
3717
  });
3632
3718
  }
3633
3719
 
3634
- function useAssigneePick(args) {
3635
- const {onSave: onSave, onUnset: onUnset} = args, {saving: saving, save: save} = useSaveField({
3636
- instanceId: args.instanceId
3637
- });
3638
- return {
3639
- saving: saving,
3640
- pick: picked => {
3641
- if (!saving) {
3642
- if (picked === null) {
3643
- onUnset !== void 0 && save(onUnset);
3644
- return;
3645
- }
3646
- save(() => onSave(picked));
3647
- }
3648
- }
3649
- };
3650
- }
3651
-
3652
- function AssigneeField({field: field, instanceId: instanceId, onSave: onSave, onUnset: onUnset}) {
3653
- const [open, setOpen] = react.useState(!1), cur = isAssigneeShape(field.value) ? field.value : null, {pick: pick} = useAssigneePick({
3654
- instanceId: instanceId,
3655
- onSave: onSave,
3656
- onUnset: onUnset
3720
+ function AssigneeField({field: field, instanceId: instanceId, onSave: onSave}) {
3721
+ const [open, setOpen] = react.useState(!1), cur = Array.isArray(field.value) ? field.value.filter(isAssigneeShape) : [], {saving: saving, save: save} = useSaveField({
3722
+ instanceId: instanceId
3657
3723
  });
3658
3724
  return field.editable ? /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
3659
3725
  align: "center",
3660
3726
  children: /* @__PURE__ */ jsxRuntime.jsx(DismissablePopover, {
3661
- content: /* @__PURE__ */ jsxRuntime.jsx(SingleAssigneePicker, {
3662
- current: cur,
3727
+ content: /* @__PURE__ */ jsxRuntime.jsx(AssigneePicker, {
3663
3728
  eligibleRoles: field.roles,
3664
- onPick: picked => {
3665
- setOpen(!1), pick(picked);
3729
+ maxUsers: 1,
3730
+ onChange: next => {
3731
+ saving || save(() => onSave(next));
3666
3732
  },
3667
- roleAliases: field.roleAliases
3733
+ roleAliases: field.roleAliases,
3734
+ value: cur
3668
3735
  }),
3669
3736
  onDismiss: () => setOpen(!1),
3670
3737
  open: open,
3671
3738
  children: /* @__PURE__ */ jsxRuntime.jsx(EditableValueButton, {
3672
- hint: cur ? "Reassign" : "Assign",
3739
+ hint: cur.length > 0 ? "Change assignment" : "Assign",
3673
3740
  hintDisabled: open,
3674
3741
  onClick: () => setOpen(v => !v),
3675
- children: cur ? /* @__PURE__ */ jsxRuntime.jsx(AssigneeBadges, {
3676
- assignees: [ cur ]
3742
+ children: cur.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(AssigneeBadges, {
3743
+ assignees: cur
3677
3744
  }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
3678
3745
  muted: !0,
3679
3746
  size: 1,
@@ -3933,8 +4000,7 @@ function fieldArm({arm: arm, entry: entry, onUnset: onUnset, onAppend: onAppend,
3933
4000
  ...arm,
3934
4001
  onUnset: onUnset
3935
4002
  }) : field.type === "assignee" ? /* @__PURE__ */ jsxRuntime.jsx(AssigneeField, {
3936
- ...arm,
3937
- onUnset: onUnset
4003
+ ...arm
3938
4004
  }) : field.type === "assignees" ? /* @__PURE__ */ jsxRuntime.jsx(ValueDisplay, {
3939
4005
  field: field,
3940
4006
  value: field.value
@@ -3995,8 +4061,19 @@ function EditableField({field: field, entry: entry, description: description, in
3995
4061
  });
3996
4062
  }
3997
4063
 
3998
- function useDrainEffects(instanceId) {
3999
- const {drainEffectsFor: drainEffectsFor} = useWorkflowContext(), toast = useWorkflowToast(), [busy, setBusy] = react.useState(!1);
4064
+ function Hairline({weight: weight, style: style}) {
4065
+ const {color: color} = ui.useTheme_v2();
4066
+ /* @__PURE__ */
4067
+ return jsxRuntime.jsx("div", {
4068
+ style: {
4069
+ borderTop: `${weight}px solid ${color.border}`,
4070
+ ...style
4071
+ }
4072
+ });
4073
+ }
4074
+
4075
+ function useDrainEffects(instanceId) {
4076
+ const {drainEffectsFor: drainEffectsFor} = useWorkflowContext(), toast = useWorkflowToast(), [busy, setBusy] = react.useState(!1);
4000
4077
  return {
4001
4078
  busy: busy,
4002
4079
  run: async () => {
@@ -4256,6 +4333,27 @@ function TaskControls({actions: actions, instanceId: instanceId, remedies: remed
4256
4333
  });
4257
4334
  }
4258
4335
 
4336
+ const LABEL = "Open in document";
4337
+
4338
+ function OpenDocumentLink({gdr: gdr, source: source}) {
4339
+ const state = useDocLink(gdr), telemetry2 = workflowReact.useWorkflowTelemetry(), link = useEditIntentLink(state.kind === "linked" ? state.bareId : void 0);
4340
+ return link === void 0 ? /* @__PURE__ */ jsxRuntime.jsx(DocPreviewLink, {
4341
+ gdr: gdr,
4342
+ layout: "inline",
4343
+ source: source
4344
+ }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
4345
+ as: link,
4346
+ fontSize: 1,
4347
+ iconRight: Launch.LaunchIcon,
4348
+ mode: "bleed",
4349
+ onClick: () => telemetry2.log(WorkflowDocumentLinkClicked, {
4350
+ source: source
4351
+ }),
4352
+ padding: 2,
4353
+ text: LABEL
4354
+ });
4355
+ }
4356
+
4259
4357
  function MetaRow({children: children, fillHeight: fillHeight, label: label}) {
4260
4358
  /* @__PURE__ */
4261
4359
  return jsxRuntime.jsxs(ui.Flex, {
@@ -4279,11 +4377,88 @@ function MetaRow({children: children, fillHeight: fillHeight, label: label}) {
4279
4377
  }),
4280
4378
  /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
4281
4379
  flex: 1,
4380
+ style: {
4381
+ minWidth: 0
4382
+ },
4282
4383
  children: children
4283
4384
  }) ]
4284
4385
  });
4285
4386
  }
4286
4387
 
4388
+ function RowAssignees({assignees: assignees, hint: hint}) {
4389
+ const ids = userIdsOf(assignees), vocabulary = useProjectMembers(), roles = assignees.flatMap(item => item.type === "role" ? [ workflowComponents.memberRoleFor(vocabulary, item.role) ] : []), displays = useUserDisplays(ids);
4390
+ if (ids.length === 0 && roles.length === 0) return null;
4391
+ const bothKinds = roles.length > 0 && displays.length > 0;
4392
+ /* @__PURE__ */
4393
+ return jsxRuntime.jsx(HoverHint, {
4394
+ content: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
4395
+ gap: 3,
4396
+ children: [ roles.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(HintSection, {
4397
+ names: roles.map(workflowComponents.roleLabel),
4398
+ ...bothKinds ? {
4399
+ label: "Roles"
4400
+ } : {}
4401
+ }) : null, displays.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(HintSection, {
4402
+ names: disambiguatedNames(displays),
4403
+ ...bothKinds ? {
4404
+ label: "Members"
4405
+ } : {}
4406
+ }) : null, hint === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
4407
+ muted: !0,
4408
+ size: 1,
4409
+ children: hint
4410
+ }) ]
4411
+ }),
4412
+ children: /* @__PURE__ */ jsxRuntime.jsx(workflowComponents.AssigneeStack, {
4413
+ members: displays.map(display => ({
4414
+ id: display.id,
4415
+ displayName: display.name,
4416
+ imageUrl: display.imageUrl
4417
+ })),
4418
+ roles: roles
4419
+ })
4420
+ });
4421
+ }
4422
+
4423
+ function HintSection({label: label, names: names}) {
4424
+ /* @__PURE__ */
4425
+ return jsxRuntime.jsxs(ui.Stack, {
4426
+ gap: 2,
4427
+ children: [ label === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
4428
+ size: 1,
4429
+ weight: "medium",
4430
+ children: label
4431
+ }),
4432
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
4433
+ size: 1,
4434
+ children: names.join(", ")
4435
+ }) ]
4436
+ });
4437
+ }
4438
+
4439
+ function SectionHeading({children: children}) {
4440
+ /* @__PURE__ */
4441
+ return jsxRuntime.jsx(ui.Text, {
4442
+ size: 1,
4443
+ weight: "medium",
4444
+ children: children
4445
+ });
4446
+ }
4447
+
4448
+ function OverlineHeading({children: children}) {
4449
+ /* @__PURE__ */
4450
+ return jsxRuntime.jsx(ui.Text, {
4451
+ muted: !0,
4452
+ size: 0,
4453
+ style: {
4454
+ letterSpacing: "0.06em",
4455
+ textTransform: "uppercase"
4456
+ },
4457
+ weight: "semibold",
4458
+ children: children
4459
+ });
4460
+ }
4461
+
4287
4462
  function CheckmarkCircleFilledIcon(props) {
4288
4463
  /* @__PURE__ */
4289
4464
  return jsxRuntime.jsx("svg", {
@@ -4337,58 +4512,6 @@ function ActivityStatusIcon({status: status}) {
4337
4512
  });
4338
4513
  }
4339
4514
 
4340
- function useSpaceToken(index) {
4341
- const value = ui.useTheme_v2().space[index];
4342
- if (value === void 0) throw new Error(`theme is missing space token ${index}`);
4343
- return value;
4344
- }
4345
-
4346
- function useRadiusToken(index) {
4347
- const value = ui.useTheme_v2().radius[index];
4348
- if (value === void 0) throw new Error(`theme is missing radius token ${index}`);
4349
- return value;
4350
- }
4351
-
4352
- function useContainerToken(index) {
4353
- const value = ui.useTheme_v2().container[index];
4354
- if (value === void 0) throw new Error(`theme is missing container token ${index}`);
4355
- return value;
4356
- }
4357
-
4358
- function useTextCapHeight() {
4359
- const textSize = ui.useTheme_v2().font.text.sizes[1];
4360
- if (!textSize) throw new Error("useTextCapHeight: theme is missing text size 1");
4361
- return textSize.lineHeight - textSize.ascenderHeight - textSize.descenderHeight;
4362
- }
4363
-
4364
- function useCapTrimFor(size) {
4365
- return (useTextCapHeight() - size) / 2;
4366
- }
4367
-
4368
- function useTextIconSize() {
4369
- const textSize = ui.useTheme_v2().font.text.sizes[1];
4370
- if (!textSize) throw new Error("useTextIconSize: theme is missing text size 1");
4371
- return textSize.iconSize;
4372
- }
4373
-
4374
- function useAvatarSize() {
4375
- const avatarSize = ui.useTheme_v2().avatar.sizes[0];
4376
- if (!avatarSize) throw new Error("useAvatarSize: theme is missing avatar size 0");
4377
- return avatarSize.size;
4378
- }
4379
-
4380
- function useAvatarCapTrim() {
4381
- return useCapTrimFor(useAvatarSize());
4382
- }
4383
-
4384
- function useBadgeCapTrim() {
4385
- const badgePadding = useSpaceToken(1);
4386
- return {
4387
- marginBottom: -badgePadding,
4388
- marginTop: -badgePadding
4389
- };
4390
- }
4391
-
4392
4515
  function SpinnerSlot({busy: busy, reserve: reserve = !0}) {
4393
4516
  const size = useTextIconSize(), trim = useCapTrimFor(size), spinning = useDelayedFlag(busy, LOADING_CUE_DELAY_MS);
4394
4517
  return !spinning && !reserve ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
@@ -4479,55 +4602,8 @@ function AvatarButton({avatar: avatar, onClick: onClick, onMouseDown: onMouseDow
4479
4602
  });
4480
4603
  }
4481
4604
 
4482
- function RowAssignees({assignees: assignees, hint: hint}) {
4483
- 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);
4484
- if (ids.length === 0 && roles.length === 0) return null;
4485
- const bothKinds = roles.length > 0 && displays.length > 0;
4486
- /* @__PURE__ */
4487
- return jsxRuntime.jsx(HoverHint, {
4488
- content: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
4489
- gap: 3,
4490
- children: [ roles.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(HintSection, {
4491
- names: roles.map(workflowComponents.roleLabel),
4492
- ...bothKinds ? {
4493
- label: "Roles"
4494
- } : {}
4495
- }) : null, displays.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(HintSection, {
4496
- names: disambiguatedNames(displays),
4497
- ...bothKinds ? {
4498
- label: "Members"
4499
- } : {}
4500
- }) : null, hint === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
4501
- muted: !0,
4502
- size: 1,
4503
- children: hint
4504
- }) ]
4505
- }),
4506
- children: /* @__PURE__ */ jsxRuntime.jsx(workflowComponents.AssigneeStack, {
4507
- members: displays.map(display => ({
4508
- id: display.id,
4509
- displayName: display.name,
4510
- imageUrl: display.imageUrl
4511
- })),
4512
- roles: roles
4513
- })
4514
- });
4515
- }
4516
-
4517
- function HintSection({label: label, names: names}) {
4518
- /* @__PURE__ */
4519
- return jsxRuntime.jsxs(ui.Stack, {
4520
- gap: 2,
4521
- children: [ label === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
4522
- size: 1,
4523
- weight: "medium",
4524
- children: label
4525
- }),
4526
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
4527
- size: 1,
4528
- children: names.join(", ")
4529
- }) ]
4530
- });
4605
+ function assignActivityIcon(assigneeCount) {
4606
+ return assigneeCount > 0 ? AddUser.AddUserIcon : User.UserIcon;
4531
4607
  }
4532
4608
 
4533
4609
  function AssignActivityControl({instanceId: instanceId, state: state, surface: surface, assignees: assignees = []}) {
@@ -4587,7 +4663,7 @@ function AssignActivityControl({instanceId: instanceId, state: state, surface: s
4587
4663
  "aria-label": "Assign",
4588
4664
  as: "span",
4589
4665
  fontSize: 1,
4590
- icon: User.UserIcon,
4666
+ icon: assignActivityIcon(current.length),
4591
4667
  mode: "bleed",
4592
4668
  onClick: handleClick,
4593
4669
  onMouseDown: stopRowMouseDown,
@@ -4620,7 +4696,7 @@ function rowMatches(row, filter) {
4620
4696
  if (filter === void 0) return !0;
4621
4697
  switch (filter.kind) {
4622
4698
  case "mine":
4623
- return isItemAssignedTo(row.item, filter.identity);
4699
+ return holdingMatchesAssignment(itemHolding(row.item, filter.identity), filter.assignment);
4624
4700
 
4625
4701
  case "activity":
4626
4702
  return row.activityName === filter.activity || row.tick?.activity === filter.activity;
@@ -4820,20 +4896,18 @@ function DueDateControl({item: item, editable: editable, onPatch: onPatch}) {
4820
4896
  }
4821
4897
 
4822
4898
  function AssigneeControl({item: item, editable: editable, eligibleRoles: eligibleRoles, onPatch: onPatch, roleAliases: roleAliases}) {
4823
- const [open, setOpen] = react.useState(!1), current = item.assignee ?? null, chip = current ? /* @__PURE__ */ jsxRuntime.jsx(RowAssignees, {
4824
- assignees: [ current ]
4899
+ const [open, setOpen] = react.useState(!1), current = item.assignee ?? [], chip = current.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(RowAssignees, {
4900
+ assignees: current
4825
4901
  }) : null;
4826
4902
  return editable ? /* @__PURE__ */ jsxRuntime.jsx(DismissablePopover, {
4827
- content:
4828
- /* @__PURE__ */ jsxRuntime.jsx(SingleAssigneePicker, {
4829
- current: current,
4903
+ content: /* @__PURE__ */ jsxRuntime.jsx(AssigneePicker, {
4830
4904
  eligibleRoles: eligibleRoles,
4831
- onPick: picked => {
4832
- setOpen(!1), onPatch({
4833
- assignee: picked
4834
- });
4835
- },
4836
- roleAliases: roleAliases
4905
+ maxUsers: 1,
4906
+ onChange: picked => onPatch({
4907
+ assignee: [ ...picked ]
4908
+ }),
4909
+ roleAliases: roleAliases,
4910
+ value: current
4837
4911
  }),
4838
4912
  onDismiss: () => setOpen(!1),
4839
4913
  open: open,
@@ -5350,7 +5424,7 @@ function ActionsMenuButton({actions: actions, instanceId: instanceId, activity:
5350
5424
 
5351
5425
  const FOOTER_GAP_PX = 8, MORE_ACTIONS_LABEL = "More actions";
5352
5426
 
5353
- function TerminalFooter({actions: actions, activity: activity, instanceId: instanceId}) {
5427
+ function TerminalFooter({actions: actions, activity: activity, instanceId: instanceId, surface: surface}) {
5354
5428
  const lock = useActionClusterState(), [only, ...rest] = actions;
5355
5429
  return only ? /* @__PURE__ */ jsxRuntime.jsx(ActionClusterProvider, {
5356
5430
  value: lock,
@@ -5360,12 +5434,13 @@ function TerminalFooter({actions: actions, activity: activity, instanceId: insta
5360
5434
  activity: activity,
5361
5435
  instanceId: instanceId,
5362
5436
  placement: "terminal-footer",
5363
- surface: "activity-dialog"
5437
+ surface: surface
5364
5438
  })
5365
5439
  }) : /* @__PURE__ */ jsxRuntime.jsx(FittedActions, {
5366
5440
  actions: actions,
5367
5441
  activity: activity,
5368
- instanceId: instanceId
5442
+ instanceId: instanceId,
5443
+ surface: surface
5369
5444
  })
5370
5445
  }) : null;
5371
5446
  }
@@ -5388,7 +5463,7 @@ function FooterRow({children: children, onElement: onElement}) {
5388
5463
  });
5389
5464
  }
5390
5465
 
5391
- function FittedActions({actions: actions, activity: activity, instanceId: instanceId}) {
5466
+ function FittedActions({actions: actions, activity: activity, instanceId: instanceId, surface: surface}) {
5392
5467
  const [footerEl, setFooterEl] = react.useState(null), [measureEl, setMeasureEl] = react.useState(null), footerSize = ui.useElementSize(footerEl), measureSize = ui.useElementSize(measureEl), [inline, setInline] = react.useState(void 0);
5393
5468
  react.useLayoutEffect(() => {
5394
5469
  if (measureEl === null || footerSize === null || measureSize === null) return;
@@ -5416,7 +5491,7 @@ function FittedActions({actions: actions, activity: activity, instanceId: instan
5416
5491
  activity: activity,
5417
5492
  instanceId: instanceId,
5418
5493
  placement: "terminal-footer",
5419
- surface: "activity-dialog"
5494
+ surface: surface
5420
5495
  }, a.action.name)), overflow.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(ActionsMenuButton, {
5421
5496
  actions: overflow,
5422
5497
  activity: activity,
@@ -5424,7 +5499,7 @@ function FittedActions({actions: actions, activity: activity, instanceId: instan
5424
5499
  label: MORE_ACTIONS_LABEL,
5425
5500
  mode: "default",
5426
5501
  placement: "terminal-footer",
5427
- surface: "activity-dialog"
5502
+ surface: surface
5428
5503
  }) : null ]
5429
5504
  }) ]
5430
5505
  });
@@ -5467,33 +5542,43 @@ function MeasureRow({actions: actions, activity: activity, onElement: onElement}
5467
5542
  });
5468
5543
  }
5469
5544
 
5470
- function ActivityDetailDialog({entry: entry, activityName: activityName, breadcrumb: breadcrumb, definition: definition, document: document, source: source, onClose: onClose}) {
5545
+ function ActivityDetailBody({activityName: activityName, definition: definition, document: document, entry: entry, layout: layout, source: source, surface: surface, todoSurface: todoSurface}) {
5471
5546
  const detail = deriveActivityDetail({
5472
5547
  entry: entry,
5473
5548
  activityName: activityName
5474
- }), faultingActivity2 = useInstanceFault(entry)?.activity;
5549
+ }), faultingActivity2 = useInstanceFault(entry)?.activity, identity = useAssignmentIdentity();
5475
5550
  if (!detail) return null;
5476
- const instanceId = entry.instance._id, notice = blockedNotice(detail), fault = /* @__PURE__ */ jsxRuntime.jsx(InstanceFaultNote, {
5477
- entry: entry,
5478
- scope: {
5479
- kind: "task",
5480
- activityName: activityName
5481
- }
5482
- }), faulted = faultingActivity2 === activityName, hasBody = detail.state.length > 0 || notice !== void 0 || faulted;
5551
+ const instanceId = entry.instance._id, notice = activityNotice(detail), faulted = faultingActivity2 === activityName, hasBody = detail.state.length > 0 || notice !== void 0 || faulted, common = {
5552
+ activityName: activityName,
5553
+ definition: definition,
5554
+ detail: detail,
5555
+ docLinkSource: layout === "panel" ? "task-panel-subject" : "dialog-subject",
5556
+ instanceId: instanceId,
5557
+ surface: surface
5558
+ }, work = hasBody ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
5559
+ children: [
5560
+ /* @__PURE__ */ jsxRuntime.jsx(InstanceFaultNote, {
5561
+ entry: entry,
5562
+ scope: {
5563
+ kind: "task",
5564
+ activityName: activityName
5565
+ }
5566
+ }), detail.state.map(field => /* @__PURE__ */ jsxRuntime.jsx(FieldRow, {
5567
+ activityName: activityName,
5568
+ detail: detail,
5569
+ entry: entry,
5570
+ field: field,
5571
+ instanceId: instanceId,
5572
+ layout: layout,
5573
+ surface: surface,
5574
+ todoSurface: todoSurface
5575
+ }, field._key)), notice ]
5576
+ }) : null, who = identityOf(identity);
5483
5577
  /* @__PURE__ */
5484
- return jsxRuntime.jsxs(ui.Dialog, {
5485
- footer: detail.presentation.terminalActions.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(TerminalFooter, {
5486
- actions: detail.presentation.terminalActions,
5487
- activity: activityName,
5488
- instanceId: instanceId
5489
- }) : void 0,
5490
- header: /* @__PURE__ */ jsxRuntime.jsx(Breadcrumb, {
5491
- emphasizeCurrent: !0,
5492
- segments: [ ...breadcrumb, detail.title ]
5493
- }),
5494
- id: "workflow-activity-detail",
5495
- onClose: onClose,
5496
- width: 1,
5578
+ return jsxRuntime.jsxs(ui.Flex, {
5579
+ direction: "column",
5580
+ flex: 1,
5581
+ overflow: "hidden",
5497
5582
  children: [
5498
5583
  /* @__PURE__ */ jsxRuntime.jsx(LogEventOnMount, {
5499
5584
  data: {
@@ -5501,86 +5586,264 @@ function ActivityDetailDialog({entry: entry, activityName: activityName, breadcr
5501
5586
  source: source
5502
5587
  },
5503
5588
  event: WorkflowActivityDialogOpened
5589
+ }), layout === "panel" ? /* @__PURE__ */ jsxRuntime.jsx(PanelBody, {
5590
+ ...common,
5591
+ document: document,
5592
+ holding: who === void 0 ? "other" : activityHolding({
5593
+ state: detail.state,
5594
+ who: who
5595
+ }),
5596
+ children: work
5597
+ }) : /* @__PURE__ */ jsxRuntime.jsx(DialogBody, {
5598
+ ...common,
5599
+ document: document,
5600
+ separated: hasBody,
5601
+ children: work
5602
+ }) ]
5603
+ });
5604
+ }
5605
+
5606
+ function PanelBody({children: children, document: document, holding: holding, ...props}) {
5607
+ const {definition: definition, detail: detail} = props, description = detail.activityEval.activity.description;
5608
+ /* @__PURE__ */
5609
+ return jsxRuntime.jsxs(jsxRuntime.Fragment, {
5610
+ children: [
5611
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
5612
+ flex: 1,
5613
+ overflow: "auto",
5614
+ padding: 4,
5615
+ children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
5616
+ gap: 5,
5617
+ children: [ description ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
5618
+ size: 1,
5619
+ children: description
5620
+ }) : null,
5621
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
5622
+ gap: 4,
5623
+ children: [
5624
+ /* @__PURE__ */ jsxRuntime.jsx(OverlineHeading, {
5625
+ children: "Details of this task"
5626
+ }),
5627
+ /* @__PURE__ */ jsxRuntime.jsx(TaskStatusRow, {
5628
+ detail: detail,
5629
+ holding: holding
5630
+ }), children,
5631
+ /* @__PURE__ */ jsxRuntime.jsx(AutomationNarration, {
5632
+ definition: definition,
5633
+ detail: detail
5634
+ }) ]
5635
+ }),
5636
+ /* @__PURE__ */ jsxRuntime.jsx(TaskActions, {
5637
+ ...props
5638
+ }) ]
5639
+ })
5640
+ }), document ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
5641
+ children: [
5642
+ /* @__PURE__ */ jsxRuntime.jsx(Hairline, {
5643
+ weight: 1
5644
+ }),
5645
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
5646
+ padding: 2,
5647
+ children: /* @__PURE__ */ jsxRuntime.jsx(OpenDocumentLink, {
5648
+ gdr: document,
5649
+ source: props.docLinkSource
5650
+ })
5651
+ }) ]
5652
+ }) : null ]
5653
+ });
5654
+ }
5655
+
5656
+ function TaskStatusRow({detail: detail, holding: holding}) {
5657
+ const {status: status} = detail.activityEval;
5658
+ /* @__PURE__ */
5659
+ return jsxRuntime.jsxs(ui.Flex, {
5660
+ align: "center",
5661
+ gap: 3,
5662
+ children: [
5663
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
5664
+ muted: !0,
5665
+ size: 1,
5666
+ children: "Status"
5504
5667
  }),
5668
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
5669
+ align: "center",
5670
+ gap: 2,
5671
+ children: [
5672
+ /* @__PURE__ */ jsxRuntime.jsx(ActivityStatusIcon, {
5673
+ status: status
5674
+ }),
5675
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
5676
+ size: 1,
5677
+ children: taskStatusLine({
5678
+ status: status,
5679
+ holding: holding
5680
+ })
5681
+ }) ]
5682
+ }) ]
5683
+ });
5684
+ }
5685
+
5686
+ function AutomationNarration({definition: definition, detail: detail}) {
5687
+ const {triggeredActions: triggeredActions} = detail.presentation;
5688
+ return triggeredActions.length === 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
5689
+ align: "center",
5690
+ gap: 2,
5691
+ wrap: "wrap",
5692
+ children: triggeredActions.map(a => /* @__PURE__ */ jsxRuntime.jsx(AutomationActionRow, {
5693
+ actionEval: a,
5694
+ definition: definition
5695
+ }, a.action.name))
5696
+ });
5697
+ }
5698
+
5699
+ function TaskActions({activityName: activityName, detail: detail, instanceId: instanceId, surface: surface}) {
5700
+ const {actions: actions, manualTarget: manualTarget, terminalActions: terminalActions} = detail.presentation, lock = useActionClusterState();
5701
+ return actions.length + terminalActions.length === 0 && !manualTarget ? null : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
5702
+ children: [
5703
+ /* @__PURE__ */ jsxRuntime.jsx(Hairline, {
5704
+ weight: 1
5705
+ }),
5706
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
5707
+ gap: 4,
5708
+ children: [
5709
+ /* @__PURE__ */ jsxRuntime.jsx(OverlineHeading, {
5710
+ children: "Your actions"
5711
+ }),
5712
+ /* @__PURE__ */ jsxRuntime.jsx(ActionClusterProvider, {
5713
+ value: lock,
5714
+ children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
5715
+ align: "center",
5716
+ gap: 2,
5717
+ wrap: "wrap",
5718
+ children: [ [ ...actions, ...terminalActions ].map(a => /* @__PURE__ */ jsxRuntime.jsx(ActivityActionRow, {
5719
+ actionEval: a,
5720
+ activity: activityName,
5721
+ instanceId: instanceId,
5722
+ placement: "task-actions",
5723
+ surface: surface
5724
+ }, a.action.name)), manualTarget ? /* @__PURE__ */ jsxRuntime.jsx(ManualTargetButton, {
5725
+ target: manualTarget
5726
+ }) : null ]
5727
+ })
5728
+ }) ]
5729
+ }) ]
5730
+ });
5731
+ }
5732
+
5733
+ function ManualTargetButton({target: target}) {
5734
+ /* @__PURE__ */
5735
+ return jsxRuntime.jsx(ui.Button, {
5736
+ as: "a",
5737
+ fontSize: 1,
5738
+ href: target.href,
5739
+ mode: "ghost",
5740
+ padding: 2,
5741
+ rel: "noreferrer",
5742
+ target: "_blank",
5743
+ text: target.label,
5744
+ tone: "caution"
5745
+ });
5746
+ }
5747
+
5748
+ function DialogBody({children: children, document: document, separated: separated, ...props}) {
5749
+ const {activityName: activityName, detail: detail, instanceId: instanceId, surface: surface} = props;
5750
+ /* @__PURE__ */
5751
+ return jsxRuntime.jsxs(jsxRuntime.Fragment, {
5752
+ children: [
5753
+ /* @__PURE__ */ jsxRuntime.jsx(DialogColumn, {
5754
+ meta: /* @__PURE__ */ jsxRuntime.jsx(MetaBlock, {
5755
+ ...props,
5756
+ document: document
5757
+ }),
5758
+ separated: separated,
5759
+ children: children
5760
+ }), detail.presentation.terminalActions.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(TerminalFooter, {
5761
+ actions: detail.presentation.terminalActions,
5762
+ activity: activityName,
5763
+ instanceId: instanceId,
5764
+ surface: surface
5765
+ }) : null ]
5766
+ });
5767
+ }
5768
+
5769
+ function DialogColumn({children: children, meta: meta, separated: separated}) {
5770
+ /* @__PURE__ */
5771
+ return jsxRuntime.jsxs(jsxRuntime.Fragment, {
5772
+ children: [
5505
5773
  /* @__PURE__ */ jsxRuntime.jsx(ui.Card, {
5506
- borderBottom: hasBody,
5774
+ borderBottom: separated,
5507
5775
  style: {
5508
5776
  position: "sticky",
5509
5777
  top: 0,
5510
5778
  zIndex: 2
5511
5779
  },
5512
- children: /* @__PURE__ */ jsxRuntime.jsx(MetaBlock, {
5513
- activityName: activityName,
5514
- definition: definition,
5515
- detail: detail,
5516
- document: document,
5517
- instanceId: instanceId
5780
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
5781
+ padding: 4,
5782
+ children: meta
5518
5783
  })
5519
- }), hasBody ? /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
5784
+ }), children === null ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
5785
+ flex: 1,
5786
+ overflow: "auto",
5520
5787
  padding: 4,
5521
- children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
5788
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Stack, {
5522
5789
  gap: 5,
5523
- children: [ fault, detail.state.map(field => /* @__PURE__ */ jsxRuntime.jsx(FieldRow, {
5524
- activityName: activityName,
5525
- detail: detail,
5526
- entry: entry,
5527
- field: field,
5528
- instanceId: instanceId
5529
- }, field._key)), notice ]
5790
+ children: children
5530
5791
  })
5531
- }) : null ]
5792
+ }) ]
5532
5793
  });
5533
5794
  }
5534
5795
 
5535
- function MetaBlock({detail: detail, definition: definition, document: document, instanceId: instanceId, activityName: activityName}) {
5536
- const description = detail.activityEval.activity.description, status = detail.activityEval.status;
5796
+ function MetaBlock({document: document, ...props}) {
5797
+ const {detail: detail} = props, description = detail.activityEval.activity.description, status = detail.activityEval.status;
5537
5798
  /* @__PURE__ */
5538
- return jsxRuntime.jsx(ui.Box, {
5539
- padding: 4,
5540
- children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
5541
- gap: 4,
5542
- children: [ description ? /* @__PURE__ */ jsxRuntime.jsx(MetaRow, {
5543
- label: "Description",
5544
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
5799
+ return jsxRuntime.jsxs(ui.Stack, {
5800
+ gap: 4,
5801
+ children: [ description ? /* @__PURE__ */ jsxRuntime.jsx(MetaRow, {
5802
+ label: "Description",
5803
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
5804
+ size: 1,
5805
+ children: description
5806
+ })
5807
+ }) : null,
5808
+ /* @__PURE__ */ jsxRuntime.jsx(MetaRow, {
5809
+ label: "Status",
5810
+ children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
5811
+ align: "center",
5812
+ gap: 2,
5813
+ children: [
5814
+ /* @__PURE__ */ jsxRuntime.jsx(ActivityStatusIcon, {
5815
+ status: status
5816
+ }),
5817
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
5545
5818
  size: 1,
5546
- children: description
5547
- })
5548
- }) : null,
5549
- /* @__PURE__ */ jsxRuntime.jsx(MetaRow, {
5550
- label: "Status",
5551
- children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
5552
- align: "center",
5553
- gap: 2,
5554
- children: [
5555
- /* @__PURE__ */ jsxRuntime.jsx(ActivityStatusIcon, {
5556
- status: status
5557
- }),
5558
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
5559
- size: 1,
5560
- children: ACTIVITY_STATUS_LABEL[status]
5561
- }) ]
5562
- })
5563
- }), document ? /* @__PURE__ */ jsxRuntime.jsx(MetaRow, {
5564
- label: "Studio document",
5565
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
5566
- children: /* @__PURE__ */ jsxRuntime.jsx(DocPreviewLink, {
5567
- gdr: document,
5568
- layout: "inline",
5569
- source: "dialog-subject"
5570
- })
5571
- })
5572
- }) : null,
5573
- /* @__PURE__ */ jsxRuntime.jsx(TopActions, {
5574
- activityName: activityName,
5575
- definition: definition,
5576
- detail: detail,
5577
- instanceId: instanceId
5578
- }) ]
5819
+ children: ACTIVITY_STATUS_LABEL[status]
5820
+ }) ]
5821
+ })
5822
+ }), document ? /* @__PURE__ */ jsxRuntime.jsx(MetaRow, {
5823
+ label: "Studio document",
5824
+ children: /* @__PURE__ */ jsxRuntime.jsx(DocumentMetaValue, {
5825
+ document: document
5826
+ })
5827
+ }) : null,
5828
+ /* @__PURE__ */ jsxRuntime.jsx(TopActions, {
5829
+ ...props
5830
+ }) ]
5831
+ });
5832
+ }
5833
+
5834
+ function DocumentMetaValue({document: document}) {
5835
+ /* @__PURE__ */
5836
+ return jsxRuntime.jsx(ui.Box, {
5837
+ style: useChipTrim(),
5838
+ children: /* @__PURE__ */ jsxRuntime.jsx(DocPreviewLink, {
5839
+ gdr: document,
5840
+ layout: "inline",
5841
+ source: "dialog-subject"
5579
5842
  })
5580
5843
  });
5581
5844
  }
5582
5845
 
5583
- function TopActions({detail: detail, definition: definition, instanceId: instanceId, activityName: activityName}) {
5846
+ function TopActions({activityName: activityName, definition: definition, detail: detail, instanceId: instanceId, surface: surface}) {
5584
5847
  const p = detail.presentation;
5585
5848
  return p.actions.length === 0 && p.triggeredActions.length === 0 && !p.manualTarget ? null : /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
5586
5849
  align: "center",
@@ -5591,17 +5854,9 @@ function TopActions({detail: detail, definition: definition, instanceId: instanc
5591
5854
  activity: activityName,
5592
5855
  instanceId: instanceId,
5593
5856
  placement: "dialog-strip",
5594
- surface: "activity-dialog"
5595
- }, a.action.name)), p.manualTarget ? /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
5596
- as: "a",
5597
- fontSize: 1,
5598
- href: p.manualTarget.href,
5599
- mode: "ghost",
5600
- padding: 2,
5601
- rel: "noreferrer",
5602
- target: "_blank",
5603
- text: p.manualTarget.label,
5604
- tone: "caution"
5857
+ surface: surface
5858
+ }, a.action.name)), p.manualTarget ? /* @__PURE__ */ jsxRuntime.jsx(ManualTargetButton, {
5859
+ target: p.manualTarget
5605
5860
  }) : null, p.triggeredActions.map(a => /* @__PURE__ */ jsxRuntime.jsx(AutomationActionRow, {
5606
5861
  actionEval: a,
5607
5862
  definition: definition
@@ -5609,7 +5864,7 @@ function TopActions({detail: detail, definition: definition, instanceId: instanc
5609
5864
  });
5610
5865
  }
5611
5866
 
5612
- function FieldRow({field: field, detail: detail, entry: entry, activityName: activityName, instanceId: instanceId}) {
5867
+ function FieldRow({field: field, detail: detail, entry: entry, activityName: activityName, instanceId: instanceId, layout: layout, surface: surface, todoSurface: todoSurface}) {
5613
5868
  const head = /* @__PURE__ */ jsxRuntime.jsx(FieldHead, {
5614
5869
  label: field.title ?? field.name,
5615
5870
  ...field.description === void 0 ? {} : {
@@ -5629,10 +5884,10 @@ function FieldRow({field: field, detail: detail, entry: entry, activityName: act
5629
5884
  activity: activityName
5630
5885
  },
5631
5886
  showEmpty: !0,
5632
- surface: "activity-dialog"
5887
+ surface: todoSurface
5633
5888
  }) ]
5634
5889
  });
5635
- if (field._type === "assignees") {
5890
+ if (field._type === "assignee" || field._type === "assignees") {
5636
5891
  const assignField = detail.assignFields.get(field.name);
5637
5892
  /* @__PURE__ */
5638
5893
  return jsxRuntime.jsxs(ui.Stack, {
@@ -5642,8 +5897,9 @@ function FieldRow({field: field, detail: detail, entry: entry, activityName: act
5642
5897
  align: "center",
5643
5898
  gap: 2,
5644
5899
  wrap: "wrap",
5645
- children: [
5646
- /* @__PURE__ */ jsxRuntime.jsx(FieldValue, {
5900
+ children: [ layout === "panel" ? /* @__PURE__ */ jsxRuntime.jsx(RowAssignees, {
5901
+ assignees: field.value
5902
+ }) : /* @__PURE__ */ jsxRuntime.jsx(FieldValue, {
5647
5903
  field: field
5648
5904
  }), assignField ? /* @__PURE__ */ jsxRuntime.jsx(AssignActivityControl, {
5649
5905
  instanceId: instanceId,
@@ -5651,7 +5907,7 @@ function FieldRow({field: field, detail: detail, entry: entry, activityName: act
5651
5907
  kind: "editable",
5652
5908
  field: assignField
5653
5909
  },
5654
- surface: "activity-dialog"
5910
+ surface: surface
5655
5911
  }) : null ]
5656
5912
  }) ]
5657
5913
  });
@@ -5660,28 +5916,95 @@ function FieldRow({field: field, detail: detail, entry: entry, activityName: act
5660
5916
  return editable ? /* @__PURE__ */ jsxRuntime.jsx(EditableFieldControl, {
5661
5917
  field: editable,
5662
5918
  instanceId: instanceId,
5663
- surface: "activity-dialog"
5919
+ surface: surface
5664
5920
  }) : /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
5665
5921
  gap: 2,
5666
5922
  children: [ head,
5667
5923
  /* @__PURE__ */ jsxRuntime.jsx(ReadOnlyField, {
5668
5924
  entry: field
5669
5925
  }) ]
5670
- });
5671
- }
5672
-
5673
- function blockedNotice(detail) {
5674
- const reason = detail.presentation.blockedReason;
5675
- if (reason) /* @__PURE__ */
5676
- return jsxRuntime.jsx(ui.Card, {
5926
+ });
5927
+ }
5928
+
5929
+ function activityNotice(detail) {
5930
+ const reason = detail.presentation.blockedReason, holders = detail.presentation.holderGate;
5931
+ if (!reason && holders === void 0) return;
5932
+ let content2;
5933
+ return holders === void 0 ? content2 = /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
5934
+ size: 1,
5935
+ children: reason === void 0 ? "" : describeDisabledReason(reason)
5936
+ }) : holders.length === 0 ? content2 = /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
5937
+ size: 1,
5938
+ children: "Only a task holder can act, but no holder is selected."
5939
+ }) : content2 = /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
5940
+ align: "center",
5941
+ gap: 2,
5942
+ wrap: "wrap",
5943
+ children: [
5944
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
5945
+ size: 1,
5946
+ children: "Only someone holding this task can act. Assigned to"
5947
+ }),
5948
+ /* @__PURE__ */ jsxRuntime.jsx(RowAssignees, {
5949
+ assignees: holders
5950
+ }) ]
5951
+ }), /* @__PURE__ */ jsxRuntime.jsx(ui.Card, {
5677
5952
  border: !0,
5678
5953
  padding: 3,
5679
5954
  radius: 2,
5680
5955
  tone: "caution",
5681
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
5682
- size: 1,
5683
- children: describeDisabledReason(reason)
5956
+ children: content2
5957
+ });
5958
+ }
5959
+
5960
+ function ActivityDetailDialog({entry: entry, activityName: activityName, breadcrumb: breadcrumb, definition: definition, document: document, source: source, onClose: onClose}) {
5961
+ const detail = deriveActivityDetail({
5962
+ entry: entry,
5963
+ activityName: activityName
5964
+ });
5965
+ return detail ? /* @__PURE__ */ jsxRuntime.jsx(ui.Dialog, {
5966
+ header: /* @__PURE__ */ jsxRuntime.jsx(Breadcrumb, {
5967
+ emphasizeCurrent: !0,
5968
+ segments: [ ...breadcrumb, detail.title ]
5969
+ }),
5970
+ id: "workflow-activity-detail",
5971
+ onClose: onClose,
5972
+ width: 1,
5973
+ children: /* @__PURE__ */ jsxRuntime.jsx(ActivityDetailBody, {
5974
+ activityName: activityName,
5975
+ definition: definition,
5976
+ document: document,
5977
+ entry: entry,
5978
+ layout: "dialog",
5979
+ source: source,
5980
+ surface: "activity-dialog",
5981
+ todoSurface: "activity-dialog"
5684
5982
  })
5983
+ }) : null;
5984
+ }
5985
+
5986
+ const FOR_ME_SECTION_COPY = {
5987
+ assignedTitle: "Tasks assigned to you",
5988
+ roleDescription: "Unassigned tasks, sent to role groups you're part of",
5989
+ roleTitle: "Tasks sent to your roles"
5990
+ };
5991
+
5992
+ function ForMeSectionHeading({description: description, title: title}) {
5993
+ /* @__PURE__ */
5994
+ return jsxRuntime.jsxs(ui.Stack, {
5995
+ gap: 2,
5996
+ paddingLeft: 2,
5997
+ children: [
5998
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
5999
+ as: "h3",
6000
+ size: 2,
6001
+ weight: "semibold",
6002
+ children: title
6003
+ }), typeof description == "string" ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
6004
+ muted: !0,
6005
+ size: 1,
6006
+ children: description
6007
+ }) : description ]
5685
6008
  });
5686
6009
  }
5687
6010
 
@@ -5701,42 +6024,36 @@ function CountedLabel({count: count, label: label}) {
5701
6024
  });
5702
6025
  }
5703
6026
 
5704
- function CountedHeading({count: count, title: title}) {
5705
- /* @__PURE__ */
5706
- return jsxRuntime.jsx(CountedLabel, {
5707
- count: count,
5708
- label: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
5709
- size: 1,
5710
- weight: "semibold",
5711
- children: title
5712
- })
5713
- });
5714
- }
5715
-
5716
- function GroupHeading({busy: busy, count: count, title: title, end: end}) {
6027
+ function GroupHeading({busy: busy, count: count, title: title, action: action}) {
5717
6028
  /* @__PURE__ */
5718
6029
  return jsxRuntime.jsxs(ui.Flex, {
5719
6030
  align: "center",
5720
- gap: 3,
6031
+ gap: 2,
5721
6032
  paddingLeft: 2,
5722
- paddingY: end === void 0 ? 3 : 1,
6033
+ paddingY: action === void 0 ? 3 : 1,
5723
6034
  children: [
5724
- /* @__PURE__ */ jsxRuntime.jsx(CountedHeading, {
6035
+ /* @__PURE__ */ jsxRuntime.jsx(CountedLabel, {
5725
6036
  count: count,
5726
- title: title
5727
- }), busy === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(SpinnerSlot, {
6037
+ label: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
6038
+ size: 2,
6039
+ weight: "medium",
6040
+ children: title
6041
+ })
6042
+ }), action, busy === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(SpinnerSlot, {
5728
6043
  busy: busy
5729
- }), end === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
5730
- children: [
5731
- /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
5732
- flex: 1
5733
- }), end ]
5734
6044
  }) ]
5735
6045
  });
5736
6046
  }
5737
6047
 
5738
6048
  const EMPTY_METRIC_OPACITY = .5;
5739
6049
 
6050
+ function labelledImgProps(label) {
6051
+ return label === void 0 ? {} : {
6052
+ "aria-label": label,
6053
+ role: "img"
6054
+ };
6055
+ }
6056
+
5740
6057
  function MetricText({children: children, tone: tone}) {
5741
6058
  return tone === void 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
5742
6059
  muted: !0,
@@ -5749,33 +6066,41 @@ function MetricText({children: children, tone: tone}) {
5749
6066
  });
5750
6067
  }
5751
6068
 
5752
- function MetricPair({Icon: Icon, empty: empty, face: face, tone: tone, value: value}) {
6069
+ function MetricPair({face: face, ...lockup}) {
5753
6070
  /* @__PURE__ */
5754
6071
  return jsxRuntime.jsx(HoverHint, {
5755
6072
  ...face,
5756
- children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
5757
- align: "center",
5758
- gap: 2,
5759
- style: empty ? {
5760
- opacity: EMPTY_METRIC_OPACITY
5761
- } : void 0,
5762
- children: [
5763
- /* @__PURE__ */ jsxRuntime.jsx(MetricText, {
5764
- tone: tone,
5765
- children: /* @__PURE__ */ jsxRuntime.jsx(Icon, {
5766
- style: {
5767
- color: "inherit"
5768
- }
5769
- })
5770
- }),
5771
- /* @__PURE__ */ jsxRuntime.jsx(MetricText, {
5772
- tone: tone,
5773
- children: value
5774
- }) ]
6073
+ children: /* @__PURE__ */ jsxRuntime.jsx(MetricLockup, {
6074
+ ...lockup
5775
6075
  })
5776
6076
  });
5777
6077
  }
5778
6078
 
6079
+ function MetricLockup({Icon: Icon, empty: empty, label: label, tone: tone, value: value}) {
6080
+ /* @__PURE__ */
6081
+ return jsxRuntime.jsxs(ui.Flex, {
6082
+ align: "center",
6083
+ gap: 2,
6084
+ style: empty ? {
6085
+ opacity: EMPTY_METRIC_OPACITY
6086
+ } : void 0,
6087
+ ...labelledImgProps(label),
6088
+ children: [
6089
+ /* @__PURE__ */ jsxRuntime.jsx(MetricText, {
6090
+ tone: tone,
6091
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icon, {
6092
+ style: {
6093
+ color: "inherit"
6094
+ }
6095
+ })
6096
+ }),
6097
+ /* @__PURE__ */ jsxRuntime.jsx(MetricText, {
6098
+ tone: tone,
6099
+ children: value
6100
+ }) ]
6101
+ });
6102
+ }
6103
+
5779
6104
  function AlertGlyph({Icon: Icon, hint: hint, label: label, tone: tone}) {
5780
6105
  /* @__PURE__ */
5781
6106
  return jsxRuntime.jsx(HoverHint, {
@@ -5784,10 +6109,7 @@ function AlertGlyph({Icon: Icon, hint: hint, label: label, tone: tone}) {
5784
6109
  size: 1,
5785
6110
  tone: tone,
5786
6111
  children: /* @__PURE__ */ jsxRuntime.jsx(Icon, {
5787
- ...label === void 0 ? {} : {
5788
- "aria-label": label,
5789
- role: "img"
5790
- },
6112
+ ...labelledImgProps(label),
5791
6113
  style: {
5792
6114
  color: "inherit"
5793
6115
  }
@@ -5796,6 +6118,37 @@ function AlertGlyph({Icon: Icon, hint: hint, label: label, tone: tone}) {
5796
6118
  });
5797
6119
  }
5798
6120
 
6121
+ function AlertChip({Icon: Icon, hint: hint, label: label, tone: tone}) {
6122
+ const glyph = useTextIconSize(), disc = glyph + useSpaceToken(1) * 2;
6123
+ /* @__PURE__ */
6124
+ return jsxRuntime.jsx(HoverHint, {
6125
+ text: hint,
6126
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Card, {
6127
+ radius: "full",
6128
+ style: {
6129
+ alignItems: "center",
6130
+ display: "flex",
6131
+ height: disc,
6132
+ justifyContent: "center",
6133
+ width: disc
6134
+ },
6135
+ tone: tone,
6136
+ children: /* @__PURE__ */ jsxRuntime.jsx(sanity.TextWithTone, {
6137
+ size: 1,
6138
+ tone: tone,
6139
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icon, {
6140
+ ...labelledImgProps(label),
6141
+ style: {
6142
+ color: "inherit",
6143
+ height: glyph,
6144
+ width: glyph
6145
+ }
6146
+ })
6147
+ })
6148
+ })
6149
+ });
6150
+ }
6151
+
5799
6152
  function ActivityDateControl({instanceId: instanceId, state: state, surface: surface, dueDates: dueDates}) {
5800
6153
  const editField = useEditField(surface), {save: save} = useSaveField({
5801
6154
  instanceId: instanceId
@@ -6146,13 +6499,10 @@ function peopleFaceOf(kind, entry) {
6146
6499
  kind: "assignees",
6147
6500
  assignees: entry?._type === "assignees" ? entry.value : []
6148
6501
  };
6149
- if (kind === "assignee") {
6150
- const value = entry?._type === "assignee" ? entry.value : null;
6151
- return {
6152
- kind: "assignees",
6153
- assignees: value ? [ value ] : []
6154
- };
6155
- }
6502
+ if (kind === "assignee") return {
6503
+ kind: "assignees",
6504
+ assignees: entry?._type === "assignee" ? entry.value : []
6505
+ };
6156
6506
  }
6157
6507
 
6158
6508
  function faceOf(args) {
@@ -6409,7 +6759,7 @@ function AvatarCapAligned({children: children}) {
6409
6759
  }
6410
6760
 
6411
6761
  function AssigneesFace({assignees: assignees}) {
6412
- const vocabulary = useProjectMembers(), userIds = assignees.flatMap(a => a.type === "user" ? [ a.id ] : []), roles = assignees.flatMap(a => a.type === "role" ? [ workflowComponents.roleLabelFor(vocabulary, a.role) ] : []);
6762
+ const vocabulary = useProjectMembers(), userIds = userIdsOf(assignees), roles = assignees.flatMap(a => a.type === "role" ? [ workflowComponents.roleLabelFor(vocabulary, a.role) ] : []);
6413
6763
  /* @__PURE__ */
6414
6764
  return jsxRuntime.jsxs(jsxRuntime.Fragment, {
6415
6765
  children: [ userIds.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(AvatarCapAligned, {
@@ -6710,24 +7060,21 @@ function ActorPill({entry: entry, pill: pill, editability: editability, surface:
6710
7060
  }
6711
7061
 
6712
7062
  function AssigneePill({entry: entry, pill: pill, editability: editability, surface: surface}) {
6713
- const [open, setOpen] = react.useState(!1), {set: set, unset: unset} = useFieldCommit({
7063
+ const [open, setOpen] = react.useState(!1), {set: set, saving: saving, save: save} = usePillWrite({
6714
7064
  entry: entry,
6715
7065
  editability: editability,
6716
7066
  surface: surface
6717
- }), current = pill.entry?._type === "assignee" ? pill.entry.value : null, {pick: pick} = useAssigneePick({
6718
- instanceId: entry.instance._id,
6719
- onSave: set,
6720
- onUnset: unset
6721
- });
7067
+ }), current = pill.entry?._type === "assignee" ? pill.entry.value : [];
6722
7068
  /* @__PURE__ */
6723
7069
  return jsxRuntime.jsx(PillPopover, {
6724
- content: /* @__PURE__ */ jsxRuntime.jsx(SingleAssigneePicker, {
6725
- current: current,
7070
+ content: /* @__PURE__ */ jsxRuntime.jsx(AssigneePicker, {
6726
7071
  eligibleRoles: editability.roles,
6727
- onPick: picked => {
6728
- setOpen(!1), pick(picked);
7072
+ maxUsers: 1,
7073
+ onChange: next => {
7074
+ saving || save(() => set(next));
6729
7075
  },
6730
- roleAliases: editability.roleAliases
7076
+ roleAliases: editability.roleAliases,
7077
+ value: current
6731
7078
  }),
6732
7079
  onDismiss: () => setOpen(!1),
6733
7080
  onToggle: () => setOpen(v => !v),
@@ -7019,100 +7366,6 @@ function conditionLines(description) {
7019
7366
  });
7020
7367
  }
7021
7368
 
7022
- function Hairline({weight: weight, style: style}) {
7023
- const {color: color} = ui.useTheme_v2();
7024
- /* @__PURE__ */
7025
- return jsxRuntime.jsx("div", {
7026
- style: {
7027
- borderTop: `${weight}px solid ${color.border}`,
7028
- ...style
7029
- }
7030
- });
7031
- }
7032
-
7033
- function StageGlyph(props) {
7034
- /* @__PURE__ */
7035
- return jsxRuntime.jsxs("svg", {
7036
- "data-sanity-icon": "stage",
7037
- fill: "none",
7038
- height: "1em",
7039
- viewBox: "0 0 25 25",
7040
- width: "1em",
7041
- xmlns: "http://www.w3.org/2000/svg",
7042
- ...props,
7043
- children: [
7044
- /* @__PURE__ */ jsxRuntime.jsx("path", {
7045
- 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",
7046
- fill: "currentColor"
7047
- }),
7048
- /* @__PURE__ */ jsxRuntime.jsx("path", {
7049
- 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",
7050
- fill: "currentColor"
7051
- }),
7052
- /* @__PURE__ */ jsxRuntime.jsx("path", {
7053
- 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",
7054
- fill: "currentColor"
7055
- }) ]
7056
- });
7057
- }
7058
-
7059
- function StageFace({completed: completed = !1, detail: detail, glyph: glyph = !0, title: title}) {
7060
- const tone = completed ? "default" : "primary";
7061
- /* @__PURE__ */
7062
- return jsxRuntime.jsxs(ui.Flex, {
7063
- align: "center",
7064
- as: "span",
7065
- gap: 2,
7066
- children: [ glyph ? /* @__PURE__ */ jsxRuntime.jsx(sanity.TextWithTone, {
7067
- size: 1,
7068
- tone: tone,
7069
- children: completed ? /* @__PURE__ */ jsxRuntime.jsx(CheckmarkCircleFilledIcon, {
7070
- style: {
7071
- color: "inherit"
7072
- }
7073
- }) : /* @__PURE__ */ jsxRuntime.jsx(StageGlyph, {
7074
- style: {
7075
- color: "inherit"
7076
- }
7077
- })
7078
- }) : null,
7079
- /* @__PURE__ */ jsxRuntime.jsx(sanity.TextWithTone, {
7080
- size: 1,
7081
- tone: tone,
7082
- weight: "medium",
7083
- children: title
7084
- }), detail === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
7085
- muted: !0,
7086
- size: 1,
7087
- children: detail
7088
- }) ]
7089
- });
7090
- }
7091
-
7092
- function StageChip({completed: completed = !1, detail: detail, interactive: interactive = !1, title: title}) {
7093
- const {color: color} = ui.useTheme_v2();
7094
- /* @__PURE__ */
7095
- return jsxRuntime.jsx(ui.Card, {
7096
- padding: 3,
7097
- radius: 4,
7098
- style: {
7099
- boxShadow: `inset 0 0 0 1px ${completed ? color.badge.default.fg : color.focusRing}`,
7100
- cursor: interactive ? "help" : "default"
7101
- },
7102
- tone: completed ? "default" : "primary",
7103
- ...interactive ? {
7104
- tabIndex: 0
7105
- } : {},
7106
- children: /* @__PURE__ */ jsxRuntime.jsx(StageFace, {
7107
- completed: completed,
7108
- title: title,
7109
- ...detail === void 0 ? {} : {
7110
- detail: detail
7111
- }
7112
- })
7113
- });
7114
- }
7115
-
7116
7369
  function StartIncompleteBadge({style: style}) {
7117
7370
  /* @__PURE__ */
7118
7371
  return jsxRuntime.jsx(ui.Badge, {
@@ -7143,7 +7396,7 @@ function abortedToast(title) {
7143
7396
  return {
7144
7397
  id: TOAST_ID.abort,
7145
7398
  status: "info",
7146
- title: `Aborted “${title}”`
7399
+ title: `Canceled “${title}”`
7147
7400
  };
7148
7401
  }
7149
7402
 
@@ -7152,7 +7405,7 @@ function abortAlreadySettledToast(title) {
7152
7405
  id: TOAST_ID.abort,
7153
7406
  status: "info",
7154
7407
  title: `“${title}” had already finished`,
7155
- description: "Nothing was aborted — the workflow reached a terminal state first."
7408
+ description: "Nothing was canceled — the workflow reached a terminal state first."
7156
7409
  };
7157
7410
  }
7158
7411
 
@@ -7160,8 +7413,8 @@ function abortUnconfirmedToast(args) {
7160
7413
  return {
7161
7414
  id: TOAST_ID.abort,
7162
7415
  status: "warning",
7163
- title: `Couldn’t confirm “${args.title}” was aborted`,
7164
- description: `${describeError(args.err)} — the abort may still have committed, so check the workflow’s state before trying again.`
7416
+ title: `Couldn’t confirm “${args.title}” was canceled`,
7417
+ description: `${describeError(args.err)} — the cancellation may still have committed, so check the workflow’s state before trying again.`
7165
7418
  };
7166
7419
  }
7167
7420
 
@@ -7207,7 +7460,7 @@ function AbortWorkflowDialog({entry: entry, onClose: onClose}) {
7207
7460
  mode: "bleed",
7208
7461
  onClick: onClose,
7209
7462
  padding: 2,
7210
- text: "Cancel"
7463
+ text: "Keep workflow"
7211
7464
  }),
7212
7465
  /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
7213
7466
  disabled: reason === void 0,
@@ -7217,12 +7470,12 @@ function AbortWorkflowDialog({entry: entry, onClose: onClose}) {
7217
7470
  confirm();
7218
7471
  },
7219
7472
  padding: 2,
7220
- text: "Abort workflow",
7473
+ text: "Cancel workflow",
7221
7474
  tone: "critical"
7222
7475
  }) ]
7223
7476
  })
7224
7477
  }),
7225
- header: "Abort workflow",
7478
+ header: "Cancel workflow",
7226
7479
  id: `abort-workflow-${instance._id}`,
7227
7480
  onClose: () => {
7228
7481
  pending || onClose();
@@ -7235,7 +7488,7 @@ function AbortWorkflowDialog({entry: entry, onClose: onClose}) {
7235
7488
  children: [
7236
7489
  /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, {
7237
7490
  size: 1,
7238
- children: [ "Abort the ",
7491
+ children: [ "Cancel the ",
7239
7492
  /* @__PURE__ */ jsxRuntime.jsx("strong", {
7240
7493
  children: title
7241
7494
  }), " workflow? This cannot be undone." ]
@@ -7707,7 +7960,7 @@ function InstanceCardMenu({entry: entry, title: title}) {
7707
7960
  /* @__PURE__ */ jsxRuntime.jsx(ui.MenuDivider, {}),
7708
7961
  /* @__PURE__ */ jsxRuntime.jsx(ui.MenuItem, {
7709
7962
  onClick: () => setDialog("abort"),
7710
- text: "Abort workflow…",
7963
+ text: "Cancel workflow…",
7711
7964
  tone: "critical"
7712
7965
  }) ]
7713
7966
  }) : null ]
@@ -7726,90 +7979,97 @@ function InstanceCardMenu({entry: entry, title: title}) {
7726
7979
  });
7727
7980
  }
7728
7981
 
7982
+ const HeaderHoverZone = styledComponents.styled.div`
7983
+ position: relative;
7984
+
7985
+ /* Resting opacity cannot be inline: it outranks this hover rule. */
7986
+ & > [data-header-fill] {
7987
+ opacity: 0;
7988
+ }
7989
+
7990
+ & > button:hover ~ [data-header-fill] {
7991
+ opacity: 1;
7992
+ }
7993
+
7994
+ /* Bleed paints surrounding-card white; :not() leaves Sanity hover/open tones. */
7995
+ & [data-ui='MenuButton'] {
7996
+ cursor: pointer;
7997
+ }
7998
+
7999
+ & [data-ui='MenuButton']:not(:hover):not([aria-expanded='true']) {
8000
+ background-color: transparent;
8001
+ }
8002
+ `;
8003
+
7729
8004
  function InstanceCard({entry: entry, children: children, defaultOpen: defaultOpen}) {
7730
- const definition = useDefinition(entry), {instance: instance} = entry, settled = !isLiveEntry(entry), [open, setOpen] = react.useState(defaultOpen ?? !settled), title = instanceTitle(instance, definition), menuSlot = useSpaceToken(2) * 2 + useTextIconSize();
8005
+ const definition = useDefinition(entry), {instance: instance} = entry, settled = !isLiveEntry(entry), [open, setOpen] = react.useState(defaultOpen ?? !settled), title = instanceTitle(instance, definition);
7731
8006
  /* @__PURE__ */
7732
8007
  return jsxRuntime.jsxs(ui.Card, {
7733
8008
  border: !0,
7734
8009
  overflow: "hidden",
7735
8010
  radius: 4,
7736
8011
  children: [
7737
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Box, {
7738
- style: {
7739
- position: "relative"
7740
- },
8012
+ /* @__PURE__ */ jsxRuntime.jsxs(HeaderHoverZone, {
7741
8013
  children: [
7742
8014
  /* @__PURE__ */ jsxRuntime.jsx(ui.Card, {
7743
8015
  "aria-expanded": open,
8016
+ "aria-label": title,
7744
8017
  as: "button",
7745
8018
  onClick: () => setOpen(value => !value),
7746
- padding: 3,
7747
8019
  style: {
7748
- display: "block",
7749
- textAlign: "left",
8020
+ backgroundColor: "transparent",
8021
+ cursor: "pointer",
8022
+ inset: 0,
8023
+ position: "absolute",
7750
8024
  width: "100%"
8025
+ }
8026
+ }),
8027
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Card, {
8028
+ "data-header-fill": !0,
8029
+ style: {
8030
+ inset: 0,
8031
+ pointerEvents: "none",
8032
+ position: "absolute"
7751
8033
  },
7752
- ...open ? {
7753
- tone: "transparent"
7754
- } : {},
7755
- children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
7756
- align: "center",
7757
- gap: 3,
7758
- children: [
7759
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
7760
- muted: !0,
7761
- size: 1,
7762
- children: open ? /* @__PURE__ */ jsxRuntime.jsx(ChevronDown.ChevronDownIcon, {}) : /* @__PURE__ */ jsxRuntime.jsx(ChevronRight.ChevronRightIcon, {})
7763
- }),
7764
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
7765
- flex: 1,
7766
- gap: 2,
7767
- style: {
7768
- minWidth: 0
7769
- },
7770
- children: [
7771
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
7772
- size: 1,
7773
- textOverflow: "ellipsis",
7774
- weight: "medium",
7775
- children: title
7776
- }),
7777
- /* @__PURE__ */ jsxRuntime.jsx(HeaderStage, {
7778
- entry: entry
7779
- }) ]
7780
- }),
7781
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
7782
- align: "center",
7783
- flex: "none",
7784
- children: [
7785
- /* @__PURE__ */ jsxRuntime.jsx(HeaderBadges, {
7786
- instance: instance,
7787
- settled: settled
7788
- }),
7789
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
7790
- flex: "none",
7791
- style: {
7792
- width: menuSlot
7793
- }
7794
- }) ]
7795
- }) ]
7796
- })
8034
+ tone: "transparent"
7797
8035
  }),
7798
- /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
8036
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
7799
8037
  align: "center",
8038
+ gap: 2,
8039
+ padding: 3,
7800
8040
  style: {
7801
- bottom: 0,
7802
- position: "absolute",
7803
- right: 0,
7804
- top: 0
8041
+ pointerEvents: "none",
8042
+ position: "relative"
7805
8043
  },
7806
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
7807
- paddingRight: 3,
8044
+ children: [
8045
+ /* @__PURE__ */ jsxRuntime.jsx(HeaderTitleLine, {
8046
+ entry: entry
8047
+ }),
8048
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
8049
+ flex: "none",
8050
+ style: {
8051
+ pointerEvents: "auto"
8052
+ },
7808
8053
  children: /* @__PURE__ */ jsxRuntime.jsx(InstanceCardMenu, {
7809
8054
  entry: entry,
7810
8055
  title: title
7811
8056
  })
7812
- })
8057
+ }),
8058
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
8059
+ flex: 1
8060
+ }),
8061
+ /* @__PURE__ */ jsxRuntime.jsx(HeaderBadges, {
8062
+ instance: instance,
8063
+ settled: settled
8064
+ }),
8065
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
8066
+ paddingRight: 1,
8067
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
8068
+ muted: !0,
8069
+ size: 1,
8070
+ children: open ? /* @__PURE__ */ jsxRuntime.jsx(ChevronDown.ChevronDownIcon, {}) : /* @__PURE__ */ jsxRuntime.jsx(ChevronRight.ChevronRightIcon, {})
8071
+ })
8072
+ }) ]
7813
8073
  }) ]
7814
8074
  }), open ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
7815
8075
  children: [
@@ -7824,24 +8084,39 @@ function InstanceCard({entry: entry, children: children, defaultOpen: defaultOpe
7824
8084
  });
7825
8085
  }
7826
8086
 
7827
- function HeaderStage({entry: entry}) {
8087
+ function HeaderTitleLine({entry: entry}) {
7828
8088
  const definition = useDefinition(entry), badgeTrim = useBadgeCapTrim(), face = instanceStageFace({
7829
8089
  definition: definition,
7830
8090
  instance: entry.instance
7831
8091
  });
7832
8092
  /* @__PURE__ */
7833
- return jsxRuntime.jsx(ui.Flex, {
8093
+ return jsxRuntime.jsxs(ui.Flex, {
7834
8094
  align: "center",
7835
- children: face === void 0 ? /* @__PURE__ */ jsxRuntime.jsx(StartIncompleteBadge, {
8095
+ gap: 2,
8096
+ style: {
8097
+ minWidth: 0
8098
+ },
8099
+ children: [
8100
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
8101
+ size: 1,
8102
+ textOverflow: "ellipsis",
8103
+ weight: "medium",
8104
+ children: instanceTitle(entry.instance, definition)
8105
+ }), face === void 0 ? /* @__PURE__ */ jsxRuntime.jsx(StartIncompleteBadge, {
7836
8106
  style: badgeTrim
7837
- }) : /* @__PURE__ */ jsxRuntime.jsx(StageFace, {
7838
- ...face.detail === void 0 ? {} : {
7839
- detail: face.detail
7840
- },
7841
- completed: face.completed,
7842
- glyph: !1,
7843
- title: face.title
7844
- })
8107
+ }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
8108
+ children: [
8109
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
8110
+ muted: !0,
8111
+ size: 1,
8112
+ textOverflow: "ellipsis",
8113
+ children: `/ ${face.title}`
8114
+ }), face.detail === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
8115
+ muted: !0,
8116
+ size: 1,
8117
+ children: face.detail
8118
+ }) ]
8119
+ }) ]
7845
8120
  });
7846
8121
  }
7847
8122
 
@@ -7852,7 +8127,10 @@ function HeaderBadges({instance: instance, settled: settled}) {
7852
8127
  align: "center",
7853
8128
  flex: "none",
7854
8129
  gap: 2,
7855
- style: badgeTrim,
8130
+ style: {
8131
+ ...badgeTrim,
8132
+ pointerEvents: "auto"
8133
+ },
7856
8134
  children: [
7857
8135
  /* @__PURE__ */ jsxRuntime.jsx(AbortedBadge, {
7858
8136
  instance: instance
@@ -7891,6 +8169,90 @@ function PartOfBand({instance: instance}) {
7891
8169
  });
7892
8170
  }
7893
8171
 
8172
+ function StageGlyph(props) {
8173
+ /* @__PURE__ */
8174
+ return jsxRuntime.jsxs("svg", {
8175
+ "data-sanity-icon": "stage",
8176
+ fill: "none",
8177
+ height: "1em",
8178
+ viewBox: "0 0 25 25",
8179
+ width: "1em",
8180
+ xmlns: "http://www.w3.org/2000/svg",
8181
+ ...props,
8182
+ children: [
8183
+ /* @__PURE__ */ jsxRuntime.jsx("path", {
8184
+ 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",
8185
+ fill: "currentColor"
8186
+ }),
8187
+ /* @__PURE__ */ jsxRuntime.jsx("path", {
8188
+ 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",
8189
+ fill: "currentColor"
8190
+ }),
8191
+ /* @__PURE__ */ jsxRuntime.jsx("path", {
8192
+ 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",
8193
+ fill: "currentColor"
8194
+ }) ]
8195
+ });
8196
+ }
8197
+
8198
+ function StageFace({completed: completed = !1, detail: detail, title: title}) {
8199
+ const tone = completed ? "default" : "primary";
8200
+ /* @__PURE__ */
8201
+ return jsxRuntime.jsxs(ui.Flex, {
8202
+ align: "center",
8203
+ as: "span",
8204
+ gap: 2,
8205
+ children: [
8206
+ /* @__PURE__ */ jsxRuntime.jsx(sanity.TextWithTone, {
8207
+ size: 1,
8208
+ tone: tone,
8209
+ children: completed ? /* @__PURE__ */ jsxRuntime.jsx(CheckmarkCircleFilledIcon, {
8210
+ style: {
8211
+ color: "inherit"
8212
+ }
8213
+ }) : /* @__PURE__ */ jsxRuntime.jsx(StageGlyph, {
8214
+ style: {
8215
+ color: "inherit"
8216
+ }
8217
+ })
8218
+ }),
8219
+ /* @__PURE__ */ jsxRuntime.jsx(sanity.TextWithTone, {
8220
+ size: 1,
8221
+ tone: tone,
8222
+ weight: "medium",
8223
+ children: title
8224
+ }), detail === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
8225
+ muted: !0,
8226
+ size: 1,
8227
+ children: detail
8228
+ }) ]
8229
+ });
8230
+ }
8231
+
8232
+ function StageChip({completed: completed = !1, detail: detail, interactive: interactive = !1, title: title}) {
8233
+ const {color: color} = ui.useTheme_v2();
8234
+ /* @__PURE__ */
8235
+ return jsxRuntime.jsx(ui.Card, {
8236
+ padding: 3,
8237
+ radius: 4,
8238
+ style: {
8239
+ boxShadow: `inset 0 0 0 1px ${completed ? color.badge.default.fg : color.focusRing}`,
8240
+ cursor: interactive ? "help" : "default"
8241
+ },
8242
+ tone: completed ? "default" : "primary",
8243
+ ...interactive ? {
8244
+ tabIndex: 0
8245
+ } : {},
8246
+ children: /* @__PURE__ */ jsxRuntime.jsx(StageFace, {
8247
+ completed: completed,
8248
+ title: title,
8249
+ ...detail === void 0 ? {} : {
8250
+ detail: detail
8251
+ }
8252
+ })
8253
+ });
8254
+ }
8255
+
7894
8256
  const NODE_ICON = {
7895
8257
  done: CheckmarkCircle.CheckmarkCircleIcon
7896
8258
  };
@@ -7957,6 +8319,7 @@ function SpineNodeView({definition: definition, node: node, transitions: transit
7957
8319
  "data-testid": `spine-node-${node.name}`,
7958
8320
  flush: !0,
7959
8321
  children: /* @__PURE__ */ jsxRuntime.jsx(InertPill, {
8322
+ filled: node.state === "upcoming" || node.state === "revisit",
7960
8323
  children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
7961
8324
  align: "center",
7962
8325
  gap: 2,
@@ -7974,14 +8337,16 @@ function SpineNodeView({definition: definition, node: node, transitions: transit
7974
8337
  });
7975
8338
  }
7976
8339
 
7977
- function InertPill({children: children}) {
8340
+ function InertPill({children: children, filled: filled = !1}) {
7978
8341
  const {color: color} = ui.useTheme_v2();
7979
8342
  /* @__PURE__ */
7980
8343
  return jsxRuntime.jsx(ui.Card, {
7981
8344
  padding: 3,
7982
8345
  radius: 4,
7983
8346
  style: {
7984
- backgroundColor: "transparent",
8347
+ ...filled ? {} : {
8348
+ backgroundColor: "transparent"
8349
+ },
7985
8350
  boxShadow: `inset 0 0 0 1px ${color.border}`,
7986
8351
  cursor: "help"
7987
8352
  },
@@ -8127,9 +8492,7 @@ function InstanceSnapshotBody({entry: entry, onOpenActivity: onOpenActivity, sur
8127
8492
  /* @__PURE__ */ jsxRuntime.jsx(ui.Card, {
8128
8493
  borderBottom: !0,
8129
8494
  padding: 2,
8130
- ...definition ? {} : {
8131
- tone: "caution"
8132
- },
8495
+ tone: definition ? "transparent" : "caution",
8133
8496
  children: definition ? /* @__PURE__ */ jsxRuntime.jsx(WorkflowSpine, {
8134
8497
  definition: definition,
8135
8498
  evaluation: entry.evaluation,
@@ -8283,21 +8646,6 @@ function InvalidDocNotice({invalid: invalid}) {
8283
8646
  });
8284
8647
  }
8285
8648
 
8286
- function RoleAssignedNotice() {
8287
- /* @__PURE__ */
8288
- return jsxRuntime.jsx(ui.Box, {
8289
- padding: 2,
8290
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
8291
- muted: !0,
8292
- size: 1,
8293
- style: {
8294
- fontStyle: "italic"
8295
- },
8296
- children: "Including tasks assigned to your role"
8297
- })
8298
- });
8299
- }
8300
-
8301
8649
  function TabSwitch({ariaControls: ariaControls, idPrefix: idPrefix, options: options, selected: selected, onSelect: onSelect}) {
8302
8650
  /* @__PURE__ */
8303
8651
  return jsxRuntime.jsx(ui.TabList, {
@@ -9064,7 +9412,7 @@ function StartWorkflowMenuItem({mapping: mapping, docId: docId, initialValue: in
9064
9412
  }) : item;
9065
9413
  }
9066
9414
 
9067
- function ForMeList({entry: entry, work: work, identity: identity, onOpenActivity: onOpenActivity}) {
9415
+ function ForMeList({entry: entry, work: work, identity: identity, assignment: assignment, onOpenActivity: onOpenActivity}) {
9068
9416
  const definition = useDefinition(entry), {instance: instance} = entry, itemCount = work.openItems.length + work.doneItems.length;
9069
9417
  if (!hasAssignedRows(work)) return null;
9070
9418
  const activityState = stateByActivity(instance), breadcrumb = instanceBreadcrumb(instance, definition);
@@ -9088,7 +9436,8 @@ function ForMeList({entry: entry, work: work, identity: identity, onOpenActivity
9088
9436
  entry: entry,
9089
9437
  filter: {
9090
9438
  kind: "mine",
9091
- identity: identity
9439
+ identity: identity,
9440
+ assignment: assignment
9092
9441
  },
9093
9442
  surface: "document-view-for-me"
9094
9443
  }) : null ]
@@ -9203,10 +9552,7 @@ function WorkflowsPanel({entries: entries, documentId: documentId, docTypeMappin
9203
9552
  padding: 3,
9204
9553
  children: [
9205
9554
  /* @__PURE__ */ jsxRuntime.jsx(GroupHeading, {
9206
- busy: booting,
9207
- count: active.length,
9208
- end:
9209
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
9555
+ action: /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
9210
9556
  style: {
9211
9557
  visibility: view === "for-me" ? "hidden" : "visible"
9212
9558
  },
@@ -9220,6 +9566,7 @@ function WorkflowsPanel({entries: entries, documentId: documentId, docTypeMappin
9220
9566
  tone: "default"
9221
9567
  })
9222
9568
  }),
9569
+ busy: booting,
9223
9570
  title: "Active Workflows"
9224
9571
  }),
9225
9572
  /* @__PURE__ */ jsxRuntime.jsx(TabSwitch, {
@@ -9323,21 +9670,50 @@ function OverviewEmptyState({mappings: mappings, docId: docId, initialValue: ini
9323
9670
 
9324
9671
  function ForMeTab({forMe: forMe, assignedWorkUnknown: assignedWorkUnknown, onOpenActivity: onOpenActivity}) {
9325
9672
  return forMe.hasRows ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
9326
- gap: GROUP_GAP,
9673
+ gap: 6,
9327
9674
  paddingBottom: 4,
9328
- children: [ forMe.hasRoleMatched ? /* @__PURE__ */ jsxRuntime.jsx(RoleAssignedNotice, {}) : null, forMe.work.map(({entry: entry, who: who, shown: shown}) => /* @__PURE__ */ jsxRuntime.jsx(ForMeList, {
9329
- entry: entry,
9330
- identity: who,
9331
- work: shown,
9332
- onOpenActivity: activityName => onOpenActivity({
9333
- instanceId: entry.instance._id,
9334
- activityName: activityName,
9335
- stage: entry.instance.currentStage
9336
- })
9337
- }, entry.instance._id)) ]
9675
+ children: [
9676
+ /* @__PURE__ */ jsxRuntime.jsx(DocumentForMeSection, {
9677
+ assignment: "you",
9678
+ onOpenActivity: onOpenActivity,
9679
+ title: FOR_ME_SECTION_COPY.assignedTitle,
9680
+ work: forMe.assignedToUser
9681
+ }),
9682
+ /* @__PURE__ */ jsxRuntime.jsx(DocumentForMeSection, {
9683
+ assignment: "role",
9684
+ description: FOR_ME_SECTION_COPY.roleDescription,
9685
+ onOpenActivity: onOpenActivity,
9686
+ title: FOR_ME_SECTION_COPY.roleTitle,
9687
+ work: forMe.assignedToRoles
9688
+ }) ]
9338
9689
  }) : assignedWorkUnknown ? null : /* @__PURE__ */ jsxRuntime.jsx(ForMeEmptyState, {});
9339
9690
  }
9340
9691
 
9692
+ function DocumentForMeSection({assignment: assignment, description: description, onOpenActivity: onOpenActivity, title: title, work: work}) {
9693
+ return hasForMeRows(work) ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
9694
+ gap: 3,
9695
+ children: [
9696
+ /* @__PURE__ */ jsxRuntime.jsx(ForMeSectionHeading, {
9697
+ description: description,
9698
+ title: title
9699
+ }),
9700
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Stack, {
9701
+ gap: GROUP_GAP,
9702
+ children: work.map(({entry: entry, who: who, shown: shown}) => /* @__PURE__ */ jsxRuntime.jsx(ForMeList, {
9703
+ assignment: assignment,
9704
+ entry: entry,
9705
+ identity: who,
9706
+ work: shown,
9707
+ onOpenActivity: activityName => onOpenActivity({
9708
+ instanceId: entry.instance._id,
9709
+ activityName: activityName,
9710
+ stage: entry.instance.currentStage
9711
+ })
9712
+ }, entry.instance._id))
9713
+ }) ]
9714
+ }) : null;
9715
+ }
9716
+
9341
9717
  function SectionActivityDialog({entry: entry, activityName: activityName, onClose: onClose}) {
9342
9718
  const definition = useDefinition(entry), {instance: instance} = entry;
9343
9719
  /* @__PURE__ */
@@ -9359,6 +9735,44 @@ function workflowDefaultDocumentNode() {
9359
9735
  return S => S.document().views([ S.view.form(), workflowsView(S) ]);
9360
9736
  }
9361
9737
 
9738
+ function publishedMutation(args) {
9739
+ const {draft: draft, published: published, publishedId: publishedId} = args;
9740
+ if (draft !== null) return {
9741
+ before: published === null ? null : {
9742
+ ...published,
9743
+ _id: publishedId
9744
+ },
9745
+ after: {
9746
+ ...draft,
9747
+ _id: publishedId
9748
+ },
9749
+ action: published === null ? "create" : "update"
9750
+ };
9751
+ }
9752
+
9753
+ function deletionMutation(document, id) {
9754
+ if (document !== null) return {
9755
+ before: {
9756
+ ...document,
9757
+ _id: id
9758
+ },
9759
+ after: null,
9760
+ action: "delete"
9761
+ };
9762
+ }
9763
+
9764
+ function lakeMutationForDocumentAction(args) {
9765
+ const {action: action, draft: draft, published: published} = args, publishedId = csm.getPublishedId(args.id);
9766
+ if (action === "publish") return publishedMutation({
9767
+ draft: draft,
9768
+ published: published,
9769
+ publishedId: publishedId
9770
+ });
9771
+ if (action === "unpublish") return deletionMutation(published, publishedId);
9772
+ const current = draft ?? published;
9773
+ return deletionMutation(current, current?._id ?? args.id);
9774
+ }
9775
+
9362
9776
  function lockTitleFor(args) {
9363
9777
  const {denials: denials, entries: entries} = args;
9364
9778
  if (denials.length === 0) return;
@@ -9720,6 +10134,34 @@ function useDefaultLayout(props) {
9720
10134
  return react.useMemo(() => props.renderDefault(props), [ props ]);
9721
10135
  }
9722
10136
 
10137
+ const WARM_DEMAND_MS = 3e4, WARM_DEMAND_LIMIT = 4;
10138
+
10139
+ function useWarmDemand(args) {
10140
+ const {acquire: acquire, release: release} = args, warm = react.useRef(/* @__PURE__ */ new Map), cool = react.useCallback(id => {
10141
+ const expiry = warm.current.get(id);
10142
+ expiry !== void 0 && (clearTimeout(expiry), warm.current.delete(id), release(id));
10143
+ }, [ release ]);
10144
+ react.useEffect(() => () => {
10145
+ for (const expiry of warm.current.values()) clearTimeout(expiry);
10146
+ warm.current.clear();
10147
+ }, []);
10148
+ const acquireWarm = react.useCallback(id => {
10149
+ acquire(id), cool(id);
10150
+ }, [ acquire, cool ]), releaseWarm = react.useCallback(id => {
10151
+ const expiry = warm.current.get(id);
10152
+ for (expiry === void 0 ? acquire(id) : clearTimeout(expiry), release(id), warm.current.delete(id),
10153
+ warm.current.set(id, setTimeout(() => cool(id), WARM_DEMAND_MS)); warm.current.size > WARM_DEMAND_LIMIT; ) {
10154
+ const oldest = warm.current.keys().next().value;
10155
+ if (oldest === void 0) return;
10156
+ cool(oldest);
10157
+ }
10158
+ }, [ acquire, release, cool ]);
10159
+ return {
10160
+ acquire: acquireWarm,
10161
+ release: releaseWarm
10162
+ };
10163
+ }
10164
+
9723
10165
  const notReady = (..._args) => Promise.reject(new Error("workflow session not ready yet")), NO_REGISTERED_DOCUMENTS = [], DEMAND_RELEASE_GRACE_MS = 500;
9724
10166
 
9725
10167
  function workspaceParts(config) {
@@ -9784,17 +10226,6 @@ function DiscoverySubscription(props) {
9784
10226
  }, [ instances, invalid, registered, onSnapshot ]), null;
9785
10227
  }
9786
10228
 
9787
- function engineOptionsFrom(config) {
9788
- return {
9789
- ...config.effectHandlers ? {
9790
- effectHandlers: config.effectHandlers
9791
- } : {},
9792
- ...config.resourceClients ? {
9793
- resourceClients: config.resourceClients
9794
- } : {}
9795
- };
9796
- }
9797
-
9798
10229
  function WorkflowProvider(props) {
9799
10230
  const {config: config} = props, defaultLayout = useDefaultLayout(props), studioClient = sanity.useClient({
9800
10231
  apiVersion: WORKFLOW_API_VERSION
@@ -9808,11 +10239,18 @@ function WorkflowProvider(props) {
9808
10239
  id: `${projectId}.${contentDataset}`
9809
10240
  },
9810
10241
  tag: config.tag
9811
- }), [ projectId, workflowDataset, contentDataset, config.tag ]), engine = workflowStudio.useWorkflowEngine({
10242
+ }), [ projectId, workflowDataset, contentDataset, config.tag ]), effects = react.useMemo(() => ({
10243
+ missingHandler: "skip",
10244
+ ...config.effectHandlers ? {
10245
+ handlers: config.effectHandlers
10246
+ } : {}
10247
+ }), [ config.effectHandlers ]), engine = workflowStudio.useWorkflowEngine({
9812
10248
  workflowResource: binding.engineResource,
9813
10249
  tag: config.tag,
9814
- missingHandler: "skip",
9815
- ...engineOptionsFrom(config)
10250
+ effects: effects,
10251
+ ...config.resourceClients ? {
10252
+ resourceClients: config.resourceClients
10253
+ } : {}
9816
10254
  }), grantsFromPath = workflowEngine.aclPathForResource({
9817
10255
  type: "dataset",
9818
10256
  id: `${projectId}.${workflowDataset}`
@@ -9822,8 +10260,14 @@ function WorkflowProvider(props) {
9822
10260
  registerActive(id), retainRegistration(id);
9823
10261
  }, [ registerActive, retainRegistration ]), unregister = react.useCallback(id => {
9824
10262
  unregisterActive(id), releaseRegistration(id);
9825
- }, [ unregisterActive, releaseRegistration ]), {ids: requested, acquire: requestInstance, release: releaseInstance} = workflowReact.useRefcountedIds(), {ids: evaluationDemand, acquire: requestEvaluation, release: releaseEvaluation} = workflowReact.useRefcountedIds({
10263
+ }, [ unregisterActive, releaseRegistration ]), {ids: requested, acquire: acquireRequested, release: dropRequested} = workflowReact.useRefcountedIds(), {acquire: requestInstance, release: releaseInstance} = useWarmDemand({
10264
+ acquire: acquireRequested,
10265
+ release: dropRequested
10266
+ }), {ids: evaluationDemand, acquire: acquireEvaluation, release: dropEvaluation} = workflowReact.useRefcountedIds({
9826
10267
  releaseDelayMs: DEMAND_RELEASE_GRACE_MS
10268
+ }), {acquire: requestEvaluation, release: releaseEvaluation} = useWarmDemand({
10269
+ acquire: acquireEvaluation,
10270
+ release: dropEvaluation
9827
10271
  }), [seeded, setSeeded] = react.useState(/* @__PURE__ */ new Map), seedInstance = react.useCallback(instance => {
9828
10272
  setSeeded(prev => new Map(prev).set(instance._id, instance));
9829
10273
  }, []), [startRequest2, setStartRequest] = react.useState(void 0), openStartDialog = react.useCallback(r => setStartRequest(r), []), closeStartDialog = react.useCallback(() => setStartRequest(void 0), []), [entriesStore] = react.useState(createEntriesStore);
@@ -9936,7 +10380,7 @@ function WorkflowProvider(props) {
9936
10380
  mappingStarts: starts,
9937
10381
  mappingFields: fields,
9938
10382
  latestDefinitionVersions: latestVersions,
9939
- effectHandlers: engine.effectHandlers,
10383
+ effectHandlers: engine.effects.handlers,
9940
10384
  autoStartByType: autoStartByType,
9941
10385
  autoStartDefinitions: autoStartDefinitions
9942
10386
  }), [ 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 ]);
@@ -10041,7 +10485,43 @@ function logOnce(messages, logged) {
10041
10485
  for (const message of messages) logged.has(message) || (logged.add(message), console.warn(`[workflow-studio-plugin] ${message}`));
10042
10486
  }
10043
10487
 
10044
- function AssigneesInput({value: value, onChange: onChange, eligibleRoles: eligibleRoles, roleAliases: roleAliases}) {
10488
+ function sameGuardIds(previous, next) {
10489
+ return previous.length === next.length && previous.every((guard, index) => guard._id === next[index]?._id);
10490
+ }
10491
+
10492
+ function useActionLockDenials(args) {
10493
+ const [denials, setDenials] = react.useState([]), applyDenials = denied => setDenials(previous => sameGuardIds(previous, denied) ? previous : denied), currentMutation = react.useEffectEvent(() => lakeMutationForDocumentAction({
10494
+ action: args.action,
10495
+ id: args.id,
10496
+ draft: args.draft,
10497
+ published: args.published
10498
+ }));
10499
+ return react.useEffect(() => {
10500
+ if (applyDenials([]), args.guards.length === 0) return;
10501
+ const mutation = currentMutation();
10502
+ if (mutation === void 0) return;
10503
+ let cancelled = !1;
10504
+ return (async () => {
10505
+ const denied = await workflowEngine.documentActionDenials({
10506
+ mutation: mutation,
10507
+ resource: args.resource,
10508
+ guards: args.guards,
10509
+ dereference: args.dereference,
10510
+ ...args.identity !== void 0 ? {
10511
+ identity: args.identity
10512
+ } : {}
10513
+ });
10514
+ cancelled || applyDenials(denied);
10515
+ })().catch(error => {
10516
+ console.error("[workflow-studio-plugin] document-action guard evaluation failed:", error);
10517
+ }), () => {
10518
+ cancelled = !0;
10519
+ };
10520
+ }, [ args.id, args.draft?._id, args.draft?._rev, args.published?._id, args.published?._rev, args.guards, args.action, args.resource, args.identity, args.dereference ]),
10521
+ denials;
10522
+ }
10523
+
10524
+ function AssigneesInput({value: value, onChange: onChange, eligibleRoles: eligibleRoles, roleAliases: roleAliases, maxUsers: maxUsers}) {
10045
10525
  const [open, setOpen] = react.useState(!1), remove = index => onChange(value.filter((_, i) => i !== index));
10046
10526
  /* @__PURE__ */
10047
10527
  return jsxRuntime.jsxs(ui.Stack, {
@@ -10076,6 +10556,7 @@ function AssigneesInput({value: value, onChange: onChange, eligibleRoles: eligib
10076
10556
  children: /* @__PURE__ */ jsxRuntime.jsx(DismissablePopover, {
10077
10557
  content: /* @__PURE__ */ jsxRuntime.jsx(AssigneePicker, {
10078
10558
  eligibleRoles: eligibleRoles,
10559
+ maxUsers: maxUsers,
10079
10560
  onChange: next => onChange([ ...next ]),
10080
10561
  roleAliases: roleAliases,
10081
10562
  value: value
@@ -10442,6 +10923,13 @@ const docRefInput = ({entry: entry, docType: docType, releaseId: releaseId, valu
10442
10923
  roleAliases: roleAliases,
10443
10924
  value: value ?? []
10444
10925
  }),
10926
+ assignee: ({entry: entry, roleAliases: roleAliases, value: value, onChange: onChange}) => /* @__PURE__ */ jsxRuntime.jsx(AssigneesInput, {
10927
+ eligibleRoles: entry.roles,
10928
+ maxUsers: 1,
10929
+ onChange: onChange,
10930
+ roleAliases: roleAliases,
10931
+ value: value ?? []
10932
+ }),
10445
10933
  array: ({entry: entry, value: value, onChange: onChange}) => {
10446
10934
  const editor = arrayEditorKind(entry);
10447
10935
  if (editor === "notes") /* @__PURE__ */ return jsxRuntime.jsx(NotesStartInput, {
@@ -11271,9 +11759,9 @@ function StripLines({active: active, docId: docId, finished: finished, initialVa
11271
11759
 
11272
11760
  function lineHint(entry, identity) {
11273
11761
  const forMe = forMeWorkOf([ entry ], identity);
11274
- return forMe.work.some(({shown: shown}) => hasOpenAssignedWork(shown)) ? {
11762
+ return forMe.assignedToUser.some(({shown: shown}) => hasOpenAssignedWork(shown)) ? {
11275
11763
  content: /* @__PURE__ */ jsxRuntime.jsx(AssignedTasksHint, {
11276
- work: forMe.work
11764
+ work: forMe.assignedToUser
11277
11765
  }),
11278
11766
  wide: !0
11279
11767
  } : unassignedLineHint({
@@ -11484,31 +11972,21 @@ const workflowsTool = {
11484
11972
  }, LOCKABLE_ACTIONS = /* @__PURE__ */ new Map([ [ "delete", "delete" ], [ "publish", "publish" ], [ "unpublish", "unpublish" ] ]);
11485
11973
 
11486
11974
  function useDocumentActionLock(action, props) {
11487
- const {binding: binding} = useWorkflowContext(), identity = sanity.useCurrentUser()?.id, doc = props.draft ?? props.published, {entries: entries} = useWorkflowsForDocument(doc?._id ?? props.id), active = react.useMemo(() => entries.filter(isLiveEntry), [ entries ]), guards = react.useMemo(() => active.flatMap(entry => entry.guards ?? []), [ active ]), [denials, setDenials] = react.useState([]), resource = binding.contentResource, applyDenials = denied => setDenials(prev => prev.length === 0 && denied.length === 0 ? prev : denied);
11488
- return react.useEffect(() => {
11489
- if (!doc || guards.length === 0) {
11490
- applyDenials([]);
11491
- return;
11492
- }
11493
- let cancelled = !1;
11494
- return (async () => {
11495
- const denied = await workflowEngine.documentActionDenials({
11496
- doc: doc,
11497
- resource: resource,
11498
- action: action,
11499
- guards: guards,
11500
- ...identity !== void 0 ? {
11501
- identity: identity
11502
- } : {}
11503
- });
11504
- cancelled || applyDenials(denied);
11505
- })().catch(err => {
11506
- console.error("[workflow-studio-plugin] document-action guard evaluation failed:", err),
11507
- cancelled || applyDenials([]);
11508
- }), () => {
11509
- cancelled = !0;
11510
- };
11511
- }, [ doc?._id, doc?._rev, guards, action, resource, identity ]), lockTitleFor({
11975
+ const {binding: binding} = useWorkflowContext(), client = sanity.useClient({
11976
+ apiVersion: WORKFLOW_API_VERSION
11977
+ }), dereference = react.useMemo(() => workflowEngine.clientGuardDereference(client), [ client ]), identity = sanity.useCurrentUser()?.id, doc = props.draft ?? props.published, {entries: entries} = useWorkflowsForDocument(doc?._id ?? props.id), active = react.useMemo(() => entries.filter(isLiveEntry), [ entries ]), guards = react.useMemo(() => active.flatMap(entry => entry.guards ?? []), [ active ]), resource = binding.contentResource, denials = useActionLockDenials({
11978
+ action: action,
11979
+ id: props.id,
11980
+ draft: props.draft,
11981
+ published: props.published,
11982
+ resource: resource,
11983
+ guards: guards,
11984
+ dereference: dereference,
11985
+ ...identity !== void 0 ? {
11986
+ identity: identity
11987
+ } : {}
11988
+ });
11989
+ return lockTitleFor({
11512
11990
  denials: denials,
11513
11991
  entries: active
11514
11992
  });
@@ -11574,17 +12052,23 @@ function WorkflowRootInput(props) {
11574
12052
 
11575
12053
  exports.AbortWorkflowDialog = AbortWorkflowDialog;
11576
12054
 
12055
+ exports.ActivityDetailBody = ActivityDetailBody;
12056
+
11577
12057
  exports.ActivityDetailDialog = ActivityDetailDialog;
11578
12058
 
11579
12059
  exports.ActivityLog = ActivityLog;
11580
12060
 
11581
12061
  exports.AgoStamp = AgoStamp;
11582
12062
 
12063
+ exports.AlertChip = AlertChip;
12064
+
11583
12065
  exports.AlertGlyph = AlertGlyph;
11584
12066
 
12067
+ exports.Breadcrumb = Breadcrumb;
12068
+
11585
12069
  exports.CodeChip = CodeChip;
11586
12070
 
11587
- exports.CountedHeading = CountedHeading;
12071
+ exports.CountedLabel = CountedLabel;
11588
12072
 
11589
12073
  exports.DismissablePopover = DismissablePopover;
11590
12074
 
@@ -11594,6 +12078,12 @@ exports.DocRefFace = DocRefFace;
11594
12078
 
11595
12079
  exports.EmptyState = EmptyState;
11596
12080
 
12081
+ exports.FOR_ME_SECTION_COPY = FOR_ME_SECTION_COPY;
12082
+
12083
+ exports.ForMeEmptyState = ForMeEmptyState;
12084
+
12085
+ exports.ForMeSectionHeading = ForMeSectionHeading;
12086
+
11597
12087
  exports.HoverHint = HoverHint;
11598
12088
 
11599
12089
  exports.InstanceFaultNote = InstanceFaultNote;
@@ -11608,16 +12098,20 @@ exports.LogEventOnMount = LogEventOnMount;
11608
12098
 
11609
12099
  exports.MetaRow = MetaRow;
11610
12100
 
12101
+ exports.MetricLockup = MetricLockup;
12102
+
11611
12103
  exports.MetricPair = MetricPair;
11612
12104
 
11613
12105
  exports.NoteBanner = NoteBanner;
11614
12106
 
11615
- exports.RUN_SEARCH_PARAM = RUN_SEARCH_PARAM;
12107
+ exports.OverlineHeading = OverlineHeading;
11616
12108
 
11617
- exports.RoleAssignedNotice = RoleAssignedNotice;
12109
+ exports.RUN_SEARCH_PARAM = RUN_SEARCH_PARAM;
11618
12110
 
11619
12111
  exports.RowAssignees = RowAssignees;
11620
12112
 
12113
+ exports.SectionHeading = SectionHeading;
12114
+
11621
12115
  exports.SpinnerSlot = SpinnerSlot;
11622
12116
 
11623
12117
  exports.TOOL_TABS = TOOL_TABS;
@@ -11638,20 +12132,34 @@ exports.WorkflowTitleSeedDrifted = WorkflowTitleSeedDrifted;
11638
12132
 
11639
12133
  exports.WorkflowToolOpened = WorkflowToolOpened;
11640
12134
 
12135
+ exports.activityLabel = activityLabel;
12136
+
11641
12137
  exports.assigneesOf = assigneesOf;
11642
12138
 
12139
+ exports.assignmentHolding = assignmentHolding;
12140
+
11643
12141
  exports.countBy = countBy;
11644
12142
 
11645
12143
  exports.definitionFingerprint = definitionFingerprint;
11646
12144
 
11647
12145
  exports.definitionsRouteOf = definitionsRouteOf;
11648
12146
 
12147
+ exports.deriveActivityDetail = deriveActivityDetail;
12148
+
11649
12149
  exports.describeError = describeError;
11650
12150
 
12151
+ exports.disambiguatedNames = disambiguatedNames;
12152
+
11651
12153
  exports.dueDatesOf = dueDatesOf;
11652
12154
 
12155
+ exports.dueMomentSentence = dueMomentSentence;
12156
+
11653
12157
  exports.findActivity = findActivity;
11654
12158
 
12159
+ exports.formatDate = formatDate;
12160
+
12161
+ exports.formatShortAgo = formatShortAgo;
12162
+
11655
12163
  exports.formatShortDateTime = formatShortDateTime;
11656
12164
 
11657
12165
  exports.formatTimeAgo = formatTimeAgo;
@@ -11668,6 +12176,8 @@ exports.isDueDatePast = isDueDatePast;
11668
12176
 
11669
12177
  exports.isEvaluationStale = isEvaluationStale;
11670
12178
 
12179
+ exports.isHandsOff = isHandsOff;
12180
+
11671
12181
  exports.isLiveEntry = isLiveEntry;
11672
12182
 
11673
12183
  exports.isOpenActivityStatus = isOpenActivityStatus;
@@ -11686,6 +12196,8 @@ exports.parseStoredDateValue = parseStoredDateValue;
11686
12196
 
11687
12197
  exports.readDeployedDefinitions = readDeployedDefinitions;
11688
12198
 
12199
+ exports.shortSpanOf = shortSpanOf;
12200
+
11689
12201
  exports.stageTitle = stageTitle;
11690
12202
 
11691
12203
  exports.tabSelectionNavigates = tabSelectionNavigates;
@@ -11694,6 +12206,8 @@ exports.toolRoute = toolRoute;
11694
12206
 
11695
12207
  exports.toolTabState = toolTabState;
11696
12208
 
12209
+ exports.uniqueIds = uniqueIds;
12210
+
11697
12211
  exports.useAssignmentIdentity = useAssignmentIdentity;
11698
12212
 
11699
12213
  exports.useAvatarSize = useAvatarSize;
@@ -11726,6 +12240,8 @@ exports.useWorkflowContext = useWorkflowContext;
11726
12240
 
11727
12241
  exports.useWorkflowInstanceEntry = useWorkflowInstanceEntry;
11728
12242
 
12243
+ exports.userIdsOf = userIdsOf;
12244
+
11729
12245
  exports.workflowDefaultDocumentNode = workflowDefaultDocumentNode;
11730
12246
 
11731
12247
  exports.workflowState = workflowState;