@sanity/workflow-studio-plugin 0.31.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 : {
@@ -441,6 +441,14 @@ function formatDate(value) {
441
441
  });
442
442
  }
443
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
+
444
452
  function formatBoolean(value) {
445
453
  return value ? "True" : "False";
446
454
  }
@@ -699,19 +707,10 @@ function isOpenActivityStatus(status) {
699
707
  return !workflowEngine.isTerminalActivityStatus(status);
700
708
  }
701
709
 
702
- function assigneeMatches(member, who) {
703
- return member.type === "user" ? member.id === who.userId : who.roles.includes(member.role);
704
- }
705
-
706
710
  function changedAssignee(current, next) {
707
711
  return next.find(item => !current.some(existing => workflowComponents.sameAssignee(item, existing))) ?? current.find(item => !next.some(existing => workflowComponents.sameAssignee(item, existing)));
708
712
  }
709
713
 
710
- function singleAssigneePick(current, next) {
711
- const changed = changedAssignee(current ? [ current ] : [], next);
712
- if (changed !== void 0) return current && workflowComponents.sameAssignee(changed, current) ? null : changed;
713
- }
714
-
715
714
  function isAssigneeShape(value) {
716
715
  if (typeof value != "object" || value === null) return !1;
717
716
  const {type: type, id: id, role: role} = value;
@@ -725,7 +724,7 @@ function isActorShape(value) {
725
724
  }
726
725
 
727
726
  function assigneesOf(entries) {
728
- return entries.flatMap(entry => entry._type === "assignees" ? entry.value : []);
727
+ return [ ...workflowEngine.assignmentMembers(entries) ];
729
728
  }
730
729
 
731
730
  function userIdsOf(assignees) {
@@ -743,43 +742,36 @@ function assigneeEdit(current, next) {
743
742
  };
744
743
  }
745
744
 
746
- function isItemAssignedTo(item, who) {
747
- return item.assignee != null && assigneeMatches(item.assignee, who);
745
+ function assignmentHolding(assignees, who) {
746
+ const match = workflowComponents.assignmentMatch(assignees, who);
747
+ return match === void 0 ? "other" : match === "user" ? "you" : "role";
748
748
  }
749
749
 
750
- function matchingAssignees(state, who) {
751
- 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 ] : []);
750
+ function holdingMatchesAssignment(holding, assignment) {
751
+ return assignment === void 0 ? holding !== "other" : holding === assignment;
752
752
  }
753
753
 
754
- function isActivityAssignedTo(args) {
755
- return matchingAssignees(args.state, args.who).length > 0;
754
+ function activityHolding(args) {
755
+ return assignmentHolding(assigneesOf(args.state), args.who);
756
756
  }
757
757
 
758
- function isRoleAssignedTo(args) {
759
- return matchingAssignees(args.state, args.who).some(member => member.type === "role");
760
- }
761
-
762
- function isItemRoleAssignedTo(item, who) {
763
- return isItemAssignedTo(item, who) && item.assignee?.type === "role";
758
+ function itemHolding(item, who) {
759
+ return assignmentHolding(item.assignee ?? [], who);
764
760
  }
765
761
 
766
762
  function assignedWork(args) {
767
- 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({
768
764
  state: stateOf(t),
769
765
  who: who
770
- })), items = deriveTodoItems({
766
+ }), args.assignment)), items = deriveTodoItems({
771
767
  instance: instance,
772
768
  committed: committed,
773
769
  evaluation: evaluation
774
- }).rows.filter(row => isItemAssignedTo(row.item, who));
770
+ }).rows.filter(row => holdingMatchesAssignment(itemHolding(row.item, who), args.assignment));
775
771
  return {
776
772
  activities: activities,
777
773
  openItems: items.filter(row => !isTodoDone(row.item)),
778
- doneItems: items.filter(row => isTodoDone(row.item)),
779
- roleMatched: activities.some(t => isRoleAssignedTo({
780
- state: stateOf(t),
781
- who: who
782
- })) || items.some(row => isItemRoleAssignedTo(row.item, who))
774
+ doneItems: items.filter(row => isTodoDone(row.item))
783
775
  };
784
776
  }
785
777
 
@@ -804,11 +796,18 @@ function hasOpenAssignedWork(work) {
804
796
  }
805
797
 
806
798
  function assignedTaskCount(args) {
807
- 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));
808
807
  }
809
808
 
810
809
  function forMeWorkOf(entries, identity) {
811
- const work = identity ? entries.map(entry => {
810
+ const section = assignment => identity === void 0 ? [] : entries.map(entry => {
812
811
  const base = {
813
812
  instance: entry.instance,
814
813
  committed: entry.committed,
@@ -818,18 +817,22 @@ function forMeWorkOf(entries, identity) {
818
817
  return {
819
818
  entry: entry,
820
819
  who: identity,
821
- count: assignedTaskCount(base),
820
+ count: openAssignedCount(assignedWork({
821
+ ...base,
822
+ assignment: assignment
823
+ })),
822
824
  shown: assignedWork({
823
825
  ...base,
826
+ assignment: assignment,
824
827
  staleEvaluation: "keep"
825
828
  })
826
829
  };
827
- }) : [];
830
+ }), assignedToUser = section("you"), assignedToRoles = section("role");
828
831
  return {
829
- work: work,
830
- count: work.reduce((n, {count: count}) => n + count, 0),
831
- hasRows: work.some(({shown: shown}) => hasAssignedRows(shown)),
832
- 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 ])
833
836
  };
834
837
  }
835
838
 
@@ -909,8 +912,20 @@ const ACTIVITY_STATUS_LABEL = {
909
912
  done: "Done",
910
913
  failed: "Failed",
911
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
912
922
  };
913
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
+
914
929
  function isHandsOff(args) {
915
930
  return args.classification === "autonomous" && args.completesWithoutCaller === "yes";
916
931
  }
@@ -997,9 +1012,10 @@ function deriveActivityPresentation(args) {
997
1012
  }), blockedReason = status === "active" && actions.length > 0 && actions.every(a => !a.allowed) ? actions.find(a => a.disabledReason)?.disabledReason : void 0, ticks = tickActionNames({
998
1013
  actions: actions,
999
1014
  state: args.state
1000
- }), 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;
1001
1016
  return {
1002
1017
  blockedReason: blockedReason,
1018
+ holderGate: holderGate?.holders,
1003
1019
  settled: settled,
1004
1020
  triggeredActions: settled ? [] : args.activityEval.actions.filter(a => a.triggered === !0),
1005
1021
  manualTarget: kind === "manual" ? manualLink(activity) : void 0,
@@ -1127,7 +1143,7 @@ function deriveActivityDetail(args) {
1127
1143
  title: activityLabel(activityEval.activity),
1128
1144
  state: state,
1129
1145
  editableByName: new Map(activityEditables.map(f => [ f.name, f ])),
1130
- 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 ]))
1131
1147
  };
1132
1148
  }
1133
1149
 
@@ -1171,6 +1187,35 @@ function useWorkflowInstanceEntry(instanceId, options = {}) {
1171
1187
  }, [ instanceId, evaluate, requestEvaluation, releaseEvaluation ]), useHeldWorkflowEntry(instanceId);
1172
1188
  }
1173
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
+
1174
1219
  const WorkflowToolOpened = telemetry.defineEvent({
1175
1220
  name: "Workflows Studio Plugin Tool Opened",
1176
1221
  version: 3,
@@ -1202,7 +1247,7 @@ const WorkflowDefinitionDetailViewed = telemetry.defineEvent({
1202
1247
  description: "The form strip's instance line was clicked, opening the document view"
1203
1248
  }), WorkflowDocumentLinkClicked = telemetry.defineEvent({
1204
1249
  name: "Workflows Studio Plugin Document Link Clicked",
1205
- version: 3,
1250
+ version: 4,
1206
1251
  description: "A document link was clicked, opening the referenced document's editor"
1207
1252
  }), WorkflowStartDialogOpened = telemetry.defineEvent({
1208
1253
  name: "Workflows Studio Plugin Start Dialog Opened",
@@ -1218,15 +1263,15 @@ const WorkflowDefinitionDetailViewed = telemetry.defineEvent({
1218
1263
  description: "A fresh document's auto-start ran — one start request per configured workflow"
1219
1264
  }), WorkflowActionControlUsed = telemetry.defineEvent({
1220
1265
  name: "Workflows Studio Plugin Action Control Used",
1221
- version: 3,
1266
+ version: 4,
1222
1267
  description: "An action-firing control was used, attributed to its UI surface"
1223
1268
  }), WorkflowFieldControlUsed = telemetry.defineEvent({
1224
1269
  name: "Workflows Studio Plugin Field Control Used",
1225
- version: 2,
1270
+ version: 3,
1226
1271
  description: "A field-editing control committed an edit, attributed to its UI surface"
1227
1272
  }), WorkflowActivityDialogOpened = telemetry.defineEvent({
1228
1273
  name: "Workflows Studio Plugin Activity Dialog Opened",
1229
- version: 2,
1274
+ version: 3,
1230
1275
  description: "The activity detail dialog was opened"
1231
1276
  }), WorkflowBoardWorkflowSelected = telemetry.defineEvent({
1232
1277
  name: "Workflows Studio Plugin Board Workflow Selected",
@@ -1238,11 +1283,11 @@ const WorkflowDefinitionDetailViewed = telemetry.defineEvent({
1238
1283
  description: "A cold-start seeded preview title diverged from the live preview pipeline"
1239
1284
  }), WorkflowTodoToggled = telemetry.defineEvent({
1240
1285
  name: "Workflows Studio Plugin Todo Toggled",
1241
- version: 1,
1286
+ version: 2,
1242
1287
  description: "A todo checkbox was toggled, attributed to its UI surface and write seam"
1243
1288
  }), WorkflowTodoEdited = telemetry.defineEvent({
1244
1289
  name: "Workflows Studio Plugin Todo Edited",
1245
- version: 1,
1290
+ version: 2,
1246
1291
  description: "A non-toggle todo-list write, attributed to its UI surface and gesture"
1247
1292
  }), WorkflowAbortDialogOpened = telemetry.defineEvent({
1248
1293
  name: "Workflows Studio Plugin Abort Dialog Opened",
@@ -1265,26 +1310,6 @@ function LogEventOnMount(props) {
1265
1310
  return useLogEventOnMount(props.event, props.data), null;
1266
1311
  }
1267
1312
 
1268
- function isEmptyValue(value) {
1269
- return value == null || value === "" || Array.isArray(value) && value.length === 0;
1270
- }
1271
-
1272
- function effectiveValidation(kind, validation) {
1273
- return kind !== "progress" ? validation : {
1274
- min: validation?.min ?? 0,
1275
- max: validation?.max ?? 100
1276
- };
1277
- }
1278
-
1279
- function scalarValidationIssue(args) {
1280
- const issues = workflowEngine.scalarValidationIssues({
1281
- entryType: args.kind,
1282
- validation: effectiveValidation(args.kind, args.validation),
1283
- value: args.value
1284
- });
1285
- return issues === void 0 ? void 0 : `${args.label}: ${issues.join("; ")}`;
1286
- }
1287
-
1288
1313
  function countBy(rows, keysOf) {
1289
1314
  const counts = /* @__PURE__ */ new Map;
1290
1315
  for (const row of rows) for (const key of keysOf(row)) counts.set(key, (counts.get(key) ?? 0) + 1);
@@ -1402,16 +1427,18 @@ function useSelfActor() {
1402
1427
  }
1403
1428
 
1404
1429
  function useAssignmentIdentity() {
1405
- const state = useSelfState();
1406
- if (state.kind !== "resolved") return state;
1407
- const {id: id, roles: roles} = state.self;
1408
- 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
+ } : {
1409
1436
  kind: "resolved",
1410
1437
  identity: {
1411
1438
  userId: id,
1412
- roles: roles.map(r => r.name)
1439
+ roles: roles.map(role => role.name)
1413
1440
  }
1414
- };
1441
+ }, [ id, roles, state.kind ]);
1415
1442
  }
1416
1443
 
1417
1444
  function identityOf(state) {
@@ -1441,15 +1468,35 @@ function projectMembersFrom(users) {
1441
1468
  }
1442
1469
 
1443
1470
  function useProjectMembers() {
1444
- const {users: users, roles: roles, loading: loading, error: error} = workflowStudio.useStudioProjectUsers();
1445
- return {
1446
- 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,
1447
1474
  roles: roles,
1448
1475
  loading: loading,
1449
- 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
1450
1488
  };
1451
1489
  }
1452
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
+
1453
1500
  const passthrough = raw => ({
1454
1501
  value: raw
1455
1502
  }), paramConverter = {
@@ -1812,31 +1859,19 @@ function MemberPicker({selectedIds: selectedIds, onSelect: onSelect, unassignRow
1812
1859
  });
1813
1860
  }
1814
1861
 
1815
- function AssigneePicker({value: value, onChange: onChange, eligibleRoles: eligibleRoles, roleAliases: roleAliases}) {
1862
+ function AssigneePicker({value: value, onChange: onChange, eligibleRoles: eligibleRoles, roleAliases: roleAliases, maxUsers: maxUsers}) {
1816
1863
  const state = useProjectMembers();
1817
1864
  /* @__PURE__ */
1818
1865
  return jsxRuntime.jsx(workflowComponents.AssigneePicker, {
1819
1866
  ...state,
1820
1867
  eligibleRoles: eligibleRoles,
1868
+ maxUsers: maxUsers,
1821
1869
  onChange: onChange,
1822
1870
  roleAliases: roleAliases,
1823
1871
  value: value
1824
1872
  });
1825
1873
  }
1826
1874
 
1827
- function SingleAssigneePicker({current: current, onPick: onPick, eligibleRoles: eligibleRoles, roleAliases: roleAliases}) {
1828
- /* @__PURE__ */
1829
- return jsxRuntime.jsx(AssigneePicker, {
1830
- eligibleRoles: eligibleRoles,
1831
- onChange: next => {
1832
- const picked = singleAssigneePick(current, next);
1833
- picked !== void 0 && onPick(picked);
1834
- },
1835
- roleAliases: roleAliases,
1836
- value: current ? [ current ] : []
1837
- });
1838
- }
1839
-
1840
1875
  function MemberPickerButton({label: label = "Select member…", onChange: onChange, selectedIds: selectedIds, unassignRow: unassignRow = !1, value: value}) {
1841
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);
1842
1877
  /* @__PURE__ */
@@ -2507,39 +2542,6 @@ function ParamsActionButton({actionEval: actionEval, instanceId: instanceId, act
2507
2542
  });
2508
2543
  }
2509
2544
 
2510
- const DIM = {
2511
- opacity: .6
2512
- };
2513
-
2514
- function Breadcrumb({segments: segments, emphasizeCurrent: emphasizeCurrent = !1}) {
2515
- /* @__PURE__ */
2516
- return jsxRuntime.jsx(jsxRuntime.Fragment, {
2517
- children: segments.map((segment, i) => /* @__PURE__ */ jsxRuntime.jsxs(react.Fragment, {
2518
- children: [ i > 0 ? /* @__PURE__ */ jsxRuntime.jsx(Separator, {}) : null,
2519
- /* @__PURE__ */ jsxRuntime.jsx("span", {
2520
- style: emphasizeCurrent && i < segments.length - 1 ? DIM : void 0,
2521
- children: segment
2522
- }) ]
2523
- }, `${i}-${segment}`))
2524
- });
2525
- }
2526
-
2527
- function Separator() {
2528
- /* @__PURE__ */
2529
- return jsxRuntime.jsx("span", {
2530
- "aria-hidden": !0,
2531
- style: {
2532
- ...DIM,
2533
- alignItems: "center",
2534
- display: "inline-flex",
2535
- height: "0.7em",
2536
- margin: "0 0.5em",
2537
- overflow: "hidden"
2538
- },
2539
- children: /* @__PURE__ */ jsxRuntime.jsx(ChevronRight.ChevronRightIcon, {})
2540
- });
2541
- }
2542
-
2543
2545
  function stageTitle(definition, stageName) {
2544
2546
  return workflowEngine.findStageNode({
2545
2547
  definition: definition,
@@ -2754,10 +2756,81 @@ function docFaceChrome(args) {
2754
2756
  }
2755
2757
  }
2756
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
+
2757
2824
  function chipPadding(fill) {
2758
2825
  return fill ? 3 : 2;
2759
2826
  }
2760
2827
 
2828
+ function useChipTrim() {
2829
+ return {
2830
+ margin: -useSpaceToken(chipPadding(!1))
2831
+ };
2832
+ }
2833
+
2761
2834
  function LinkChip({hint: hint, children: children, as: as = "a", fill: fill = !1, ...anchorProps}) {
2762
2835
  /* @__PURE__ */
2763
2836
  return jsxRuntime.jsx(HoverHint, {
@@ -2956,12 +3029,18 @@ function InlineChipFace({bareId: bareId, schemaType: schemaType}) {
2956
3029
  return jsxRuntime.jsxs(ui.Flex, {
2957
3030
  align: "center",
2958
3031
  gap: 2,
3032
+ style: {
3033
+ minWidth: 0
3034
+ },
2959
3035
  children: [
2960
3036
  /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
2961
3037
  size: 1,
2962
3038
  children: renderTypeIcon(schemaType.icon)
2963
3039
  }), preview.isLoading ? /* @__PURE__ */ jsxRuntime.jsx(TitleSkeleton, {}) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
2964
3040
  size: 1,
3041
+ style: {
3042
+ minWidth: 0
3043
+ },
2965
3044
  textOverflow: "ellipsis",
2966
3045
  weight: "medium",
2967
3046
  children: preview.value?.title ?? /* @__PURE__ */ jsxRuntime.jsx("em", {
@@ -3022,16 +3101,7 @@ function DocRefShell({face: face, layout: layout, source: source}) {
3022
3101
  e.stopPropagation(), telemetry2.log(WorkflowDocumentLinkClicked, {
3023
3102
  source: source
3024
3103
  });
3025
- }, EditIntentLink = react.useMemo(() => bareId === void 0 ? void 0 : function(linkProps) {
3026
- /* @__PURE__ */
3027
- return jsxRuntime.jsx(router.IntentLink, {
3028
- ...linkProps,
3029
- intent: "edit",
3030
- params: {
3031
- id: bareId
3032
- }
3033
- });
3034
- }, [ bareId ]);
3104
+ }, EditIntentLink = useEditIntentLink(bareId);
3035
3105
  if (isCompact(layout)) /* @__PURE__ */
3036
3106
  return jsxRuntime.jsx(CompactDocRef, {
3037
3107
  face: face,
@@ -3194,8 +3264,8 @@ const fieldValueRenderer = {
3194
3264
  array: field => /* @__PURE__ */ jsxRuntime.jsx(ArrayValueRows, {
3195
3265
  rows: field.value
3196
3266
  }),
3197
- assignee: field => field.value ? /* @__PURE__ */ jsxRuntime.jsx(AssigneeBadges, {
3198
- assignees: [ field.value ]
3267
+ assignee: field => field.value.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(AssigneeBadges, {
3268
+ assignees: field.value
3199
3269
  }) : /* @__PURE__ */ jsxRuntime.jsx(Empty, {}),
3200
3270
  assignees: field => field.value.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(AssigneeBadges, {
3201
3271
  assignees: field.value
@@ -3366,8 +3436,8 @@ function ReadOnlyAssigneeValue({value: value}) {
3366
3436
  padding: 2,
3367
3437
  radius: 2,
3368
3438
  tone: "transparent",
3369
- children: value ? /* @__PURE__ */ jsxRuntime.jsx(AssigneeBadges, {
3370
- assignees: [ value ]
3439
+ children: value.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(AssigneeBadges, {
3440
+ assignees: value
3371
3441
  }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
3372
3442
  muted: !0,
3373
3443
  size: 1,
@@ -3406,7 +3476,7 @@ function ReadOnlyValueFace({entry: entry}) {
3406
3476
  });
3407
3477
  }
3408
3478
 
3409
- const VALUE_FACE_KINDS = /* @__PURE__ */ new Set([ "assignees", "object", "array" ]);
3479
+ const VALUE_FACE_KINDS = /* @__PURE__ */ new Set([ "assignee", "assignees", "object", "array" ]);
3410
3480
 
3411
3481
  function ReadOnlyField({entry: entry}) {
3412
3482
  return workflowEngine.isSingleDocRefEntry(entry) ? /* @__PURE__ */ jsxRuntime.jsx(DocPicker, {
@@ -3422,8 +3492,6 @@ function ReadOnlyField({entry: entry}) {
3422
3492
  value: entry.value?.releaseName ?? ""
3423
3493
  }) : entry._type === "actor" ? /* @__PURE__ */ jsxRuntime.jsx(ReadOnlyActorValue, {
3424
3494
  value: entry.value
3425
- }) : entry._type === "assignee" ? /* @__PURE__ */ jsxRuntime.jsx(ReadOnlyAssigneeValue, {
3426
- value: entry.value
3427
3495
  }) : VALUE_FACE_KINDS.has(entry._type) ? /* @__PURE__ */ jsxRuntime.jsx(ReadOnlyValueFace, {
3428
3496
  entry: entry
3429
3497
  }) : /* @__PURE__ */ jsxRuntime.jsx(FieldInput$1, {
@@ -3649,49 +3717,30 @@ function ActorField({field: field, instanceId: instanceId, onSave: onSave, onUns
3649
3717
  });
3650
3718
  }
3651
3719
 
3652
- function useAssigneePick(args) {
3653
- const {onSave: onSave, onUnset: onUnset} = args, {saving: saving, save: save} = useSaveField({
3654
- instanceId: args.instanceId
3655
- });
3656
- return {
3657
- saving: saving,
3658
- pick: picked => {
3659
- if (!saving) {
3660
- if (picked === null) {
3661
- onUnset !== void 0 && save(onUnset);
3662
- return;
3663
- }
3664
- save(() => onSave(picked));
3665
- }
3666
- }
3667
- };
3668
- }
3669
-
3670
- function AssigneeField({field: field, instanceId: instanceId, onSave: onSave, onUnset: onUnset}) {
3671
- const [open, setOpen] = react.useState(!1), cur = isAssigneeShape(field.value) ? field.value : null, {pick: pick} = useAssigneePick({
3672
- instanceId: instanceId,
3673
- onSave: onSave,
3674
- 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
3675
3723
  });
3676
3724
  return field.editable ? /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
3677
3725
  align: "center",
3678
3726
  children: /* @__PURE__ */ jsxRuntime.jsx(DismissablePopover, {
3679
- content: /* @__PURE__ */ jsxRuntime.jsx(SingleAssigneePicker, {
3680
- current: cur,
3727
+ content: /* @__PURE__ */ jsxRuntime.jsx(AssigneePicker, {
3681
3728
  eligibleRoles: field.roles,
3682
- onPick: picked => {
3683
- setOpen(!1), pick(picked);
3729
+ maxUsers: 1,
3730
+ onChange: next => {
3731
+ saving || save(() => onSave(next));
3684
3732
  },
3685
- roleAliases: field.roleAliases
3733
+ roleAliases: field.roleAliases,
3734
+ value: cur
3686
3735
  }),
3687
3736
  onDismiss: () => setOpen(!1),
3688
3737
  open: open,
3689
3738
  children: /* @__PURE__ */ jsxRuntime.jsx(EditableValueButton, {
3690
- hint: cur ? "Reassign" : "Assign",
3739
+ hint: cur.length > 0 ? "Change assignment" : "Assign",
3691
3740
  hintDisabled: open,
3692
3741
  onClick: () => setOpen(v => !v),
3693
- children: cur ? /* @__PURE__ */ jsxRuntime.jsx(AssigneeBadges, {
3694
- assignees: [ cur ]
3742
+ children: cur.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(AssigneeBadges, {
3743
+ assignees: cur
3695
3744
  }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
3696
3745
  muted: !0,
3697
3746
  size: 1,
@@ -3951,8 +4000,7 @@ function fieldArm({arm: arm, entry: entry, onUnset: onUnset, onAppend: onAppend,
3951
4000
  ...arm,
3952
4001
  onUnset: onUnset
3953
4002
  }) : field.type === "assignee" ? /* @__PURE__ */ jsxRuntime.jsx(AssigneeField, {
3954
- ...arm,
3955
- onUnset: onUnset
4003
+ ...arm
3956
4004
  }) : field.type === "assignees" ? /* @__PURE__ */ jsxRuntime.jsx(ValueDisplay, {
3957
4005
  field: field,
3958
4006
  value: field.value
@@ -4013,6 +4061,17 @@ function EditableField({field: field, entry: entry, description: description, in
4013
4061
  });
4014
4062
  }
4015
4063
 
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
+
4016
4075
  function useDrainEffects(instanceId) {
4017
4076
  const {drainEffectsFor: drainEffectsFor} = useWorkflowContext(), toast = useWorkflowToast(), [busy, setBusy] = react.useState(!1);
4018
4077
  return {
@@ -4274,7 +4333,28 @@ function TaskControls({actions: actions, instanceId: instanceId, remedies: remed
4274
4333
  });
4275
4334
  }
4276
4335
 
4277
- function MetaRow({children: children, fillHeight: fillHeight, label: label}) {
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
+
4357
+ function MetaRow({children: children, fillHeight: fillHeight, label: label}) {
4278
4358
  /* @__PURE__ */
4279
4359
  return jsxRuntime.jsxs(ui.Flex, {
4280
4360
  gap: 4,
@@ -4297,11 +4377,88 @@ function MetaRow({children: children, fillHeight: fillHeight, label: label}) {
4297
4377
  }),
4298
4378
  /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
4299
4379
  flex: 1,
4380
+ style: {
4381
+ minWidth: 0
4382
+ },
4300
4383
  children: children
4301
4384
  }) ]
4302
4385
  });
4303
4386
  }
4304
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
+
4305
4462
  function CheckmarkCircleFilledIcon(props) {
4306
4463
  /* @__PURE__ */
4307
4464
  return jsxRuntime.jsx("svg", {
@@ -4355,58 +4512,6 @@ function ActivityStatusIcon({status: status}) {
4355
4512
  });
4356
4513
  }
4357
4514
 
4358
- function useSpaceToken(index) {
4359
- const value = ui.useTheme_v2().space[index];
4360
- if (value === void 0) throw new Error(`theme is missing space token ${index}`);
4361
- return value;
4362
- }
4363
-
4364
- function useRadiusToken(index) {
4365
- const value = ui.useTheme_v2().radius[index];
4366
- if (value === void 0) throw new Error(`theme is missing radius token ${index}`);
4367
- return value;
4368
- }
4369
-
4370
- function useContainerToken(index) {
4371
- const value = ui.useTheme_v2().container[index];
4372
- if (value === void 0) throw new Error(`theme is missing container token ${index}`);
4373
- return value;
4374
- }
4375
-
4376
- function useTextCapHeight() {
4377
- const textSize = ui.useTheme_v2().font.text.sizes[1];
4378
- if (!textSize) throw new Error("useTextCapHeight: theme is missing text size 1");
4379
- return textSize.lineHeight - textSize.ascenderHeight - textSize.descenderHeight;
4380
- }
4381
-
4382
- function useCapTrimFor(size) {
4383
- return (useTextCapHeight() - size) / 2;
4384
- }
4385
-
4386
- function useTextIconSize() {
4387
- const textSize = ui.useTheme_v2().font.text.sizes[1];
4388
- if (!textSize) throw new Error("useTextIconSize: theme is missing text size 1");
4389
- return textSize.iconSize;
4390
- }
4391
-
4392
- function useAvatarSize() {
4393
- const avatarSize = ui.useTheme_v2().avatar.sizes[0];
4394
- if (!avatarSize) throw new Error("useAvatarSize: theme is missing avatar size 0");
4395
- return avatarSize.size;
4396
- }
4397
-
4398
- function useAvatarCapTrim() {
4399
- return useCapTrimFor(useAvatarSize());
4400
- }
4401
-
4402
- function useBadgeCapTrim() {
4403
- const badgePadding = useSpaceToken(1);
4404
- return {
4405
- marginBottom: -badgePadding,
4406
- marginTop: -badgePadding
4407
- };
4408
- }
4409
-
4410
4515
  function SpinnerSlot({busy: busy, reserve: reserve = !0}) {
4411
4516
  const size = useTextIconSize(), trim = useCapTrimFor(size), spinning = useDelayedFlag(busy, LOADING_CUE_DELAY_MS);
4412
4517
  return !spinning && !reserve ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
@@ -4497,55 +4602,8 @@ function AvatarButton({avatar: avatar, onClick: onClick, onMouseDown: onMouseDow
4497
4602
  });
4498
4603
  }
4499
4604
 
4500
- function RowAssignees({assignees: assignees, hint: hint}) {
4501
- const ids = userIdsOf(assignees), vocabulary = useProjectMembers(), roles = assignees.flatMap(item => item.type === "role" ? [ workflowComponents.memberRoleFor(vocabulary, item.role) ] : []), displays = useUserDisplays(ids);
4502
- if (ids.length === 0 && roles.length === 0) return null;
4503
- const bothKinds = roles.length > 0 && displays.length > 0;
4504
- /* @__PURE__ */
4505
- return jsxRuntime.jsx(HoverHint, {
4506
- content: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
4507
- gap: 3,
4508
- children: [ roles.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(HintSection, {
4509
- names: roles.map(workflowComponents.roleLabel),
4510
- ...bothKinds ? {
4511
- label: "Roles"
4512
- } : {}
4513
- }) : null, displays.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(HintSection, {
4514
- names: disambiguatedNames(displays),
4515
- ...bothKinds ? {
4516
- label: "Members"
4517
- } : {}
4518
- }) : null, hint === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
4519
- muted: !0,
4520
- size: 1,
4521
- children: hint
4522
- }) ]
4523
- }),
4524
- children: /* @__PURE__ */ jsxRuntime.jsx(workflowComponents.AssigneeStack, {
4525
- members: displays.map(display => ({
4526
- id: display.id,
4527
- displayName: display.name,
4528
- imageUrl: display.imageUrl
4529
- })),
4530
- roles: roles
4531
- })
4532
- });
4533
- }
4534
-
4535
- function HintSection({label: label, names: names}) {
4536
- /* @__PURE__ */
4537
- return jsxRuntime.jsxs(ui.Stack, {
4538
- gap: 2,
4539
- children: [ label === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
4540
- size: 1,
4541
- weight: "medium",
4542
- children: label
4543
- }),
4544
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
4545
- size: 1,
4546
- children: names.join(", ")
4547
- }) ]
4548
- });
4605
+ function assignActivityIcon(assigneeCount) {
4606
+ return assigneeCount > 0 ? AddUser.AddUserIcon : User.UserIcon;
4549
4607
  }
4550
4608
 
4551
4609
  function AssignActivityControl({instanceId: instanceId, state: state, surface: surface, assignees: assignees = []}) {
@@ -4605,7 +4663,7 @@ function AssignActivityControl({instanceId: instanceId, state: state, surface: s
4605
4663
  "aria-label": "Assign",
4606
4664
  as: "span",
4607
4665
  fontSize: 1,
4608
- icon: User.UserIcon,
4666
+ icon: assignActivityIcon(current.length),
4609
4667
  mode: "bleed",
4610
4668
  onClick: handleClick,
4611
4669
  onMouseDown: stopRowMouseDown,
@@ -4638,7 +4696,7 @@ function rowMatches(row, filter) {
4638
4696
  if (filter === void 0) return !0;
4639
4697
  switch (filter.kind) {
4640
4698
  case "mine":
4641
- return isItemAssignedTo(row.item, filter.identity);
4699
+ return holdingMatchesAssignment(itemHolding(row.item, filter.identity), filter.assignment);
4642
4700
 
4643
4701
  case "activity":
4644
4702
  return row.activityName === filter.activity || row.tick?.activity === filter.activity;
@@ -4838,20 +4896,18 @@ function DueDateControl({item: item, editable: editable, onPatch: onPatch}) {
4838
4896
  }
4839
4897
 
4840
4898
  function AssigneeControl({item: item, editable: editable, eligibleRoles: eligibleRoles, onPatch: onPatch, roleAliases: roleAliases}) {
4841
- const [open, setOpen] = react.useState(!1), current = item.assignee ?? null, chip = current ? /* @__PURE__ */ jsxRuntime.jsx(RowAssignees, {
4842
- assignees: [ current ]
4899
+ const [open, setOpen] = react.useState(!1), current = item.assignee ?? [], chip = current.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(RowAssignees, {
4900
+ assignees: current
4843
4901
  }) : null;
4844
4902
  return editable ? /* @__PURE__ */ jsxRuntime.jsx(DismissablePopover, {
4845
- content:
4846
- /* @__PURE__ */ jsxRuntime.jsx(SingleAssigneePicker, {
4847
- current: current,
4903
+ content: /* @__PURE__ */ jsxRuntime.jsx(AssigneePicker, {
4848
4904
  eligibleRoles: eligibleRoles,
4849
- onPick: picked => {
4850
- setOpen(!1), onPatch({
4851
- assignee: picked
4852
- });
4853
- },
4854
- roleAliases: roleAliases
4905
+ maxUsers: 1,
4906
+ onChange: picked => onPatch({
4907
+ assignee: [ ...picked ]
4908
+ }),
4909
+ roleAliases: roleAliases,
4910
+ value: current
4855
4911
  }),
4856
4912
  onDismiss: () => setOpen(!1),
4857
4913
  open: open,
@@ -5368,7 +5424,7 @@ function ActionsMenuButton({actions: actions, instanceId: instanceId, activity:
5368
5424
 
5369
5425
  const FOOTER_GAP_PX = 8, MORE_ACTIONS_LABEL = "More actions";
5370
5426
 
5371
- function TerminalFooter({actions: actions, activity: activity, instanceId: instanceId}) {
5427
+ function TerminalFooter({actions: actions, activity: activity, instanceId: instanceId, surface: surface}) {
5372
5428
  const lock = useActionClusterState(), [only, ...rest] = actions;
5373
5429
  return only ? /* @__PURE__ */ jsxRuntime.jsx(ActionClusterProvider, {
5374
5430
  value: lock,
@@ -5378,12 +5434,13 @@ function TerminalFooter({actions: actions, activity: activity, instanceId: insta
5378
5434
  activity: activity,
5379
5435
  instanceId: instanceId,
5380
5436
  placement: "terminal-footer",
5381
- surface: "activity-dialog"
5437
+ surface: surface
5382
5438
  })
5383
5439
  }) : /* @__PURE__ */ jsxRuntime.jsx(FittedActions, {
5384
5440
  actions: actions,
5385
5441
  activity: activity,
5386
- instanceId: instanceId
5442
+ instanceId: instanceId,
5443
+ surface: surface
5387
5444
  })
5388
5445
  }) : null;
5389
5446
  }
@@ -5406,7 +5463,7 @@ function FooterRow({children: children, onElement: onElement}) {
5406
5463
  });
5407
5464
  }
5408
5465
 
5409
- function FittedActions({actions: actions, activity: activity, instanceId: instanceId}) {
5466
+ function FittedActions({actions: actions, activity: activity, instanceId: instanceId, surface: surface}) {
5410
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);
5411
5468
  react.useLayoutEffect(() => {
5412
5469
  if (measureEl === null || footerSize === null || measureSize === null) return;
@@ -5434,7 +5491,7 @@ function FittedActions({actions: actions, activity: activity, instanceId: instan
5434
5491
  activity: activity,
5435
5492
  instanceId: instanceId,
5436
5493
  placement: "terminal-footer",
5437
- surface: "activity-dialog"
5494
+ surface: surface
5438
5495
  }, a.action.name)), overflow.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(ActionsMenuButton, {
5439
5496
  actions: overflow,
5440
5497
  activity: activity,
@@ -5442,7 +5499,7 @@ function FittedActions({actions: actions, activity: activity, instanceId: instan
5442
5499
  label: MORE_ACTIONS_LABEL,
5443
5500
  mode: "default",
5444
5501
  placement: "terminal-footer",
5445
- surface: "activity-dialog"
5502
+ surface: surface
5446
5503
  }) : null ]
5447
5504
  }) ]
5448
5505
  });
@@ -5485,33 +5542,43 @@ function MeasureRow({actions: actions, activity: activity, onElement: onElement}
5485
5542
  });
5486
5543
  }
5487
5544
 
5488
- 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}) {
5489
5546
  const detail = deriveActivityDetail({
5490
5547
  entry: entry,
5491
5548
  activityName: activityName
5492
- }), faultingActivity2 = useInstanceFault(entry)?.activity;
5549
+ }), faultingActivity2 = useInstanceFault(entry)?.activity, identity = useAssignmentIdentity();
5493
5550
  if (!detail) return null;
5494
- const instanceId = entry.instance._id, notice = blockedNotice(detail), fault = /* @__PURE__ */ jsxRuntime.jsx(InstanceFaultNote, {
5495
- entry: entry,
5496
- scope: {
5497
- kind: "task",
5498
- activityName: activityName
5499
- }
5500
- }), 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);
5501
5577
  /* @__PURE__ */
5502
- return jsxRuntime.jsxs(ui.Dialog, {
5503
- footer: detail.presentation.terminalActions.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(TerminalFooter, {
5504
- actions: detail.presentation.terminalActions,
5505
- activity: activityName,
5506
- instanceId: instanceId
5507
- }) : void 0,
5508
- header: /* @__PURE__ */ jsxRuntime.jsx(Breadcrumb, {
5509
- emphasizeCurrent: !0,
5510
- segments: [ ...breadcrumb, detail.title ]
5511
- }),
5512
- id: "workflow-activity-detail",
5513
- onClose: onClose,
5514
- width: 1,
5578
+ return jsxRuntime.jsxs(ui.Flex, {
5579
+ direction: "column",
5580
+ flex: 1,
5581
+ overflow: "hidden",
5515
5582
  children: [
5516
5583
  /* @__PURE__ */ jsxRuntime.jsx(LogEventOnMount, {
5517
5584
  data: {
@@ -5519,86 +5586,264 @@ function ActivityDetailDialog({entry: entry, activityName: activityName, breadcr
5519
5586
  source: source
5520
5587
  },
5521
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"
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
5522
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: [
5523
5773
  /* @__PURE__ */ jsxRuntime.jsx(ui.Card, {
5524
- borderBottom: hasBody,
5774
+ borderBottom: separated,
5525
5775
  style: {
5526
5776
  position: "sticky",
5527
5777
  top: 0,
5528
5778
  zIndex: 2
5529
5779
  },
5530
- children: /* @__PURE__ */ jsxRuntime.jsx(MetaBlock, {
5531
- activityName: activityName,
5532
- definition: definition,
5533
- detail: detail,
5534
- document: document,
5535
- instanceId: instanceId
5780
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
5781
+ padding: 4,
5782
+ children: meta
5783
+ })
5784
+ }), children === null ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
5785
+ flex: 1,
5786
+ overflow: "auto",
5787
+ padding: 4,
5788
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Stack, {
5789
+ gap: 5,
5790
+ children: children
5791
+ })
5792
+ }) ]
5793
+ });
5794
+ }
5795
+
5796
+ function MetaBlock({document: document, ...props}) {
5797
+ const {detail: detail} = props, description = detail.activityEval.activity.description, status = detail.activityEval.status;
5798
+ /* @__PURE__ */
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
5536
5806
  })
5537
- }), hasBody ? /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
5538
- padding: 4,
5539
- children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
5540
- gap: 5,
5541
- children: [ fault, detail.state.map(field => /* @__PURE__ */ jsxRuntime.jsx(FieldRow, {
5542
- activityName: activityName,
5543
- detail: detail,
5544
- entry: entry,
5545
- field: field,
5546
- instanceId: instanceId
5547
- }, field._key)), notice ]
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, {
5818
+ size: 1,
5819
+ children: ACTIVITY_STATUS_LABEL[status]
5820
+ }) ]
5548
5821
  })
5549
- }) : null ]
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
+ }) ]
5550
5831
  });
5551
5832
  }
5552
5833
 
5553
- function MetaBlock({detail: detail, definition: definition, document: document, instanceId: instanceId, activityName: activityName}) {
5554
- const description = detail.activityEval.activity.description, status = detail.activityEval.status;
5834
+ function DocumentMetaValue({document: document}) {
5555
5835
  /* @__PURE__ */
5556
5836
  return jsxRuntime.jsx(ui.Box, {
5557
- padding: 4,
5558
- children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
5559
- gap: 4,
5560
- children: [ description ? /* @__PURE__ */ jsxRuntime.jsx(MetaRow, {
5561
- label: "Description",
5562
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
5563
- size: 1,
5564
- children: description
5565
- })
5566
- }) : null,
5567
- /* @__PURE__ */ jsxRuntime.jsx(MetaRow, {
5568
- label: "Status",
5569
- children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
5570
- align: "center",
5571
- gap: 2,
5572
- children: [
5573
- /* @__PURE__ */ jsxRuntime.jsx(ActivityStatusIcon, {
5574
- status: status
5575
- }),
5576
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
5577
- size: 1,
5578
- children: ACTIVITY_STATUS_LABEL[status]
5579
- }) ]
5580
- })
5581
- }), document ? /* @__PURE__ */ jsxRuntime.jsx(MetaRow, {
5582
- label: "Studio document",
5583
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
5584
- children: /* @__PURE__ */ jsxRuntime.jsx(DocPreviewLink, {
5585
- gdr: document,
5586
- layout: "inline",
5587
- source: "dialog-subject"
5588
- })
5589
- })
5590
- }) : null,
5591
- /* @__PURE__ */ jsxRuntime.jsx(TopActions, {
5592
- activityName: activityName,
5593
- definition: definition,
5594
- detail: detail,
5595
- instanceId: instanceId
5596
- }) ]
5837
+ style: useChipTrim(),
5838
+ children: /* @__PURE__ */ jsxRuntime.jsx(DocPreviewLink, {
5839
+ gdr: document,
5840
+ layout: "inline",
5841
+ source: "dialog-subject"
5597
5842
  })
5598
5843
  });
5599
5844
  }
5600
5845
 
5601
- function TopActions({detail: detail, definition: definition, instanceId: instanceId, activityName: activityName}) {
5846
+ function TopActions({activityName: activityName, definition: definition, detail: detail, instanceId: instanceId, surface: surface}) {
5602
5847
  const p = detail.presentation;
5603
5848
  return p.actions.length === 0 && p.triggeredActions.length === 0 && !p.manualTarget ? null : /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
5604
5849
  align: "center",
@@ -5609,17 +5854,9 @@ function TopActions({detail: detail, definition: definition, instanceId: instanc
5609
5854
  activity: activityName,
5610
5855
  instanceId: instanceId,
5611
5856
  placement: "dialog-strip",
5612
- surface: "activity-dialog"
5613
- }, a.action.name)), p.manualTarget ? /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
5614
- as: "a",
5615
- fontSize: 1,
5616
- href: p.manualTarget.href,
5617
- mode: "ghost",
5618
- padding: 2,
5619
- rel: "noreferrer",
5620
- target: "_blank",
5621
- text: p.manualTarget.label,
5622
- tone: "caution"
5857
+ surface: surface
5858
+ }, a.action.name)), p.manualTarget ? /* @__PURE__ */ jsxRuntime.jsx(ManualTargetButton, {
5859
+ target: p.manualTarget
5623
5860
  }) : null, p.triggeredActions.map(a => /* @__PURE__ */ jsxRuntime.jsx(AutomationActionRow, {
5624
5861
  actionEval: a,
5625
5862
  definition: definition
@@ -5627,7 +5864,7 @@ function TopActions({detail: detail, definition: definition, instanceId: instanc
5627
5864
  });
5628
5865
  }
5629
5866
 
5630
- 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}) {
5631
5868
  const head = /* @__PURE__ */ jsxRuntime.jsx(FieldHead, {
5632
5869
  label: field.title ?? field.name,
5633
5870
  ...field.description === void 0 ? {} : {
@@ -5647,10 +5884,10 @@ function FieldRow({field: field, detail: detail, entry: entry, activityName: act
5647
5884
  activity: activityName
5648
5885
  },
5649
5886
  showEmpty: !0,
5650
- surface: "activity-dialog"
5887
+ surface: todoSurface
5651
5888
  }) ]
5652
5889
  });
5653
- if (field._type === "assignees") {
5890
+ if (field._type === "assignee" || field._type === "assignees") {
5654
5891
  const assignField = detail.assignFields.get(field.name);
5655
5892
  /* @__PURE__ */
5656
5893
  return jsxRuntime.jsxs(ui.Stack, {
@@ -5660,8 +5897,9 @@ function FieldRow({field: field, detail: detail, entry: entry, activityName: act
5660
5897
  align: "center",
5661
5898
  gap: 2,
5662
5899
  wrap: "wrap",
5663
- children: [
5664
- /* @__PURE__ */ jsxRuntime.jsx(FieldValue, {
5900
+ children: [ layout === "panel" ? /* @__PURE__ */ jsxRuntime.jsx(RowAssignees, {
5901
+ assignees: field.value
5902
+ }) : /* @__PURE__ */ jsxRuntime.jsx(FieldValue, {
5665
5903
  field: field
5666
5904
  }), assignField ? /* @__PURE__ */ jsxRuntime.jsx(AssignActivityControl, {
5667
5905
  instanceId: instanceId,
@@ -5669,7 +5907,7 @@ function FieldRow({field: field, detail: detail, entry: entry, activityName: act
5669
5907
  kind: "editable",
5670
5908
  field: assignField
5671
5909
  },
5672
- surface: "activity-dialog"
5910
+ surface: surface
5673
5911
  }) : null ]
5674
5912
  }) ]
5675
5913
  });
@@ -5678,7 +5916,7 @@ function FieldRow({field: field, detail: detail, entry: entry, activityName: act
5678
5916
  return editable ? /* @__PURE__ */ jsxRuntime.jsx(EditableFieldControl, {
5679
5917
  field: editable,
5680
5918
  instanceId: instanceId,
5681
- surface: "activity-dialog"
5919
+ surface: surface
5682
5920
  }) : /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
5683
5921
  gap: 2,
5684
5922
  children: [ head,
@@ -5688,18 +5926,85 @@ function FieldRow({field: field, detail: detail, entry: entry, activityName: act
5688
5926
  });
5689
5927
  }
5690
5928
 
5691
- function blockedNotice(detail) {
5692
- const reason = detail.presentation.blockedReason;
5693
- if (reason) /* @__PURE__ */
5694
- return jsxRuntime.jsx(ui.Card, {
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, {
5695
5952
  border: !0,
5696
5953
  padding: 3,
5697
5954
  radius: 2,
5698
5955
  tone: "caution",
5699
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
5700
- size: 1,
5701
- 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"
5702
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 ]
5703
6008
  });
5704
6009
  }
5705
6010
 
@@ -5719,36 +6024,23 @@ function CountedLabel({count: count, label: label}) {
5719
6024
  });
5720
6025
  }
5721
6026
 
5722
- function CountedHeading({count: count, title: title}) {
5723
- /* @__PURE__ */
5724
- return jsxRuntime.jsx(CountedLabel, {
5725
- count: count,
5726
- label: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
5727
- size: 1,
5728
- weight: "semibold",
5729
- children: title
5730
- })
5731
- });
5732
- }
5733
-
5734
- function GroupHeading({busy: busy, count: count, title: title, end: end}) {
6027
+ function GroupHeading({busy: busy, count: count, title: title, action: action}) {
5735
6028
  /* @__PURE__ */
5736
6029
  return jsxRuntime.jsxs(ui.Flex, {
5737
6030
  align: "center",
5738
- gap: 3,
6031
+ gap: 2,
5739
6032
  paddingLeft: 2,
5740
- paddingY: end === void 0 ? 3 : 1,
6033
+ paddingY: action === void 0 ? 3 : 1,
5741
6034
  children: [
5742
- /* @__PURE__ */ jsxRuntime.jsx(CountedHeading, {
6035
+ /* @__PURE__ */ jsxRuntime.jsx(CountedLabel, {
5743
6036
  count: count,
5744
- title: title
5745
- }), 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, {
5746
6043
  busy: busy
5747
- }), end === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
5748
- children: [
5749
- /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
5750
- flex: 1
5751
- }), end ]
5752
6044
  }) ]
5753
6045
  });
5754
6046
  }
@@ -6207,13 +6499,10 @@ function peopleFaceOf(kind, entry) {
6207
6499
  kind: "assignees",
6208
6500
  assignees: entry?._type === "assignees" ? entry.value : []
6209
6501
  };
6210
- if (kind === "assignee") {
6211
- const value = entry?._type === "assignee" ? entry.value : null;
6212
- return {
6213
- kind: "assignees",
6214
- assignees: value ? [ value ] : []
6215
- };
6216
- }
6502
+ if (kind === "assignee") return {
6503
+ kind: "assignees",
6504
+ assignees: entry?._type === "assignee" ? entry.value : []
6505
+ };
6217
6506
  }
6218
6507
 
6219
6508
  function faceOf(args) {
@@ -6771,24 +7060,21 @@ function ActorPill({entry: entry, pill: pill, editability: editability, surface:
6771
7060
  }
6772
7061
 
6773
7062
  function AssigneePill({entry: entry, pill: pill, editability: editability, surface: surface}) {
6774
- 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({
6775
7064
  entry: entry,
6776
7065
  editability: editability,
6777
7066
  surface: surface
6778
- }), current = pill.entry?._type === "assignee" ? pill.entry.value : null, {pick: pick} = useAssigneePick({
6779
- instanceId: entry.instance._id,
6780
- onSave: set,
6781
- onUnset: unset
6782
- });
7067
+ }), current = pill.entry?._type === "assignee" ? pill.entry.value : [];
6783
7068
  /* @__PURE__ */
6784
7069
  return jsxRuntime.jsx(PillPopover, {
6785
- content: /* @__PURE__ */ jsxRuntime.jsx(SingleAssigneePicker, {
6786
- current: current,
7070
+ content: /* @__PURE__ */ jsxRuntime.jsx(AssigneePicker, {
6787
7071
  eligibleRoles: editability.roles,
6788
- onPick: picked => {
6789
- setOpen(!1), pick(picked);
7072
+ maxUsers: 1,
7073
+ onChange: next => {
7074
+ saving || save(() => set(next));
6790
7075
  },
6791
- roleAliases: editability.roleAliases
7076
+ roleAliases: editability.roleAliases,
7077
+ value: current
6792
7078
  }),
6793
7079
  onDismiss: () => setOpen(!1),
6794
7080
  onToggle: () => setOpen(v => !v),
@@ -7080,100 +7366,6 @@ function conditionLines(description) {
7080
7366
  });
7081
7367
  }
7082
7368
 
7083
- function Hairline({weight: weight, style: style}) {
7084
- const {color: color} = ui.useTheme_v2();
7085
- /* @__PURE__ */
7086
- return jsxRuntime.jsx("div", {
7087
- style: {
7088
- borderTop: `${weight}px solid ${color.border}`,
7089
- ...style
7090
- }
7091
- });
7092
- }
7093
-
7094
- function StageGlyph(props) {
7095
- /* @__PURE__ */
7096
- return jsxRuntime.jsxs("svg", {
7097
- "data-sanity-icon": "stage",
7098
- fill: "none",
7099
- height: "1em",
7100
- viewBox: "0 0 25 25",
7101
- width: "1em",
7102
- xmlns: "http://www.w3.org/2000/svg",
7103
- ...props,
7104
- children: [
7105
- /* @__PURE__ */ jsxRuntime.jsx("path", {
7106
- 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",
7107
- fill: "currentColor"
7108
- }),
7109
- /* @__PURE__ */ jsxRuntime.jsx("path", {
7110
- 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",
7111
- fill: "currentColor"
7112
- }),
7113
- /* @__PURE__ */ jsxRuntime.jsx("path", {
7114
- 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",
7115
- fill: "currentColor"
7116
- }) ]
7117
- });
7118
- }
7119
-
7120
- function StageFace({completed: completed = !1, detail: detail, glyph: glyph = !0, title: title}) {
7121
- const tone = completed ? "default" : "primary";
7122
- /* @__PURE__ */
7123
- return jsxRuntime.jsxs(ui.Flex, {
7124
- align: "center",
7125
- as: "span",
7126
- gap: 2,
7127
- children: [ glyph ? /* @__PURE__ */ jsxRuntime.jsx(sanity.TextWithTone, {
7128
- size: 1,
7129
- tone: tone,
7130
- children: completed ? /* @__PURE__ */ jsxRuntime.jsx(CheckmarkCircleFilledIcon, {
7131
- style: {
7132
- color: "inherit"
7133
- }
7134
- }) : /* @__PURE__ */ jsxRuntime.jsx(StageGlyph, {
7135
- style: {
7136
- color: "inherit"
7137
- }
7138
- })
7139
- }) : null,
7140
- /* @__PURE__ */ jsxRuntime.jsx(sanity.TextWithTone, {
7141
- size: 1,
7142
- tone: tone,
7143
- weight: "medium",
7144
- children: title
7145
- }), detail === void 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
7146
- muted: !0,
7147
- size: 1,
7148
- children: detail
7149
- }) ]
7150
- });
7151
- }
7152
-
7153
- function StageChip({completed: completed = !1, detail: detail, interactive: interactive = !1, title: title}) {
7154
- const {color: color} = ui.useTheme_v2();
7155
- /* @__PURE__ */
7156
- return jsxRuntime.jsx(ui.Card, {
7157
- padding: 3,
7158
- radius: 4,
7159
- style: {
7160
- boxShadow: `inset 0 0 0 1px ${completed ? color.badge.default.fg : color.focusRing}`,
7161
- cursor: interactive ? "help" : "default"
7162
- },
7163
- tone: completed ? "default" : "primary",
7164
- ...interactive ? {
7165
- tabIndex: 0
7166
- } : {},
7167
- children: /* @__PURE__ */ jsxRuntime.jsx(StageFace, {
7168
- completed: completed,
7169
- title: title,
7170
- ...detail === void 0 ? {} : {
7171
- detail: detail
7172
- }
7173
- })
7174
- });
7175
- }
7176
-
7177
7369
  function StartIncompleteBadge({style: style}) {
7178
7370
  /* @__PURE__ */
7179
7371
  return jsxRuntime.jsx(ui.Badge, {
@@ -7204,7 +7396,7 @@ function abortedToast(title) {
7204
7396
  return {
7205
7397
  id: TOAST_ID.abort,
7206
7398
  status: "info",
7207
- title: `Aborted “${title}”`
7399
+ title: `Canceled “${title}”`
7208
7400
  };
7209
7401
  }
7210
7402
 
@@ -7213,7 +7405,7 @@ function abortAlreadySettledToast(title) {
7213
7405
  id: TOAST_ID.abort,
7214
7406
  status: "info",
7215
7407
  title: `“${title}” had already finished`,
7216
- description: "Nothing was aborted — the workflow reached a terminal state first."
7408
+ description: "Nothing was canceled — the workflow reached a terminal state first."
7217
7409
  };
7218
7410
  }
7219
7411
 
@@ -7221,8 +7413,8 @@ function abortUnconfirmedToast(args) {
7221
7413
  return {
7222
7414
  id: TOAST_ID.abort,
7223
7415
  status: "warning",
7224
- title: `Couldn’t confirm “${args.title}” was aborted`,
7225
- 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.`
7226
7418
  };
7227
7419
  }
7228
7420
 
@@ -7268,7 +7460,7 @@ function AbortWorkflowDialog({entry: entry, onClose: onClose}) {
7268
7460
  mode: "bleed",
7269
7461
  onClick: onClose,
7270
7462
  padding: 2,
7271
- text: "Cancel"
7463
+ text: "Keep workflow"
7272
7464
  }),
7273
7465
  /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
7274
7466
  disabled: reason === void 0,
@@ -7278,12 +7470,12 @@ function AbortWorkflowDialog({entry: entry, onClose: onClose}) {
7278
7470
  confirm();
7279
7471
  },
7280
7472
  padding: 2,
7281
- text: "Abort workflow",
7473
+ text: "Cancel workflow",
7282
7474
  tone: "critical"
7283
7475
  }) ]
7284
7476
  })
7285
7477
  }),
7286
- header: "Abort workflow",
7478
+ header: "Cancel workflow",
7287
7479
  id: `abort-workflow-${instance._id}`,
7288
7480
  onClose: () => {
7289
7481
  pending || onClose();
@@ -7296,7 +7488,7 @@ function AbortWorkflowDialog({entry: entry, onClose: onClose}) {
7296
7488
  children: [
7297
7489
  /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, {
7298
7490
  size: 1,
7299
- children: [ "Abort the ",
7491
+ children: [ "Cancel the ",
7300
7492
  /* @__PURE__ */ jsxRuntime.jsx("strong", {
7301
7493
  children: title
7302
7494
  }), " workflow? This cannot be undone." ]
@@ -7768,7 +7960,7 @@ function InstanceCardMenu({entry: entry, title: title}) {
7768
7960
  /* @__PURE__ */ jsxRuntime.jsx(ui.MenuDivider, {}),
7769
7961
  /* @__PURE__ */ jsxRuntime.jsx(ui.MenuItem, {
7770
7962
  onClick: () => setDialog("abort"),
7771
- text: "Abort workflow…",
7963
+ text: "Cancel workflow…",
7772
7964
  tone: "critical"
7773
7965
  }) ]
7774
7966
  }) : null ]
@@ -7787,90 +7979,97 @@ function InstanceCardMenu({entry: entry, title: title}) {
7787
7979
  });
7788
7980
  }
7789
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
+
7790
8004
  function InstanceCard({entry: entry, children: children, defaultOpen: defaultOpen}) {
7791
- 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);
7792
8006
  /* @__PURE__ */
7793
8007
  return jsxRuntime.jsxs(ui.Card, {
7794
8008
  border: !0,
7795
8009
  overflow: "hidden",
7796
8010
  radius: 4,
7797
8011
  children: [
7798
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Box, {
7799
- style: {
7800
- position: "relative"
7801
- },
8012
+ /* @__PURE__ */ jsxRuntime.jsxs(HeaderHoverZone, {
7802
8013
  children: [
7803
8014
  /* @__PURE__ */ jsxRuntime.jsx(ui.Card, {
7804
8015
  "aria-expanded": open,
8016
+ "aria-label": title,
7805
8017
  as: "button",
7806
8018
  onClick: () => setOpen(value => !value),
7807
- padding: 3,
7808
8019
  style: {
7809
- display: "block",
7810
- textAlign: "left",
8020
+ backgroundColor: "transparent",
8021
+ cursor: "pointer",
8022
+ inset: 0,
8023
+ position: "absolute",
7811
8024
  width: "100%"
7812
- },
7813
- ...open ? {
7814
- tone: "transparent"
7815
- } : {},
7816
- children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
7817
- align: "center",
7818
- gap: 3,
7819
- children: [
7820
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
7821
- muted: !0,
7822
- size: 1,
7823
- children: open ? /* @__PURE__ */ jsxRuntime.jsx(ChevronDown.ChevronDownIcon, {}) : /* @__PURE__ */ jsxRuntime.jsx(ChevronRight.ChevronRightIcon, {})
7824
- }),
7825
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
7826
- flex: 1,
7827
- gap: 2,
7828
- style: {
7829
- minWidth: 0
7830
- },
7831
- children: [
7832
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
7833
- size: 1,
7834
- textOverflow: "ellipsis",
7835
- weight: "medium",
7836
- children: title
7837
- }),
7838
- /* @__PURE__ */ jsxRuntime.jsx(HeaderStage, {
7839
- entry: entry
7840
- }) ]
7841
- }),
7842
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
7843
- align: "center",
7844
- flex: "none",
7845
- children: [
7846
- /* @__PURE__ */ jsxRuntime.jsx(HeaderBadges, {
7847
- instance: instance,
7848
- settled: settled
7849
- }),
7850
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
7851
- flex: "none",
7852
- style: {
7853
- width: menuSlot
7854
- }
7855
- }) ]
7856
- }) ]
7857
- })
8025
+ }
8026
+ }),
8027
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Card, {
8028
+ "data-header-fill": !0,
8029
+ style: {
8030
+ inset: 0,
8031
+ pointerEvents: "none",
8032
+ position: "absolute"
8033
+ },
8034
+ tone: "transparent"
7858
8035
  }),
7859
- /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
8036
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
7860
8037
  align: "center",
8038
+ gap: 2,
8039
+ padding: 3,
7861
8040
  style: {
7862
- bottom: 0,
7863
- position: "absolute",
7864
- right: 0,
7865
- top: 0
8041
+ pointerEvents: "none",
8042
+ position: "relative"
7866
8043
  },
7867
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
7868
- 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
+ },
7869
8053
  children: /* @__PURE__ */ jsxRuntime.jsx(InstanceCardMenu, {
7870
8054
  entry: entry,
7871
8055
  title: title
7872
8056
  })
7873
- })
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
+ }) ]
7874
8073
  }) ]
7875
8074
  }), open ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
7876
8075
  children: [
@@ -7885,24 +8084,39 @@ function InstanceCard({entry: entry, children: children, defaultOpen: defaultOpe
7885
8084
  });
7886
8085
  }
7887
8086
 
7888
- function HeaderStage({entry: entry}) {
8087
+ function HeaderTitleLine({entry: entry}) {
7889
8088
  const definition = useDefinition(entry), badgeTrim = useBadgeCapTrim(), face = instanceStageFace({
7890
8089
  definition: definition,
7891
8090
  instance: entry.instance
7892
8091
  });
7893
8092
  /* @__PURE__ */
7894
- return jsxRuntime.jsx(ui.Flex, {
8093
+ return jsxRuntime.jsxs(ui.Flex, {
7895
8094
  align: "center",
7896
- 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, {
7897
8106
  style: badgeTrim
7898
- }) : /* @__PURE__ */ jsxRuntime.jsx(StageFace, {
7899
- ...face.detail === void 0 ? {} : {
7900
- detail: face.detail
7901
- },
7902
- completed: face.completed,
7903
- glyph: !1,
7904
- title: face.title
7905
- })
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
+ }) ]
7906
8120
  });
7907
8121
  }
7908
8122
 
@@ -7913,7 +8127,10 @@ function HeaderBadges({instance: instance, settled: settled}) {
7913
8127
  align: "center",
7914
8128
  flex: "none",
7915
8129
  gap: 2,
7916
- style: badgeTrim,
8130
+ style: {
8131
+ ...badgeTrim,
8132
+ pointerEvents: "auto"
8133
+ },
7917
8134
  children: [
7918
8135
  /* @__PURE__ */ jsxRuntime.jsx(AbortedBadge, {
7919
8136
  instance: instance
@@ -7952,6 +8169,90 @@ function PartOfBand({instance: instance}) {
7952
8169
  });
7953
8170
  }
7954
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
+
7955
8256
  const NODE_ICON = {
7956
8257
  done: CheckmarkCircle.CheckmarkCircleIcon
7957
8258
  };
@@ -8018,6 +8319,7 @@ function SpineNodeView({definition: definition, node: node, transitions: transit
8018
8319
  "data-testid": `spine-node-${node.name}`,
8019
8320
  flush: !0,
8020
8321
  children: /* @__PURE__ */ jsxRuntime.jsx(InertPill, {
8322
+ filled: node.state === "upcoming" || node.state === "revisit",
8021
8323
  children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
8022
8324
  align: "center",
8023
8325
  gap: 2,
@@ -8035,14 +8337,16 @@ function SpineNodeView({definition: definition, node: node, transitions: transit
8035
8337
  });
8036
8338
  }
8037
8339
 
8038
- function InertPill({children: children}) {
8340
+ function InertPill({children: children, filled: filled = !1}) {
8039
8341
  const {color: color} = ui.useTheme_v2();
8040
8342
  /* @__PURE__ */
8041
8343
  return jsxRuntime.jsx(ui.Card, {
8042
8344
  padding: 3,
8043
8345
  radius: 4,
8044
8346
  style: {
8045
- backgroundColor: "transparent",
8347
+ ...filled ? {} : {
8348
+ backgroundColor: "transparent"
8349
+ },
8046
8350
  boxShadow: `inset 0 0 0 1px ${color.border}`,
8047
8351
  cursor: "help"
8048
8352
  },
@@ -8188,9 +8492,7 @@ function InstanceSnapshotBody({entry: entry, onOpenActivity: onOpenActivity, sur
8188
8492
  /* @__PURE__ */ jsxRuntime.jsx(ui.Card, {
8189
8493
  borderBottom: !0,
8190
8494
  padding: 2,
8191
- ...definition ? {} : {
8192
- tone: "caution"
8193
- },
8495
+ tone: definition ? "transparent" : "caution",
8194
8496
  children: definition ? /* @__PURE__ */ jsxRuntime.jsx(WorkflowSpine, {
8195
8497
  definition: definition,
8196
8498
  evaluation: entry.evaluation,
@@ -8344,21 +8646,6 @@ function InvalidDocNotice({invalid: invalid}) {
8344
8646
  });
8345
8647
  }
8346
8648
 
8347
- function RoleAssignedNotice() {
8348
- /* @__PURE__ */
8349
- return jsxRuntime.jsx(ui.Box, {
8350
- padding: 2,
8351
- children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
8352
- muted: !0,
8353
- size: 1,
8354
- style: {
8355
- fontStyle: "italic"
8356
- },
8357
- children: "Including tasks assigned to your role"
8358
- })
8359
- });
8360
- }
8361
-
8362
8649
  function TabSwitch({ariaControls: ariaControls, idPrefix: idPrefix, options: options, selected: selected, onSelect: onSelect}) {
8363
8650
  /* @__PURE__ */
8364
8651
  return jsxRuntime.jsx(ui.TabList, {
@@ -9125,7 +9412,7 @@ function StartWorkflowMenuItem({mapping: mapping, docId: docId, initialValue: in
9125
9412
  }) : item;
9126
9413
  }
9127
9414
 
9128
- function ForMeList({entry: entry, work: work, identity: identity, onOpenActivity: onOpenActivity}) {
9415
+ function ForMeList({entry: entry, work: work, identity: identity, assignment: assignment, onOpenActivity: onOpenActivity}) {
9129
9416
  const definition = useDefinition(entry), {instance: instance} = entry, itemCount = work.openItems.length + work.doneItems.length;
9130
9417
  if (!hasAssignedRows(work)) return null;
9131
9418
  const activityState = stateByActivity(instance), breadcrumb = instanceBreadcrumb(instance, definition);
@@ -9149,7 +9436,8 @@ function ForMeList({entry: entry, work: work, identity: identity, onOpenActivity
9149
9436
  entry: entry,
9150
9437
  filter: {
9151
9438
  kind: "mine",
9152
- identity: identity
9439
+ identity: identity,
9440
+ assignment: assignment
9153
9441
  },
9154
9442
  surface: "document-view-for-me"
9155
9443
  }) : null ]
@@ -9264,10 +9552,7 @@ function WorkflowsPanel({entries: entries, documentId: documentId, docTypeMappin
9264
9552
  padding: 3,
9265
9553
  children: [
9266
9554
  /* @__PURE__ */ jsxRuntime.jsx(GroupHeading, {
9267
- busy: booting,
9268
- count: active.length,
9269
- end:
9270
- /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
9555
+ action: /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, {
9271
9556
  style: {
9272
9557
  visibility: view === "for-me" ? "hidden" : "visible"
9273
9558
  },
@@ -9281,6 +9566,7 @@ function WorkflowsPanel({entries: entries, documentId: documentId, docTypeMappin
9281
9566
  tone: "default"
9282
9567
  })
9283
9568
  }),
9569
+ busy: booting,
9284
9570
  title: "Active Workflows"
9285
9571
  }),
9286
9572
  /* @__PURE__ */ jsxRuntime.jsx(TabSwitch, {
@@ -9384,21 +9670,50 @@ function OverviewEmptyState({mappings: mappings, docId: docId, initialValue: ini
9384
9670
 
9385
9671
  function ForMeTab({forMe: forMe, assignedWorkUnknown: assignedWorkUnknown, onOpenActivity: onOpenActivity}) {
9386
9672
  return forMe.hasRows ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
9387
- gap: GROUP_GAP,
9673
+ gap: 6,
9388
9674
  paddingBottom: 4,
9389
- children: [ forMe.hasRoleMatched ? /* @__PURE__ */ jsxRuntime.jsx(RoleAssignedNotice, {}) : null, forMe.work.map(({entry: entry, who: who, shown: shown}) => /* @__PURE__ */ jsxRuntime.jsx(ForMeList, {
9390
- entry: entry,
9391
- identity: who,
9392
- work: shown,
9393
- onOpenActivity: activityName => onOpenActivity({
9394
- instanceId: entry.instance._id,
9395
- activityName: activityName,
9396
- stage: entry.instance.currentStage
9397
- })
9398
- }, 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
+ }) ]
9399
9689
  }) : assignedWorkUnknown ? null : /* @__PURE__ */ jsxRuntime.jsx(ForMeEmptyState, {});
9400
9690
  }
9401
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
+
9402
9717
  function SectionActivityDialog({entry: entry, activityName: activityName, onClose: onClose}) {
9403
9718
  const definition = useDefinition(entry), {instance: instance} = entry;
9404
9719
  /* @__PURE__ */
@@ -9420,6 +9735,44 @@ function workflowDefaultDocumentNode() {
9420
9735
  return S => S.document().views([ S.view.form(), workflowsView(S) ]);
9421
9736
  }
9422
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
+
9423
9776
  function lockTitleFor(args) {
9424
9777
  const {denials: denials, entries: entries} = args;
9425
9778
  if (denials.length === 0) return;
@@ -9781,6 +10134,34 @@ function useDefaultLayout(props) {
9781
10134
  return react.useMemo(() => props.renderDefault(props), [ props ]);
9782
10135
  }
9783
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
+
9784
10165
  const notReady = (..._args) => Promise.reject(new Error("workflow session not ready yet")), NO_REGISTERED_DOCUMENTS = [], DEMAND_RELEASE_GRACE_MS = 500;
9785
10166
 
9786
10167
  function workspaceParts(config) {
@@ -9845,17 +10226,6 @@ function DiscoverySubscription(props) {
9845
10226
  }, [ instances, invalid, registered, onSnapshot ]), null;
9846
10227
  }
9847
10228
 
9848
- function engineOptionsFrom(config) {
9849
- return {
9850
- ...config.effectHandlers ? {
9851
- effectHandlers: config.effectHandlers
9852
- } : {},
9853
- ...config.resourceClients ? {
9854
- resourceClients: config.resourceClients
9855
- } : {}
9856
- };
9857
- }
9858
-
9859
10229
  function WorkflowProvider(props) {
9860
10230
  const {config: config} = props, defaultLayout = useDefaultLayout(props), studioClient = sanity.useClient({
9861
10231
  apiVersion: WORKFLOW_API_VERSION
@@ -9869,11 +10239,18 @@ function WorkflowProvider(props) {
9869
10239
  id: `${projectId}.${contentDataset}`
9870
10240
  },
9871
10241
  tag: config.tag
9872
- }), [ 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({
9873
10248
  workflowResource: binding.engineResource,
9874
10249
  tag: config.tag,
9875
- missingHandler: "skip",
9876
- ...engineOptionsFrom(config)
10250
+ effects: effects,
10251
+ ...config.resourceClients ? {
10252
+ resourceClients: config.resourceClients
10253
+ } : {}
9877
10254
  }), grantsFromPath = workflowEngine.aclPathForResource({
9878
10255
  type: "dataset",
9879
10256
  id: `${projectId}.${workflowDataset}`
@@ -9883,8 +10260,14 @@ function WorkflowProvider(props) {
9883
10260
  registerActive(id), retainRegistration(id);
9884
10261
  }, [ registerActive, retainRegistration ]), unregister = react.useCallback(id => {
9885
10262
  unregisterActive(id), releaseRegistration(id);
9886
- }, [ 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({
9887
10267
  releaseDelayMs: DEMAND_RELEASE_GRACE_MS
10268
+ }), {acquire: requestEvaluation, release: releaseEvaluation} = useWarmDemand({
10269
+ acquire: acquireEvaluation,
10270
+ release: dropEvaluation
9888
10271
  }), [seeded, setSeeded] = react.useState(/* @__PURE__ */ new Map), seedInstance = react.useCallback(instance => {
9889
10272
  setSeeded(prev => new Map(prev).set(instance._id, instance));
9890
10273
  }, []), [startRequest2, setStartRequest] = react.useState(void 0), openStartDialog = react.useCallback(r => setStartRequest(r), []), closeStartDialog = react.useCallback(() => setStartRequest(void 0), []), [entriesStore] = react.useState(createEntriesStore);
@@ -9997,7 +10380,7 @@ function WorkflowProvider(props) {
9997
10380
  mappingStarts: starts,
9998
10381
  mappingFields: fields,
9999
10382
  latestDefinitionVersions: latestVersions,
10000
- effectHandlers: engine.effectHandlers,
10383
+ effectHandlers: engine.effects.handlers,
10001
10384
  autoStartByType: autoStartByType,
10002
10385
  autoStartDefinitions: autoStartDefinitions
10003
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 ]);
@@ -10102,7 +10485,43 @@ function logOnce(messages, logged) {
10102
10485
  for (const message of messages) logged.has(message) || (logged.add(message), console.warn(`[workflow-studio-plugin] ${message}`));
10103
10486
  }
10104
10487
 
10105
- 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}) {
10106
10525
  const [open, setOpen] = react.useState(!1), remove = index => onChange(value.filter((_, i) => i !== index));
10107
10526
  /* @__PURE__ */
10108
10527
  return jsxRuntime.jsxs(ui.Stack, {
@@ -10137,6 +10556,7 @@ function AssigneesInput({value: value, onChange: onChange, eligibleRoles: eligib
10137
10556
  children: /* @__PURE__ */ jsxRuntime.jsx(DismissablePopover, {
10138
10557
  content: /* @__PURE__ */ jsxRuntime.jsx(AssigneePicker, {
10139
10558
  eligibleRoles: eligibleRoles,
10559
+ maxUsers: maxUsers,
10140
10560
  onChange: next => onChange([ ...next ]),
10141
10561
  roleAliases: roleAliases,
10142
10562
  value: value
@@ -10503,6 +10923,13 @@ const docRefInput = ({entry: entry, docType: docType, releaseId: releaseId, valu
10503
10923
  roleAliases: roleAliases,
10504
10924
  value: value ?? []
10505
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
+ }),
10506
10933
  array: ({entry: entry, value: value, onChange: onChange}) => {
10507
10934
  const editor = arrayEditorKind(entry);
10508
10935
  if (editor === "notes") /* @__PURE__ */ return jsxRuntime.jsx(NotesStartInput, {
@@ -11332,9 +11759,9 @@ function StripLines({active: active, docId: docId, finished: finished, initialVa
11332
11759
 
11333
11760
  function lineHint(entry, identity) {
11334
11761
  const forMe = forMeWorkOf([ entry ], identity);
11335
- return forMe.work.some(({shown: shown}) => hasOpenAssignedWork(shown)) ? {
11762
+ return forMe.assignedToUser.some(({shown: shown}) => hasOpenAssignedWork(shown)) ? {
11336
11763
  content: /* @__PURE__ */ jsxRuntime.jsx(AssignedTasksHint, {
11337
- work: forMe.work
11764
+ work: forMe.assignedToUser
11338
11765
  }),
11339
11766
  wide: !0
11340
11767
  } : unassignedLineHint({
@@ -11545,31 +11972,21 @@ const workflowsTool = {
11545
11972
  }, LOCKABLE_ACTIONS = /* @__PURE__ */ new Map([ [ "delete", "delete" ], [ "publish", "publish" ], [ "unpublish", "unpublish" ] ]);
11546
11973
 
11547
11974
  function useDocumentActionLock(action, props) {
11548
- 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);
11549
- return react.useEffect(() => {
11550
- if (!doc || guards.length === 0) {
11551
- applyDenials([]);
11552
- return;
11553
- }
11554
- let cancelled = !1;
11555
- return (async () => {
11556
- const denied = await workflowEngine.documentActionDenials({
11557
- doc: doc,
11558
- resource: resource,
11559
- action: action,
11560
- guards: guards,
11561
- ...identity !== void 0 ? {
11562
- identity: identity
11563
- } : {}
11564
- });
11565
- cancelled || applyDenials(denied);
11566
- })().catch(err => {
11567
- console.error("[workflow-studio-plugin] document-action guard evaluation failed:", err),
11568
- cancelled || applyDenials([]);
11569
- }), () => {
11570
- cancelled = !0;
11571
- };
11572
- }, [ 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({
11573
11990
  denials: denials,
11574
11991
  entries: active
11575
11992
  });
@@ -11635,6 +12052,8 @@ function WorkflowRootInput(props) {
11635
12052
 
11636
12053
  exports.AbortWorkflowDialog = AbortWorkflowDialog;
11637
12054
 
12055
+ exports.ActivityDetailBody = ActivityDetailBody;
12056
+
11638
12057
  exports.ActivityDetailDialog = ActivityDetailDialog;
11639
12058
 
11640
12059
  exports.ActivityLog = ActivityLog;
@@ -11645,9 +12064,11 @@ exports.AlertChip = AlertChip;
11645
12064
 
11646
12065
  exports.AlertGlyph = AlertGlyph;
11647
12066
 
12067
+ exports.Breadcrumb = Breadcrumb;
12068
+
11648
12069
  exports.CodeChip = CodeChip;
11649
12070
 
11650
- exports.CountedHeading = CountedHeading;
12071
+ exports.CountedLabel = CountedLabel;
11651
12072
 
11652
12073
  exports.DismissablePopover = DismissablePopover;
11653
12074
 
@@ -11657,6 +12078,12 @@ exports.DocRefFace = DocRefFace;
11657
12078
 
11658
12079
  exports.EmptyState = EmptyState;
11659
12080
 
12081
+ exports.FOR_ME_SECTION_COPY = FOR_ME_SECTION_COPY;
12082
+
12083
+ exports.ForMeEmptyState = ForMeEmptyState;
12084
+
12085
+ exports.ForMeSectionHeading = ForMeSectionHeading;
12086
+
11660
12087
  exports.HoverHint = HoverHint;
11661
12088
 
11662
12089
  exports.InstanceFaultNote = InstanceFaultNote;
@@ -11677,9 +12104,13 @@ exports.MetricPair = MetricPair;
11677
12104
 
11678
12105
  exports.NoteBanner = NoteBanner;
11679
12106
 
12107
+ exports.OverlineHeading = OverlineHeading;
12108
+
11680
12109
  exports.RUN_SEARCH_PARAM = RUN_SEARCH_PARAM;
11681
12110
 
11682
- exports.RoleAssignedNotice = RoleAssignedNotice;
12111
+ exports.RowAssignees = RowAssignees;
12112
+
12113
+ exports.SectionHeading = SectionHeading;
11683
12114
 
11684
12115
  exports.SpinnerSlot = SpinnerSlot;
11685
12116
 
@@ -11705,20 +12136,30 @@ exports.activityLabel = activityLabel;
11705
12136
 
11706
12137
  exports.assigneesOf = assigneesOf;
11707
12138
 
12139
+ exports.assignmentHolding = assignmentHolding;
12140
+
11708
12141
  exports.countBy = countBy;
11709
12142
 
11710
12143
  exports.definitionFingerprint = definitionFingerprint;
11711
12144
 
11712
12145
  exports.definitionsRouteOf = definitionsRouteOf;
11713
12146
 
12147
+ exports.deriveActivityDetail = deriveActivityDetail;
12148
+
11714
12149
  exports.describeError = describeError;
11715
12150
 
11716
12151
  exports.disambiguatedNames = disambiguatedNames;
11717
12152
 
11718
12153
  exports.dueDatesOf = dueDatesOf;
11719
12154
 
12155
+ exports.dueMomentSentence = dueMomentSentence;
12156
+
11720
12157
  exports.findActivity = findActivity;
11721
12158
 
12159
+ exports.formatDate = formatDate;
12160
+
12161
+ exports.formatShortAgo = formatShortAgo;
12162
+
11722
12163
  exports.formatShortDateTime = formatShortDateTime;
11723
12164
 
11724
12165
  exports.formatTimeAgo = formatTimeAgo;