@sanity/workflow-studio-plugin 0.20.0 → 0.22.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"), 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"), csm = require("@sanity/client/csm"), workflowStudio = require("@sanity/workflow-studio"), sanity = require("sanity"), Calendar = require("@sanity/icons/Calendar"), workflowComponents = require("@sanity/workflow-components"), User = require("@sanity/icons/User"), Search = require("@sanity/icons/Search"), ChevronRight = require("@sanity/icons/ChevronRight"), Edit = require("@sanity/icons/Edit"), content = require("@sanity/util/content"), InfoOutline = require("@sanity/icons/InfoOutline"), Document = require("@sanity/icons/Document"), WarningOutline = require("@sanity/icons/WarningOutline"), router = require("sanity/router"), types = require("@sanity/types"), Launch = require("@sanity/icons/Launch"), Empty$1 = require("@sanity/icons/Empty"), ErrorFilled = require("@sanity/icons/ErrorFilled"), RemoveCircle = require("@sanity/icons/RemoveCircle"), Add = require("@sanity/icons/Add"), Bolt = require("@sanity/icons/Bolt"), ChevronDown = require("@sanity/icons/ChevronDown"), CheckmarkCircle = require("@sanity/icons/CheckmarkCircle"), Ulist = require("@sanity/icons/Ulist"), pluralize = require("pluralize-esm"), EllipsisHorizontal = require("@sanity/icons/EllipsisHorizontal"), ArrowUp = require("@sanity/icons/ArrowUp"), workflowReact = require("@sanity/workflow-react"), Transfer = require("@sanity/icons/Transfer");
3
+ var jsxRuntime = require("react/jsx-runtime"), Timeline = require("@sanity/icons/Timeline"), ui = require("@sanity/ui"), workflowReact = require("@sanity/workflow-react"), react = require("react"), structure = require("sanity/structure"), workflowEngine = require("@sanity/workflow-engine"), Checkmark = require("@sanity/icons/Checkmark"), Close = require("@sanity/icons/Close"), formatDistanceToNow = require("date-fns/formatDistanceToNow"), workflowComponents = require("@sanity/workflow-components"), csm = require("@sanity/client/csm"), telemetry = require("@sanity/telemetry"), workflowStudio = require("@sanity/workflow-studio"), sanity = require("sanity"), Calendar = require("@sanity/icons/Calendar"), User = require("@sanity/icons/User"), Search = require("@sanity/icons/Search"), ChevronRight = require("@sanity/icons/ChevronRight"), Edit = require("@sanity/icons/Edit"), content = require("@sanity/util/content"), InfoOutline = require("@sanity/icons/InfoOutline"), Document = require("@sanity/icons/Document"), WarningOutline = require("@sanity/icons/WarningOutline"), router = require("sanity/router"), types = require("@sanity/types"), Launch = require("@sanity/icons/Launch"), Empty$1 = require("@sanity/icons/Empty"), ErrorFilled = require("@sanity/icons/ErrorFilled"), RemoveCircle = require("@sanity/icons/RemoveCircle"), Add = require("@sanity/icons/Add"), Bolt = require("@sanity/icons/Bolt"), ChevronDown = require("@sanity/icons/ChevronDown"), CheckmarkCircle = require("@sanity/icons/CheckmarkCircle"), Ulist = require("@sanity/icons/Ulist"), pluralize = require("pluralize-esm"), EllipsisHorizontal = require("@sanity/icons/EllipsisHorizontal"), 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 : {
@@ -421,67 +421,6 @@ function isLiveEntry(entry) {
421
421
  return workflowEngine.terminalState(entry.instance) === "in-flight";
422
422
  }
423
423
 
424
- const WORKFLOW_API_VERSION = workflowEngine.ENGINE_API_VERSION, WORKFLOW_SYSTEM_TYPES = [ workflowEngine.WORKFLOW_INSTANCE_TYPE, workflowEngine.WORKFLOW_DEFINITION_TYPE, workflowEngine.GUARD_DOC_TYPE ];
425
-
426
- function editTargetOf(field) {
427
- return {
428
- scope: field.scope,
429
- field: field.name,
430
- ...field.activity ? {
431
- activity: field.activity
432
- } : {}
433
- };
434
- }
435
-
436
- const EMPTY_ENTRIES = [], WorkflowContext = react.createContext(null);
437
-
438
- function useWorkflowContext() {
439
- const value = react.useContext(WorkflowContext);
440
- if (!value) throw new Error("useWorkflowContext must render inside the workflow plugin provider");
441
- return value;
442
- }
443
-
444
- function useWorkflowsForDocument(rawId) {
445
- return useDocumentWorkflowEntries(rawId, !0);
446
- }
447
-
448
- function useCommittedWorkflowsForDocument(rawId) {
449
- return useDocumentWorkflowEntries(rawId, !1);
450
- }
451
-
452
- function useDocumentWorkflowEntries(rawId, evaluate) {
453
- const {register: register, unregister: unregister, requestEvaluation: requestEvaluation, releaseEvaluation: releaseEvaluation, entries: entries} = useWorkflowContext(), docId = rawId ? csm.getPublishedId(rawId) : void 0;
454
- react.useEffect(() => {
455
- if (docId) return register(docId), () => unregister(docId);
456
- }, [ docId, register, unregister ]);
457
- const list = react.useSyncExternalStore(entries.subscribe, react.useCallback(() => docId ? entries.getDocument(docId) : EMPTY_ENTRIES, [ entries, docId ])), evaluationKey = evaluate ? list.map(entry => entry.instance._id).join("\0") : "";
458
- return react.useEffect(() => {
459
- if (!evaluate) return;
460
- const ids = evaluationKey === "" ? [] : evaluationKey.split("\0");
461
- for (const id of ids) requestEvaluation(id);
462
- return () => {
463
- for (const id of ids) releaseEvaluation(id);
464
- };
465
- }, [ evaluate, evaluationKey, requestEvaluation, releaseEvaluation ]), {
466
- docId: docId,
467
- entries: list
468
- };
469
- }
470
-
471
- function useHeldWorkflowEntry(instanceId) {
472
- const {entries: entries} = useWorkflowContext();
473
- return react.useSyncExternalStore(entries.subscribe, react.useCallback(() => instanceId ? entries.getInstance(instanceId) : void 0, [ entries, instanceId ]));
474
- }
475
-
476
- function useWorkflowInstanceEntry(instanceId, options = {}) {
477
- const {requestInstance: requestInstance, releaseInstance: releaseInstance, requestEvaluation: requestEvaluation, releaseEvaluation: releaseEvaluation} = useWorkflowContext(), evaluate = options.evaluate ?? !0;
478
- return react.useEffect(() => {
479
- if (instanceId) return requestInstance(instanceId), () => releaseInstance(instanceId);
480
- }, [ instanceId, requestInstance, releaseInstance ]), react.useEffect(() => {
481
- if (!(!instanceId || !evaluate)) return requestEvaluation(instanceId), () => releaseEvaluation(instanceId);
482
- }, [ instanceId, evaluate, requestEvaluation, releaseEvaluation ]), useHeldWorkflowEntry(instanceId);
483
- }
484
-
485
424
  const isTodoDone = item => item.status === "done", toggledTodoStatus = item => isTodoDone(item) ? "open" : "done";
486
425
 
487
426
  function isTodoOverdue(item, today = /* @__PURE__ */ new Date) {
@@ -557,7 +496,7 @@ function buildTickIndex(evaluation) {
557
496
  function todoFieldEditability(args) {
558
497
  const {evaluation: evaluation, source: source, fieldName: fieldName} = args, match = evaluation?.editableFields.find(f => f.name === fieldName && f.scope === source.scope && (source.scope !== "activity" || f.activity === source.activityName));
559
498
  return match ? match.editable ? {
560
- editTarget: editTargetOf(match)
499
+ editTarget: workflowReact.editFieldTarget(match)
561
500
  } : match.disabledReason === void 0 ? {} : {
562
501
  editDisabledReason: match.disabledReason
563
502
  } : {};
@@ -622,8 +561,8 @@ function assigneeMatches(member, who) {
622
561
  return member.type === "user" ? member.id === who.userId : who.roles.includes(member.role);
623
562
  }
624
563
 
625
- function sameAssignee(a, b) {
626
- return a.type === "user" && b.type === "user" ? a.id === b.id : a.type === "role" && b.type === "role" ? a.role === b.role : !1;
564
+ function changedAssignee(current, next) {
565
+ return next.find(item => !current.some(existing => workflowComponents.sameAssignee(item, existing))) ?? current.find(item => !next.some(existing => workflowComponents.sameAssignee(item, existing)));
627
566
  }
628
567
 
629
568
  function isAssigneeShape(value) {
@@ -998,6 +937,112 @@ function deriveActivityDetail(args) {
998
937
  };
999
938
  }
1000
939
 
940
+ const WORKFLOW_API_VERSION = workflowEngine.ENGINE_API_VERSION, WORKFLOW_SYSTEM_TYPES = [ workflowEngine.WORKFLOW_INSTANCE_TYPE, workflowEngine.WORKFLOW_DEFINITION_TYPE, workflowEngine.GUARD_DOC_TYPE ], EMPTY_ENTRIES = [], WorkflowContext = react.createContext(null);
941
+
942
+ function useWorkflowContext() {
943
+ const value = react.useContext(WorkflowContext);
944
+ if (!value) throw new Error("useWorkflowContext must render inside the workflow plugin provider");
945
+ return value;
946
+ }
947
+
948
+ function useWorkflowsForDocument(rawId) {
949
+ return useDocumentWorkflowEntries(rawId, !0);
950
+ }
951
+
952
+ function useCommittedWorkflowsForDocument(rawId) {
953
+ return useDocumentWorkflowEntries(rawId, !1);
954
+ }
955
+
956
+ function useDocumentWorkflowEntries(rawId, evaluate) {
957
+ const {register: register, unregister: unregister, requestEvaluation: requestEvaluation, releaseEvaluation: releaseEvaluation, entries: entries} = useWorkflowContext(), docId = rawId ? csm.getPublishedId(rawId) : void 0;
958
+ react.useEffect(() => {
959
+ if (docId) return register(docId), () => unregister(docId);
960
+ }, [ docId, register, unregister ]);
961
+ const list = react.useSyncExternalStore(entries.subscribe, react.useCallback(() => docId ? entries.getDocument(docId) : EMPTY_ENTRIES, [ entries, docId ])), evaluationKey = evaluate ? list.map(entry => entry.instance._id).join("\0") : "";
962
+ return react.useEffect(() => {
963
+ if (!evaluate) return;
964
+ const ids = evaluationKey === "" ? [] : evaluationKey.split("\0");
965
+ for (const id of ids) requestEvaluation(id);
966
+ return () => {
967
+ for (const id of ids) releaseEvaluation(id);
968
+ };
969
+ }, [ evaluate, evaluationKey, requestEvaluation, releaseEvaluation ]), {
970
+ docId: docId,
971
+ entries: list
972
+ };
973
+ }
974
+
975
+ function useHeldWorkflowEntry(instanceId) {
976
+ const {entries: entries} = useWorkflowContext();
977
+ return react.useSyncExternalStore(entries.subscribe, react.useCallback(() => instanceId ? entries.getInstance(instanceId) : void 0, [ entries, instanceId ]));
978
+ }
979
+
980
+ function useWorkflowInstanceEntry(instanceId, options = {}) {
981
+ const {requestInstance: requestInstance, releaseInstance: releaseInstance, requestEvaluation: requestEvaluation, releaseEvaluation: releaseEvaluation} = useWorkflowContext(), evaluate = options.evaluate ?? !0;
982
+ return react.useEffect(() => {
983
+ if (instanceId) return requestInstance(instanceId), () => releaseInstance(instanceId);
984
+ }, [ instanceId, requestInstance, releaseInstance ]), react.useEffect(() => {
985
+ if (!(!instanceId || !evaluate)) return requestEvaluation(instanceId), () => releaseEvaluation(instanceId);
986
+ }, [ instanceId, evaluate, requestEvaluation, releaseEvaluation ]), useHeldWorkflowEntry(instanceId);
987
+ }
988
+
989
+ const WorkflowToolOpened = telemetry.defineEvent({
990
+ name: "Editorial Workflows Studio Plugin Tool Opened",
991
+ version: 1,
992
+ description: "The Workflows tool was opened or its tab was switched"
993
+ }), WorkflowDocumentViewOpened = telemetry.defineEvent({
994
+ name: "Editorial Workflows Studio Plugin Document View Opened",
995
+ version: 1,
996
+ description: "The Workflows document view was opened or its tab was switched"
997
+ }), WorkflowInstanceDetailViewed = telemetry.defineEvent({
998
+ name: "Editorial Workflows Studio Plugin Instance Detail Viewed",
999
+ version: 1,
1000
+ description: "The Workflows tool's per-instance detail view was opened"
1001
+ }), WorkflowFormStripClicked = telemetry.defineEvent({
1002
+ name: "Editorial Workflows Studio Plugin Form Strip Clicked",
1003
+ version: 1,
1004
+ description: "The form strip's instance line was clicked, opening the document view"
1005
+ }), WorkflowStartDialogOpened = telemetry.defineEvent({
1006
+ name: "Editorial Workflows Studio Plugin Start Dialog Opened",
1007
+ version: 1,
1008
+ description: "The start-workflow dialog was opened"
1009
+ }), WorkflowStartDialogSubmitted = telemetry.defineEvent({
1010
+ name: "Editorial Workflows Studio Plugin Start Dialog Submitted",
1011
+ version: 1,
1012
+ description: "The start-workflow dialog's confirm was pressed"
1013
+ }), WorkflowAutoStartRan = telemetry.defineEvent({
1014
+ name: "Editorial Workflows Studio Plugin Auto Start Ran",
1015
+ version: 1,
1016
+ description: "A fresh document's auto-start ran — one start request per configured workflow"
1017
+ }), WorkflowActionControlUsed = telemetry.defineEvent({
1018
+ name: "Editorial Workflows Studio Plugin Action Control Used",
1019
+ version: 1,
1020
+ description: "An action-firing control was used, attributed to its UI surface"
1021
+ }), WorkflowActivityDialogOpened = telemetry.defineEvent({
1022
+ name: "Editorial Workflows Studio Plugin Activity Dialog Opened",
1023
+ version: 1,
1024
+ description: "The activity detail dialog was opened"
1025
+ }), WorkflowTaskFiltersApplied = telemetry.defineEvent({
1026
+ name: "Editorial Workflows Studio Plugin Task Filters Applied",
1027
+ version: 1,
1028
+ description: "The tool's task-filter menu closed with a changed selection"
1029
+ }), WorkflowTodoToggled = telemetry.defineEvent({
1030
+ name: "Editorial Workflows Studio Plugin Todo Toggled",
1031
+ version: 1,
1032
+ description: "A todo checkbox was toggled, attributed to its UI surface and write seam"
1033
+ });
1034
+
1035
+ function useLogEventOnMount(event, data) {
1036
+ const telemetry2 = workflowReact.useWorkflowTelemetry(), logged = react.useRef(!1);
1037
+ react.useEffect(() => {
1038
+ logged.current || (logged.current = !0, telemetry2.log(event, data));
1039
+ }, [ telemetry2, event, data ]);
1040
+ }
1041
+
1042
+ function LogEventOnMount(props) {
1043
+ return useLogEventOnMount(props.event, props.data), null;
1044
+ }
1045
+
1001
1046
  function isEmptyValue(value) {
1002
1047
  return value == null || value === "" || Array.isArray(value) && value.length === 0;
1003
1048
  }
@@ -1040,8 +1085,12 @@ function memberIndex(members) {
1040
1085
 
1041
1086
  const selfUserFor = (id, me) => me != null && me.id === id ? me : void 0;
1042
1087
 
1088
+ function globalIdOf(users, projectScopedId) {
1089
+ return users.find(user => user.membership.id === projectScopedId)?.profile?.sanityUserId ?? projectScopedId;
1090
+ }
1091
+
1043
1092
  function userDisplayFor(args) {
1044
- const member = memberIndex(args.members).get(args.id), self = selfUserFor(args.id, args.me);
1093
+ const matchId = args.matchId ?? args.id, member = memberIndex(args.members).get(matchId), self = selfUserFor(matchId, args.me);
1045
1094
  return {
1046
1095
  id: args.id,
1047
1096
  name: member?.displayName ?? self?.name ?? args.id,
@@ -1050,28 +1099,52 @@ function userDisplayFor(args) {
1050
1099
  }
1051
1100
 
1052
1101
  function useUserDisplays(ids) {
1053
- const {members: members} = useProjectMembers(), me = sanity.useCurrentUser();
1102
+ const {members: members} = useProjectMembers(), {users: users} = workflowStudio.useStudioProjectUsers(), meRaw = sanity.useCurrentUser(), me = react.useMemo(() => meRaw === null ? null : {
1103
+ ...meRaw,
1104
+ id: globalIdOf(users, meRaw.id)
1105
+ }, [ meRaw, users ]);
1054
1106
  return react.useMemo(() => ids.map(id => userDisplayFor({
1055
1107
  id: id,
1056
1108
  members: members,
1057
- me: me
1058
- })), [ ids, me, members ]);
1109
+ me: me,
1110
+ matchId: globalIdOf(users, id)
1111
+ })), [ ids, me, members, users ]);
1059
1112
  }
1060
1113
 
1061
1114
  function useUserDisplay(id) {
1062
- const {members: members} = useProjectMembers(), me = sanity.useCurrentUser();
1063
- return react.useMemo(() => userDisplayFor({
1115
+ const ids = react.useMemo(() => [ id ], [ id ]), [display] = useUserDisplays(ids);
1116
+ return display ?? {
1117
+ name: id,
1118
+ imageUrl: void 0
1119
+ };
1120
+ }
1121
+
1122
+ const warnedNotMember = /* @__PURE__ */ new Set;
1123
+
1124
+ function useBridgedSelf() {
1125
+ const me = sanity.useCurrentUser(), {users: users, loading: loading} = workflowStudio.useStudioProjectUsers();
1126
+ if (!me || loading) return;
1127
+ const classified = workflowEngine.classifyPrincipalId(me.id), id = users.find(user => user.membership.id === me.id)?.profile?.sanityUserId ?? classified.globalId ?? (classified.namespace === "project" ? void 0 : me.id);
1128
+ if (id === void 0) {
1129
+ warnedNotMember.has(me.id) || (warnedNotMember.add(me.id), console.warn(`workflow: the project member directory cannot resolve the logged-in user ("${me.id}") to an account-global identity — the engine stores account-global user ids only, so workflow assignment and authoring controls stay disabled. Typically this user is not a member of this project.`));
1130
+ return;
1131
+ }
1132
+ return {
1064
1133
  id: id,
1065
- members: members,
1066
- me: me
1067
- }), [ id, me, members ]);
1134
+ roles: me.roles ?? []
1135
+ };
1136
+ }
1137
+
1138
+ function useSelfActor() {
1139
+ const self = useBridgedSelf();
1140
+ return self === void 0 ? void 0 : personActor(self);
1068
1141
  }
1069
1142
 
1070
1143
  function useAssignmentIdentity() {
1071
- const me = sanity.useCurrentUser();
1072
- if (me) return {
1073
- userId: me.id,
1074
- roles: (me.roles ?? []).map(r => r.name)
1144
+ const self = useBridgedSelf();
1145
+ if (self !== void 0) return {
1146
+ userId: self.id,
1147
+ roles: self.roles.map(r => r.name)
1075
1148
  };
1076
1149
  }
1077
1150
 
@@ -1080,16 +1153,13 @@ const projectMembersByUsers = /* @__PURE__ */ new WeakMap;
1080
1153
  function projectMembersFrom(users) {
1081
1154
  const cached = projectMembersByUsers.get(users);
1082
1155
  if (cached) return cached;
1083
- const members = users.map(({membership: membership, profile: profile}) => ({
1084
- id: membership.id,
1085
- displayName: profile?.displayName ?? membership.id,
1086
- ...profile?.email ? {
1087
- email: profile.email
1088
- } : {},
1089
- ...profile?.imageUrl ? {
1090
- imageUrl: profile.imageUrl
1091
- } : {},
1092
- roles: (membership.roles ?? []).map(role => role.name)
1156
+ const members = users.map(({membership: membership, profile: profile}) => workflowComponents.projectMemberRow({
1157
+ membershipId: membership.id,
1158
+ roles: membership.roles,
1159
+ sanityUserId: profile?.sanityUserId,
1160
+ displayName: profile?.displayName,
1161
+ email: profile?.email,
1162
+ imageUrl: profile?.imageUrl ?? void 0
1093
1163
  }));
1094
1164
  return projectMembersByUsers.set(users, members), members;
1095
1165
  }
@@ -1417,12 +1487,12 @@ function MemberPicker({selectedIds: selectedIds, onSelect: onSelect, unassignRow
1417
1487
  });
1418
1488
  }
1419
1489
 
1420
- function AssigneePicker({value: value, onToggle: onToggle}) {
1490
+ function AssigneePicker({value: value, onChange: onChange}) {
1421
1491
  const state = useProjectMembers();
1422
1492
  /* @__PURE__ */
1423
1493
  return jsxRuntime.jsx(workflowComponents.AssigneePicker, {
1424
1494
  ...state,
1425
- onToggle: onToggle,
1495
+ onChange: onChange,
1426
1496
  value: value
1427
1497
  });
1428
1498
  }
@@ -1752,7 +1822,7 @@ function useActionClusterPending() {
1752
1822
  }
1753
1823
 
1754
1824
  function useFireAction(args) {
1755
- const {instanceId: instanceId, activity: activity, action: action, label: label} = args, {fireActionFor: fireActionFor} = useWorkflowContext(), toast = useClosableToast(), cluster = useActionClusterLock(), [localPending, setLocalPending] = react.useState(!1), pending = localPending || cluster?.pending === !0;
1825
+ const {instanceId: instanceId, activity: activity, action: action, label: label, surface: surface, viaMenu: viaMenu} = args, {fireActionFor: fireActionFor} = useWorkflowContext(), telemetry2 = workflowReact.useWorkflowTelemetry(), toast = useClosableToast(), cluster = useActionClusterLock(), [localPending, setLocalPending] = react.useState(!1), pending = localPending || cluster?.pending === !0;
1756
1826
  return {
1757
1827
  fire: react.useCallback(async params => {
1758
1828
  if (pending) return !1;
@@ -1767,6 +1837,11 @@ function useFireAction(args) {
1767
1837
  }), toast.push({
1768
1838
  status: "success",
1769
1839
  title: `${label} done`
1840
+ }), telemetry2.log(WorkflowActionControlUsed, {
1841
+ instanceId: instanceId,
1842
+ surface: surface,
1843
+ viaMenu: viaMenu,
1844
+ success: !0
1770
1845
  }), !0;
1771
1846
  } catch (err) {
1772
1847
  return console.error(`[workflow-studio-plugin] firing "${action}" on "${activity}" failed:`, err),
@@ -1774,11 +1849,16 @@ function useFireAction(args) {
1774
1849
  status: "error",
1775
1850
  title: `${label} failed`,
1776
1851
  description: describeError(err)
1852
+ }), telemetry2.log(WorkflowActionControlUsed, {
1853
+ instanceId: instanceId,
1854
+ surface: surface,
1855
+ viaMenu: viaMenu,
1856
+ success: !1
1777
1857
  }), !1;
1778
1858
  } finally {
1779
1859
  setLocalPending(!1), cluster?.onFireChange(!1);
1780
1860
  }
1781
- }, [ fireActionFor, instanceId, activity, action, label, pending, toast, cluster ]),
1861
+ }, [ fireActionFor, instanceId, activity, action, label, pending, toast, cluster, telemetry2, surface, viaMenu ]),
1782
1862
  pending: pending
1783
1863
  };
1784
1864
  }
@@ -1819,12 +1899,14 @@ function RowClickShield({active: active, children: children}) {
1819
1899
  });
1820
1900
  }
1821
1901
 
1822
- function FireButton({instanceId: instanceId, activity: activity, action: action, label: label, mode: mode = "default", chrome: chrome, tone: tone = "default", icon: icon}) {
1902
+ function FireButton({instanceId: instanceId, activity: activity, action: action, label: label, surface: surface, mode: mode = "default", chrome: chrome, tone: tone = "default", icon: icon}) {
1823
1903
  const {fire: fire, pending: pending} = useFireAction({
1824
1904
  instanceId: instanceId,
1825
1905
  activity: activity,
1826
1906
  action: action,
1827
- label: label
1907
+ label: label,
1908
+ surface: surface,
1909
+ viaMenu: !1
1828
1910
  }), handleClick = e => {
1829
1911
  chrome?.inButtonCard === !0 && e.stopPropagation(), !pending && fire();
1830
1912
  };
@@ -1845,7 +1927,7 @@ function FireButton({instanceId: instanceId, activity: activity, action: action,
1845
1927
  });
1846
1928
  }
1847
1929
 
1848
- function ActivityActionRow({actionEval: actionEval, instanceId: instanceId, activity: activity, chrome: chrome}) {
1930
+ function ActivityActionRow({actionEval: actionEval, instanceId: instanceId, activity: activity, surface: surface, chrome: chrome}) {
1849
1931
  const rowKind = actionRowKind(actionEval);
1850
1932
  return rowKind.kind === "disabled" ? /* @__PURE__ */ jsxRuntime.jsx(DisabledActionButton, {
1851
1933
  actionEval: actionEval,
@@ -1855,12 +1937,14 @@ function ActivityActionRow({actionEval: actionEval, instanceId: instanceId, acti
1855
1937
  actionEval: actionEval,
1856
1938
  instanceId: instanceId,
1857
1939
  activity: activity,
1858
- chrome: chrome
1940
+ chrome: chrome,
1941
+ surface: surface
1859
1942
  }) : /* @__PURE__ */ jsxRuntime.jsx(ParamsActionButton, {
1860
1943
  actionEval: actionEval,
1861
1944
  instanceId: instanceId,
1862
1945
  activity: activity,
1863
- chrome: chrome
1946
+ chrome: chrome,
1947
+ surface: surface
1864
1948
  });
1865
1949
  }
1866
1950
 
@@ -1885,7 +1969,7 @@ function DisabledActionButton({actionEval: actionEval, activity: activity, chrom
1885
1969
  }) : button;
1886
1970
  }
1887
1971
 
1888
- function PlainActionButton({actionEval: actionEval, instanceId: instanceId, activity: activity, chrome: chrome}) {
1972
+ function PlainActionButton({actionEval: actionEval, instanceId: instanceId, activity: activity, surface: surface, chrome: chrome}) {
1889
1973
  const {action: action} = actionEval, label = actionLabel(action), btn = actionButtonFace({
1890
1974
  actionEval: actionEval,
1891
1975
  activityName: activity
@@ -1897,6 +1981,7 @@ function PlainActionButton({actionEval: actionEval, instanceId: instanceId, acti
1897
1981
  mode: btn.mode,
1898
1982
  activity: activity,
1899
1983
  chrome: chrome,
1984
+ surface: surface,
1900
1985
  tone: btn.tone
1901
1986
  });
1902
1987
  return action.description ? /* @__PURE__ */ jsxRuntime.jsx(HoverHint, {
@@ -1905,12 +1990,14 @@ function PlainActionButton({actionEval: actionEval, instanceId: instanceId, acti
1905
1990
  }) : button;
1906
1991
  }
1907
1992
 
1908
- function ParamsActionDialog({actionEval: actionEval, instanceId: instanceId, activity: activity, onClose: onClose}) {
1993
+ function ParamsActionDialog({actionEval: actionEval, instanceId: instanceId, activity: activity, surface: surface, viaMenu: viaMenu, onClose: onClose}) {
1909
1994
  const {action: action} = actionEval, label = actionLabel(action), decls = action.params ?? [], [values, setValues] = react.useState({}), {fire: fire, pending: pending} = useFireAction({
1910
1995
  instanceId: instanceId,
1911
1996
  activity: activity,
1912
1997
  action: action.name,
1913
- label: label
1998
+ label: label,
1999
+ surface: surface,
2000
+ viaMenu: viaMenu
1914
2001
  }), built = buildParams(decls, values), confirm = async () => {
1915
2002
  await fire(built.params) && onClose();
1916
2003
  };
@@ -1965,7 +2052,7 @@ function ParamsActionDialog({actionEval: actionEval, instanceId: instanceId, act
1965
2052
  });
1966
2053
  }
1967
2054
 
1968
- function ParamsActionButton({actionEval: actionEval, instanceId: instanceId, activity: activity, chrome: chrome}) {
2055
+ function ParamsActionButton({actionEval: actionEval, instanceId: instanceId, activity: activity, surface: surface, chrome: chrome}) {
1969
2056
  const [open, setOpen] = react.useState(!1), btn = actionButtonFace({
1970
2057
  actionEval: actionEval,
1971
2058
  activityName: activity
@@ -1990,7 +2077,9 @@ function ParamsActionButton({actionEval: actionEval, instanceId: instanceId, act
1990
2077
  actionEval: actionEval,
1991
2078
  activity: activity,
1992
2079
  instanceId: instanceId,
1993
- onClose: () => setOpen(!1)
2080
+ onClose: () => setOpen(!1),
2081
+ surface: surface,
2082
+ viaMenu: !1
1994
2083
  })
1995
2084
  }) : null ]
1996
2085
  });
@@ -2284,27 +2373,10 @@ function useLocalDocRef(gdr) {
2284
2373
  }
2285
2374
 
2286
2375
  function useActualDocType(bareId) {
2287
- const client = sanity.useClient({
2288
- apiVersion: WORKFLOW_API_VERSION
2289
- }), [probe, setProbe] = react.useState();
2376
+ const {actualTypes: actualTypes} = useWorkflowContext();
2290
2377
  return react.useEffect(() => {
2291
- if (!bareId) return;
2292
- let cancelled = !1;
2293
- return client.fetch("*[_id == $id || _id == $draft || _id in path($version)][0]._type", {
2294
- id: bareId,
2295
- draft: `drafts.${bareId}`,
2296
- version: `versions.*.${bareId}`
2297
- }, {
2298
- perspective: "raw"
2299
- }).then(result => {
2300
- cancelled || setProbe({
2301
- id: bareId,
2302
- value: result
2303
- });
2304
- }).catch(() => {}), () => {
2305
- cancelled = !0;
2306
- };
2307
- }, [ client, bareId ]), probe !== void 0 && probe.id === bareId ? probe.value : void 0;
2378
+ if (bareId !== null) return actualTypes.track(bareId);
2379
+ }, [ actualTypes, bareId ]), react.useSyncExternalStore(actualTypes.subscribe, react.useCallback(() => bareId === null ? void 0 : actualTypes.read(bareId), [ actualTypes, bareId ]));
2308
2380
  }
2309
2381
 
2310
2382
  function useDocLink(gdr) {
@@ -2884,7 +2956,7 @@ function useFieldDraft(args) {
2884
2956
  }
2885
2957
 
2886
2958
  function EditableFieldControl({instanceId: instanceId, field: field}) {
2887
- const {editFieldFor: editFieldFor, previewFieldFor: previewFieldFor, discardFieldPreviewFor: discardFieldPreviewFor} = useWorkflowContext(), me = sanity.useCurrentUser(), held = useHeldWorkflowEntry(instanceId), entry = held ? workflowEngine.resolveFieldEntry(held.instance, field) : void 0, evaluation = held?.evaluation, target = editTargetOf(field), consequence = fieldConsequence(evaluation, field.name), advanceTo = advanceTargetTitle(evaluation, field.name);
2959
+ const {editFieldFor: editFieldFor, previewFieldFor: previewFieldFor, discardFieldPreviewFor: discardFieldPreviewFor} = useWorkflowContext(), selfActor = useSelfActor(), held = useHeldWorkflowEntry(instanceId), entry = held ? workflowEngine.resolveFieldEntry(held.instance, field) : void 0, evaluation = held?.evaluation, target = workflowReact.editFieldTarget(field), consequence = fieldConsequence(evaluation, field.name), advanceTo = advanceTargetTitle(evaluation, field.name);
2888
2960
  /* @__PURE__ */
2889
2961
  return jsxRuntime.jsx(EditableField, {
2890
2962
  field: field,
@@ -2920,7 +2992,7 @@ function EditableFieldControl({instanceId: instanceId, field: field}) {
2920
2992
  mode: "append",
2921
2993
  value: noteRow({
2922
2994
  body: body,
2923
- actor: me ? personActor(me) : void 0,
2995
+ actor: selfActor,
2924
2996
  at: /* @__PURE__ */ (new Date).toISOString()
2925
2997
  })
2926
2998
  }).then(() => {})
@@ -3033,7 +3105,7 @@ function useAssigneePick(args) {
3033
3105
  saving: saving,
3034
3106
  pick: assignee => {
3035
3107
  if (!saving) {
3036
- if (current && sameAssignee(assignee, current)) {
3108
+ if (current && workflowComponents.sameAssignee(assignee, current)) {
3037
3109
  onUnset !== void 0 && save(onUnset);
3038
3110
  return;
3039
3111
  }
@@ -3055,7 +3127,10 @@ function AssigneeField({field: field, onSave: onSave, onUnset: onUnset}) {
3055
3127
  align: "center",
3056
3128
  children: /* @__PURE__ */ jsxRuntime.jsx(DismissablePopover, {
3057
3129
  content: /* @__PURE__ */ jsxRuntime.jsx(AssigneePicker, {
3058
- onToggle: pickAndClose,
3130
+ onChange: next => {
3131
+ const changed = changedAssignee(cur ? [ cur ] : [], next);
3132
+ changed && pickAndClose(changed);
3133
+ },
3059
3134
  value: cur ? [ cur ] : []
3060
3135
  }),
3061
3136
  onDismiss: () => setOpen(!1),
@@ -3580,11 +3655,11 @@ function AssignActivityControl({instanceId: instanceId, state: state, assigneeId
3580
3655
  setBusy(!0);
3581
3656
  try {
3582
3657
  selectedIds.has(memberId) ? await editFieldFor(instanceId, {
3583
- target: editTargetOf(field),
3658
+ target: workflowReact.editFieldTarget(field),
3584
3659
  mode: "set",
3585
3660
  value: members.filter(m => !(m.type === "user" && m.id === memberId))
3586
3661
  }) : await editFieldFor(instanceId, {
3587
- target: editTargetOf(field),
3662
+ target: workflowReact.editFieldTarget(field),
3588
3663
  mode: "append",
3589
3664
  value: {
3590
3665
  type: "user",
@@ -4013,8 +4088,8 @@ function TodoItemRowView({breadcrumb: breadcrumb, row: row, onToggle: onToggle,
4013
4088
  });
4014
4089
  }
4015
4090
 
4016
- function TodoItemsList({breadcrumb: breadcrumb, entry: entry, filter: filter}) {
4017
- const {instance: instance} = entry, definition = useDefinition(entry), {editFieldFor: editFieldFor, fireActionFor: fireActionFor} = useWorkflowContext(), toast = useClosableToast(), [busy, setBusy] = react.useState(!1), derivation = deriveTodoItems(entry), rows = derivation.rows.filter(row => rowMatches(row, filter)), appendTarget = appendTargetFor(derivation.appendTargets, filter), run = async op => {
4091
+ function TodoItemsList({breadcrumb: breadcrumb, entry: entry, filter: filter, surface: surface}) {
4092
+ const {instance: instance} = entry, definition = useDefinition(entry), {editFieldFor: editFieldFor, fireActionFor: fireActionFor} = useWorkflowContext(), telemetry2 = workflowReact.useWorkflowTelemetry(), toast = useClosableToast(), [busy, setBusy] = react.useState(!1), derivation = deriveTodoItems(entry), rows = derivation.rows.filter(row => rowMatches(row, filter)), appendTarget = appendTargetFor(derivation.appendTargets, filter), run = async op => {
4018
4093
  if (busy) return !1;
4019
4094
  setBusy(!0);
4020
4095
  try {
@@ -4039,15 +4114,35 @@ function TodoItemsList({breadcrumb: breadcrumb, entry: entry, filter: filter}) {
4039
4114
  mode: "set",
4040
4115
  value: next
4041
4116
  }));
4042
- }, toggleRow = row => {
4043
- if (row.editTarget) return patchItem(row, {
4044
- status: toggledTodoStatus(row.item)
4045
- });
4117
+ }, toggleRow = async row => {
4118
+ if (busy) return;
4119
+ if (row.editTarget) {
4120
+ const done = !isTodoDone(row.item), success = await patchItem(row, {
4121
+ status: toggledTodoStatus(row.item)
4122
+ }) === !0;
4123
+ telemetry2.log(WorkflowTodoToggled, {
4124
+ instanceId: instance._id,
4125
+ surface: surface,
4126
+ via: "field-edit",
4127
+ done: done,
4128
+ success: success
4129
+ });
4130
+ return;
4131
+ }
4046
4132
  const tick = row.tick;
4047
- return tick && tick.actionEval.allowed && !isTodoDone(row.item) ? run(() => fireActionFor(instance._id, {
4048
- activity: tick.activity,
4049
- action: tick.actionEval.action.name
4050
- })) : Promise.resolve();
4133
+ if (tick && tick.actionEval.allowed && !isTodoDone(row.item)) {
4134
+ const success = await run(() => fireActionFor(instance._id, {
4135
+ activity: tick.activity,
4136
+ action: tick.actionEval.action.name
4137
+ }));
4138
+ telemetry2.log(WorkflowTodoToggled, {
4139
+ instanceId: instance._id,
4140
+ surface: surface,
4141
+ via: "action",
4142
+ done: !0,
4143
+ success: success
4144
+ });
4145
+ }
4051
4146
  }, addItem = label => appendTarget ? run(() => editFieldFor(instance._id, {
4052
4147
  target: appendTarget,
4053
4148
  mode: "append",
@@ -4164,7 +4259,7 @@ const ACTIONS_MENU_TRIGGER = {
4164
4259
  padding: 2
4165
4260
  };
4166
4261
 
4167
- function ActionMenuItem({actionEval: actionEval, instanceId: instanceId, activity: activity, onCollectParams: onCollectParams}) {
4262
+ function ActionMenuItem({actionEval: actionEval, instanceId: instanceId, activity: activity, surface: surface, onCollectParams: onCollectParams}) {
4168
4263
  const rowKind = actionRowKind(actionEval), label = actionTriggerLabel(actionEval), {tone: tone, icon: icon} = actionButtonFace({
4169
4264
  actionEval: actionEval,
4170
4265
  activityName: activity
@@ -4174,7 +4269,9 @@ function ActionMenuItem({actionEval: actionEval, instanceId: instanceId, activit
4174
4269
  instanceId: instanceId,
4175
4270
  activity: activity,
4176
4271
  action: actionEval.action.name,
4177
- label: label
4272
+ label: label,
4273
+ surface: surface,
4274
+ viaMenu: !0
4178
4275
  });
4179
4276
  return rowKind.kind === "disabled" ? /* @__PURE__ */ jsxRuntime.jsx(ui.MenuItem, {
4180
4277
  disabled: !0,
@@ -4210,7 +4307,7 @@ function rowShield(menuButton) {
4210
4307
  });
4211
4308
  }
4212
4309
 
4213
- function ActionsMenuButton({actions: actions, instanceId: instanceId, activity: activity, label: label, mode: mode = "ghost", inButtonCard: inButtonCard = !1}) {
4310
+ function ActionsMenuButton({actions: actions, instanceId: instanceId, activity: activity, label: label, surface: surface, mode: mode = "ghost", inButtonCard: inButtonCard = !1}) {
4214
4311
  const [paramsAction, setParamsAction] = react.useState(void 0), clusterPending = useActionClusterPending(), menuId = react.useId(), menuButton = /* @__PURE__ */ jsxRuntime.jsx(ui.MenuButton, {
4215
4312
  button: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
4216
4313
  ...ACTIONS_MENU_TRIGGER,
@@ -4229,7 +4326,8 @@ function ActionsMenuButton({actions: actions, instanceId: instanceId, activity:
4229
4326
  actionEval: a,
4230
4327
  activity: activity,
4231
4328
  instanceId: instanceId,
4232
- onCollectParams: () => setParamsAction(a)
4329
+ onCollectParams: () => setParamsAction(a),
4330
+ surface: surface
4233
4331
  }, a.action.name))
4234
4332
  }),
4235
4333
  popover: {
@@ -4245,7 +4343,9 @@ function ActionsMenuButton({actions: actions, instanceId: instanceId, activity:
4245
4343
  actionEval: paramsAction,
4246
4344
  activity: activity,
4247
4345
  instanceId: instanceId,
4248
- onClose: () => setParamsAction(void 0)
4346
+ onClose: () => setParamsAction(void 0),
4347
+ surface: surface,
4348
+ viaMenu: !0
4249
4349
  })
4250
4350
  }) : null ]
4251
4351
  });
@@ -4261,7 +4361,8 @@ function TerminalFooter({actions: actions, activity: activity, instanceId: insta
4261
4361
  children: /* @__PURE__ */ jsxRuntime.jsx(ActivityActionRow, {
4262
4362
  actionEval: only,
4263
4363
  activity: activity,
4264
- instanceId: instanceId
4364
+ instanceId: instanceId,
4365
+ surface: "terminal-footer"
4265
4366
  })
4266
4367
  }) : /* @__PURE__ */ jsxRuntime.jsx(FittedActions, {
4267
4368
  actions: actions,
@@ -4315,13 +4416,15 @@ function FittedActions({actions: actions, activity: activity, instanceId: instan
4315
4416
  children: [ inline === void 0 ? null : actions.slice(0, inline).map(a => /* @__PURE__ */ jsxRuntime.jsx(ActivityActionRow, {
4316
4417
  actionEval: a,
4317
4418
  activity: activity,
4318
- instanceId: instanceId
4419
+ instanceId: instanceId,
4420
+ surface: "terminal-footer"
4319
4421
  }, a.action.name)), overflow.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(ActionsMenuButton, {
4320
4422
  actions: overflow,
4321
4423
  activity: activity,
4322
4424
  instanceId: instanceId,
4323
4425
  label: MORE_ACTIONS_LABEL,
4324
- mode: "default"
4426
+ mode: "default",
4427
+ surface: "terminal-footer"
4325
4428
  }) : null ]
4326
4429
  }) ]
4327
4430
  });
@@ -4364,7 +4467,7 @@ function MeasureRow({actions: actions, activity: activity, onElement: onElement}
4364
4467
  });
4365
4468
  }
4366
4469
 
4367
- function ActivityDetailDialog({entry: entry, activityName: activityName, breadcrumb: breadcrumb, definition: definition, document: document, onClose: onClose}) {
4470
+ function ActivityDetailDialog({entry: entry, activityName: activityName, breadcrumb: breadcrumb, definition: definition, document: document, source: source, onClose: onClose}) {
4368
4471
  const detail = deriveActivityDetail({
4369
4472
  entry: entry,
4370
4473
  activityName: activityName
@@ -4386,6 +4489,13 @@ function ActivityDetailDialog({entry: entry, activityName: activityName, breadcr
4386
4489
  onClose: onClose,
4387
4490
  width: 1,
4388
4491
  children: [
4492
+ /* @__PURE__ */ jsxRuntime.jsx(LogEventOnMount, {
4493
+ data: {
4494
+ instanceId: instanceId,
4495
+ source: source
4496
+ },
4497
+ event: WorkflowActivityDialogOpened
4498
+ }),
4389
4499
  /* @__PURE__ */ jsxRuntime.jsx(ui.Card, {
4390
4500
  borderBottom: hasBody,
4391
4501
  style: {
@@ -4493,7 +4603,8 @@ function TopActions({detail: detail, definition: definition, instanceId: instanc
4493
4603
  children: [ p.actions.map(a => /* @__PURE__ */ jsxRuntime.jsx(ActivityActionRow, {
4494
4604
  actionEval: a,
4495
4605
  activity: activityName,
4496
- instanceId: instanceId
4606
+ instanceId: instanceId,
4607
+ surface: "dialog-strip"
4497
4608
  }, a.action.name)), p.manualTarget ? /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
4498
4609
  as: "a",
4499
4610
  fontSize: 1,
@@ -4529,7 +4640,8 @@ function FieldRow({field: field, detail: detail, entry: entry, activityName: act
4529
4640
  scope: "activity",
4530
4641
  field: field.name,
4531
4642
  activity: activityName
4532
- }
4643
+ },
4644
+ surface: "activity-dialog"
4533
4645
  }) ]
4534
4646
  });
4535
4647
  if (field._type === "assignees") {
@@ -4682,29 +4794,7 @@ function GroupHeading({busy: busy, count: count, title: title, end: end}) {
4682
4794
  });
4683
4795
  }
4684
4796
 
4685
- function CopyDetailsButton({unreadable: unreadable}) {
4686
- const toast = useClosableToast();
4687
- /* @__PURE__ */
4688
- return jsxRuntime.jsx(ui.Button, {
4689
- fontSize: 1,
4690
- mode: "ghost",
4691
- onClick: () => {
4692
- navigator.clipboard.writeText(unreadableDocsReport(unreadable)).then(() => toast.push({
4693
- status: "success",
4694
- title: "Details copied"
4695
- }), () => toast.push({
4696
- status: "error",
4697
- title: "Could not copy the details"
4698
- }));
4699
- },
4700
- padding: 2,
4701
- text: "Copy details"
4702
- });
4703
- }
4704
-
4705
- function UnreadableDocsNote({unreadable: unreadable}) {
4706
- if (unreadable.length === 0) return null;
4707
- const label = unreadable.length === 1 ? "1 workflow document isn’t listed — this Studio can’t read it. Share the details with your Studio maintainers." : `${unreadable.length} workflow documents aren’t listed — this Studio can’t read them. Share the details with your Studio maintainers.`;
4797
+ function CautionNote({action: action, label: label}) {
4708
4798
  /* @__PURE__ */
4709
4799
  return jsxRuntime.jsxs(ui.Card, {
4710
4800
  padding: 2,
@@ -4731,10 +4821,39 @@ function UnreadableDocsNote({unreadable: unreadable}) {
4731
4821
  size: 1,
4732
4822
  children: label
4733
4823
  }) ]
4734
- }),
4735
- /* @__PURE__ */ jsxRuntime.jsx(CopyDetailsButton, {
4824
+ }), action ]
4825
+ });
4826
+ }
4827
+
4828
+ function CopyDetailsButton({unreadable: unreadable}) {
4829
+ const toast = useClosableToast();
4830
+ /* @__PURE__ */
4831
+ return jsxRuntime.jsx(ui.Button, {
4832
+ fontSize: 1,
4833
+ mode: "ghost",
4834
+ onClick: () => {
4835
+ navigator.clipboard.writeText(unreadableDocsReport(unreadable)).then(() => toast.push({
4836
+ status: "success",
4837
+ title: "Details copied"
4838
+ }), () => toast.push({
4839
+ status: "error",
4840
+ title: "Could not copy the details"
4841
+ }));
4842
+ },
4843
+ padding: 2,
4844
+ text: "Copy details"
4845
+ });
4846
+ }
4847
+
4848
+ function UnreadableDocsNote({unreadable: unreadable}) {
4849
+ if (unreadable.length === 0) return null;
4850
+ const label = unreadable.length === 1 ? "1 workflow document isn’t listed — this Studio can’t read it. Share the details with your Studio maintainers." : `${unreadable.length} workflow documents aren’t listed — this Studio can’t read them. Share the details with your Studio maintainers.`;
4851
+ /* @__PURE__ */
4852
+ return jsxRuntime.jsx(CautionNote, {
4853
+ action: /* @__PURE__ */ jsxRuntime.jsx(CopyDetailsButton, {
4736
4854
  unreadable: unreadable
4737
- }) ]
4855
+ }),
4856
+ label: label
4738
4857
  });
4739
4858
  }
4740
4859
 
@@ -5056,6 +5175,25 @@ function buildStartRequest(args) {
5056
5175
  };
5057
5176
  }
5058
5177
 
5178
+ function sharedPreflightDataset(engine, tag) {
5179
+ let pending;
5180
+ return () => {
5181
+ if (pending !== void 0) return pending;
5182
+ const {query: query, params: params} = workflowEngine.instancesQuery({
5183
+ tag: tag,
5184
+ filter: {
5185
+ includeCompleted: !0
5186
+ }
5187
+ });
5188
+ return pending = engine.query({
5189
+ groq: query,
5190
+ params: params
5191
+ }).then(rows => rows.map(workflowEngine.assertReadableModel).map(workflowEngine.projectStartSliceRow)).finally(() => {
5192
+ pending = void 0;
5193
+ }), pending;
5194
+ };
5195
+ }
5196
+
5059
5197
  function findResumeEntry(args) {
5060
5198
  return args.entries.find(e => workflowEngine.isUnprimed(e.instance) && e.instance.definition === args.definitionName && (args.heldInstanceId === void 0 || e.instance._id === args.heldInstanceId));
5061
5199
  }
@@ -5071,7 +5209,8 @@ function classifyStartError(err) {
5071
5209
  instance: err.instance,
5072
5210
  description: describeError(err.cause)
5073
5211
  } : err instanceof workflowEngine.StartNotAllowedError ? {
5074
- kind: "not-allowed"
5212
+ kind: "not-allowed",
5213
+ description: err.unmetRequirements.map(requirementCopy).join("; ")
5075
5214
  } : {
5076
5215
  kind: "failed",
5077
5216
  description: describeError(err)
@@ -5084,22 +5223,30 @@ function boundReleaseId(mapping, selectedReleaseId) {
5084
5223
 
5085
5224
  function startGate(args) {
5086
5225
  const {mapping: mapping, mappingIssue: mappingIssue, selectedReleaseId: selectedReleaseId, releaseActive: releaseActive} = args;
5087
- return mappingIssue !== void 0 ? {
5226
+ if (mappingIssue !== void 0) return {
5088
5227
  blocked: !0,
5089
5228
  tooltip: mappingIssue
5090
- } : mapping.perspectiveField?.required === !0 && selectedReleaseId === void 0 ? {
5229
+ };
5230
+ if (mapping.perspectiveField?.required === !0 && selectedReleaseId === void 0) return {
5091
5231
  blocked: !0,
5092
5232
  tooltip: "Pick a release in the perspective dropdown first"
5093
- } : mapping.perspectiveField !== void 0 && selectedReleaseId !== void 0 && !releaseActive ? {
5233
+ };
5234
+ if (mapping.perspectiveField !== void 0 && selectedReleaseId !== void 0 && !releaseActive) return {
5094
5235
  blocked: !0,
5095
5236
  tooltip: `Release "${selectedReleaseId}" is not active — only active releases can host new workflows`
5096
- } : args.startFilterFailed === !0 ? {
5237
+ };
5238
+ if (args.startFilterFailed === !0) return {
5097
5239
  blocked: !0,
5098
5240
  tooltip: `${mapping.label} can't start for this document right now — the workflow's start condition isn't met`
5099
- } : args.startAllowedRefused === !0 ? {
5100
- blocked: !0,
5101
- tooltip: `${mapping.label} can't be started for this document right now — the workflow doesn't allow another run with these inputs`
5102
- } : {
5241
+ };
5242
+ if (args.unmetRequirement !== void 0) {
5243
+ const requirement = args.unmetRequirement;
5244
+ return {
5245
+ blocked: !0,
5246
+ tooltip: requirementCopy(requirement)
5247
+ };
5248
+ }
5249
+ return {
5103
5250
  blocked: !1,
5104
5251
  tooltip: void 0
5105
5252
  };
@@ -5122,10 +5269,10 @@ async function preflightFilter(args) {
5122
5269
  });
5123
5270
  }
5124
5271
 
5125
- async function preflightAllowed(args) {
5126
- const {allowed: allowed, mapping: mapping, fields: fields, scope: scope} = args;
5127
- return workflowEngine.unboundAllowedReads(allowed, fields).length > 0 ? !1 : (await workflowEngine.explainStartAllowed({
5128
- allowed: allowed,
5272
+ async function preflightGroqRequirement(args) {
5273
+ const {query: query, mapping: mapping, fields: fields, scope: scope} = args;
5274
+ return workflowEngine.unboundRequirementReads(query, fields).length > 0 ? !1 : (await workflowEngine.explainStartRequirement({
5275
+ query: query,
5129
5276
  definition: {
5130
5277
  name: mapping.definition
5131
5278
  },
@@ -5134,6 +5281,25 @@ async function preflightAllowed(args) {
5134
5281
  })).outcome === "unsatisfied";
5135
5282
  }
5136
5283
 
5284
+ async function preflightSingleSubjectRequirement(args) {
5285
+ const {mapping: mapping, start: start, declaredFields: declaredFields, fields: fields, scope: scope} = args;
5286
+ return workflowEngine.singleSubjectRequirementRefused({
5287
+ definition: {
5288
+ name: mapping.definition,
5289
+ ...declaredFields !== void 0 ? {
5290
+ fields: [ ...declaredFields ]
5291
+ } : {},
5292
+ start: start
5293
+ },
5294
+ fields: fields,
5295
+ scope: scope
5296
+ });
5297
+ }
5298
+
5299
+ function requirementCopy(requirement) {
5300
+ return requirement.description ?? requirement.title ?? workflowEngine.humanize(requirement.name);
5301
+ }
5302
+
5137
5303
  async function performStart(args) {
5138
5304
  const {mapping: mapping, docId: docId, initialValue: initialValue, selectedReleaseId: selectedReleaseId} = args, releaseId = boundReleaseId(mapping, selectedReleaseId);
5139
5305
  try {
@@ -5160,7 +5326,21 @@ async function performStart(args) {
5160
5326
  }
5161
5327
 
5162
5328
  function useStartVerdicts(args) {
5163
- const {mapping: mapping, start: start, docId: docId, initialValue: initialValue, selectedReleaseId: selectedReleaseId} = args, skip = args.hidden || args.resumable;
5329
+ const {mapping: mapping, start: start, docId: docId, initialValue: initialValue, selectedReleaseId: selectedReleaseId, entries: entries} = args, {engine: engine, binding: binding} = useWorkflowContext(), fetchDataset = react.useMemo(() => sharedPreflightDataset(engine, binding.tag), [ engine, binding.tag ]), skip = args.hidden || args.resumable, groqRequirements = react.useMemo(() => start?.requirements?.filter(requirement => requirement.type === "groq") ?? [], [ start?.requirements ]), refusedGroq = useGroqRequirementVerdicts({
5330
+ mapping: mapping,
5331
+ requirements: groqRequirements,
5332
+ docId: docId,
5333
+ selectedReleaseId: selectedReleaseId,
5334
+ skip: skip,
5335
+ fetchDataset: fetchDataset
5336
+ }), singleSubjectRefused = useSingleSubjectVerdict({
5337
+ mapping: mapping,
5338
+ start: start,
5339
+ docId: docId,
5340
+ selectedReleaseId: selectedReleaseId,
5341
+ entries: entries,
5342
+ skip: skip
5343
+ }), unmetRequirement = start?.requirements?.find(requirement => requirement.type === "singleSubject" ? singleSubjectRefused : refusedGroq.includes(requirement.name));
5164
5344
  return {
5165
5345
  filterFailed: useFilterVerdict({
5166
5346
  mapping: mapping,
@@ -5168,25 +5348,15 @@ function useStartVerdicts(args) {
5168
5348
  docId: docId,
5169
5349
  initialValue: initialValue,
5170
5350
  selectedReleaseId: selectedReleaseId,
5171
- skip: skip
5351
+ skip: skip,
5352
+ fetchDataset: fetchDataset
5172
5353
  }),
5173
- allowedRefused: useAllowedVerdict({
5174
- mapping: mapping,
5175
- allowed: start?.allowed,
5176
- docId: docId,
5177
- selectedReleaseId: selectedReleaseId,
5178
- skip: skip
5179
- })
5354
+ unmetRequirement: unmetRequirement
5180
5355
  };
5181
5356
  }
5182
5357
 
5183
5358
  function preflightScope(args) {
5184
- const {engine: engine, tag: tag, mapping: mapping, contentResource: contentResource, docId: docId} = args, {query: query, params: params} = workflowEngine.instancesQuery({
5185
- tag: tag,
5186
- filter: {
5187
- includeCompleted: !0
5188
- }
5189
- });
5359
+ const {tag: tag, mapping: mapping, contentResource: contentResource, docId: docId, fetchDataset: fetchDataset} = args;
5190
5360
  return {
5191
5361
  tag: tag,
5192
5362
  now: /* @__PURE__ */ (new Date).toISOString(),
@@ -5195,15 +5365,12 @@ function preflightScope(args) {
5195
5365
  contentResource: contentResource,
5196
5366
  documentId: docId
5197
5367
  }).id,
5198
- fetchDataset: async () => (await engine.query({
5199
- groq: query,
5200
- params: params
5201
- })).map(workflowEngine.assertReadableModel)
5368
+ fetchDataset: fetchDataset
5202
5369
  };
5203
5370
  }
5204
5371
 
5205
5372
  function useFilterVerdict(args) {
5206
- const {mapping: mapping, filter: filter, docId: docId, initialValue: initialValue, selectedReleaseId: selectedReleaseId, skip: skip} = args, {engine: engine, binding: binding} = useWorkflowContext(), [failed, setFailed] = react.useState(!1), rootRead = filter !== void 0 && workflowEngine.readsRootDocument(filter), candidateValue = rootRead ? initialValue : null;
5373
+ const {mapping: mapping, filter: filter, docId: docId, initialValue: initialValue, selectedReleaseId: selectedReleaseId, skip: skip, fetchDataset: fetchDataset} = args, {binding: binding} = useWorkflowContext(), [failed, setFailed] = react.useState(!1), rootRead = filter !== void 0 && workflowEngine.readsRootDocument(filter), candidateValue = rootRead ? initialValue : null;
5207
5374
  return react.useEffect(() => {
5208
5375
  if (skip || filter === void 0 || docId === void 0) {
5209
5376
  setFailed(!1);
@@ -5217,57 +5384,112 @@ function useFilterVerdict(args) {
5217
5384
  candidateValue: candidateValue,
5218
5385
  selectedReleaseId: selectedReleaseId,
5219
5386
  scope: preflightScope({
5220
- engine: engine,
5221
5387
  tag: binding.tag,
5222
5388
  mapping: mapping,
5223
5389
  contentResource: binding.contentResource,
5224
- docId: docId
5390
+ docId: docId,
5391
+ fetchDataset: fetchDataset
5225
5392
  })
5226
5393
  }).catch(showRowOnError("start.filter", mapping)).then(verdict => {
5227
5394
  cancelled || setFailed(verdict);
5228
5395
  }), () => {
5229
5396
  cancelled = !0;
5230
5397
  };
5231
- }, [ filter, rootRead, skip, docId, selectedReleaseId, candidateValue, mapping, engine, binding ]),
5398
+ }, [ filter, rootRead, skip, docId, selectedReleaseId, candidateValue, mapping, binding, fetchDataset ]),
5232
5399
  failed;
5233
5400
  }
5234
5401
 
5235
- function useAllowedVerdict(args) {
5236
- const {mapping: mapping, allowed: allowed, docId: docId, selectedReleaseId: selectedReleaseId, skip: skip} = args, {engine: engine, binding: binding, mappingFields: mappingFields} = useWorkflowContext(), [refused, setRefused] = react.useState(!1);
5402
+ function preflightSeedFields(args) {
5403
+ const ctx = {
5404
+ mapping: args.mapping,
5405
+ subjectDocId: args.docId,
5406
+ selectedReleaseId: args.selectedReleaseId,
5407
+ contentResource: args.contentResource,
5408
+ declaredFields: args.declaredFields
5409
+ };
5410
+ return Object.fromEntries(buildStartFields({
5411
+ ctx: ctx,
5412
+ initFields: [],
5413
+ values: {}
5414
+ }).map(field => [ field.name, field.value ]));
5415
+ }
5416
+
5417
+ function useGroqRequirementVerdicts(args) {
5418
+ const {mapping: mapping, requirements: requirements, docId: docId, selectedReleaseId: selectedReleaseId, skip: skip, fetchDataset: fetchDataset} = args, {binding: binding, mappingFields: mappingFields} = useWorkflowContext(), [refused, setRefused] = react.useState([]);
5237
5419
  return react.useEffect(() => {
5238
- if (skip || allowed === void 0 || docId === void 0) {
5239
- setRefused(!1);
5420
+ if (skip || requirements.length === 0 || docId === void 0) {
5421
+ setRefused(current => current.length === 0 ? current : []);
5240
5422
  return;
5241
5423
  }
5242
5424
  let cancelled = !1;
5243
- const ctx = {
5425
+ const fields = preflightSeedFields({
5244
5426
  mapping: mapping,
5245
- subjectDocId: docId,
5427
+ docId: docId,
5246
5428
  selectedReleaseId: selectedReleaseId,
5247
5429
  contentResource: binding.contentResource,
5248
5430
  declaredFields: mappingFields.get(mappingKey(mapping))
5249
- }, fields = Object.fromEntries(buildStartFields({
5250
- ctx: ctx,
5251
- initFields: [],
5252
- values: {}
5253
- }).map(field => [ field.name, field.value ]));
5254
- return preflightAllowed({
5255
- allowed: allowed,
5431
+ }), scope = preflightScope({
5432
+ tag: binding.tag,
5256
5433
  mapping: mapping,
5257
- fields: fields,
5434
+ contentResource: binding.contentResource,
5435
+ docId: docId,
5436
+ fetchDataset: fetchDataset
5437
+ });
5438
+ return Promise.all(requirements.map(async requirement => ({
5439
+ name: requirement.name,
5440
+ refused: await preflightGroqRequirement({
5441
+ query: requirement.query,
5442
+ mapping: mapping,
5443
+ fields: fields,
5444
+ scope: scope
5445
+ }).catch(showRowOnError(`start.requirements.${requirement.name}`, mapping))
5446
+ }))).then(verdicts => {
5447
+ if (!cancelled) {
5448
+ const next = verdicts.filter(verdict => verdict.refused).map(verdict => verdict.name);
5449
+ setRefused(current => current.length === next.length && current.every((name, index) => name === next[index]) ? current : next);
5450
+ }
5451
+ }), () => {
5452
+ cancelled = !0;
5453
+ };
5454
+ }, [ requirements, skip, docId, selectedReleaseId, mapping, binding, mappingFields, fetchDataset ]),
5455
+ refused;
5456
+ }
5457
+
5458
+ function useSingleSubjectVerdict(args) {
5459
+ const {mapping: mapping, start: start, docId: docId, selectedReleaseId: selectedReleaseId, entries: entries, skip: skip} = args, {binding: binding, mappingFields: mappingFields} = useWorkflowContext(), [refused, setRefused] = react.useState(!1), dedupe = start !== void 0 && workflowEngine.hasSingleSubjectRequirement({
5460
+ start: start
5461
+ });
5462
+ return react.useEffect(() => {
5463
+ if (skip || !dedupe || start === void 0 || docId === void 0) {
5464
+ setRefused(!1);
5465
+ return;
5466
+ }
5467
+ let cancelled = !1;
5468
+ const declaredFields = mappingFields.get(mappingKey(mapping));
5469
+ return preflightSingleSubjectRequirement({
5470
+ mapping: mapping,
5471
+ start: start,
5472
+ declaredFields: declaredFields,
5473
+ fields: preflightSeedFields({
5474
+ mapping: mapping,
5475
+ docId: docId,
5476
+ selectedReleaseId: selectedReleaseId,
5477
+ contentResource: binding.contentResource,
5478
+ declaredFields: declaredFields
5479
+ }),
5258
5480
  scope: preflightScope({
5259
- engine: engine,
5260
5481
  tag: binding.tag,
5261
5482
  mapping: mapping,
5483
+ docId: docId,
5262
5484
  contentResource: binding.contentResource,
5263
- docId: docId
5485
+ fetchDataset: () => Promise.resolve(entries.map(({instance: instance}) => workflowEngine.projectStartSliceRow(instance)))
5264
5486
  })
5265
- }).catch(showRowOnError("start.allowed", mapping)).then(verdict => {
5487
+ }).catch(showRowOnError("singleSubject requirement", mapping)).then(verdict => {
5266
5488
  cancelled || setRefused(verdict);
5267
5489
  }), () => {
5268
5490
  cancelled = !0;
5269
5491
  };
5270
- }, [ allowed, skip, docId, selectedReleaseId, mapping, engine, binding, mappingFields ]),
5492
+ }, [ dedupe, start, skip, docId, selectedReleaseId, entries, mapping, binding, mappingFields ]),
5271
5493
  refused;
5272
5494
  }
5273
5495
 
@@ -5277,7 +5499,7 @@ function showRowOnError(key, mapping) {
5277
5499
  }
5278
5500
 
5279
5501
  function useStartWorkflow(args) {
5280
- const {mapping: mapping, docId: docId, initialValue: initialValue} = args, toast = useClosableToast(), {engine: engine, openStartDialog: openStartDialog, mappingIssues: mappingIssues2, mappingStarts: mappingStarts} = useWorkflowContext(), observer = workflowStudio.useStudioObserver({
5502
+ const {mapping: mapping, docId: docId, initialValue: initialValue, source: source} = args, toast = useClosableToast(), {engine: engine, openStartDialog: openStartDialog, mappingIssues: mappingIssues2, mappingStarts: mappingStarts} = useWorkflowContext(), observer = workflowStudio.useStudioObserver({
5281
5503
  engine: engine
5282
5504
  }), [starting, setStarting] = react.useState(!1), {selectedReleaseId: selectedReleaseId} = sanity.usePerspective(), releaseActive = sanity.useIsReleaseActive(), startBlock = mappingStarts.get(mappingKey(mapping)), hidden = workflowEngine.startKindOf({
5283
5505
  start: startBlock
@@ -5285,12 +5507,13 @@ function useStartWorkflow(args) {
5285
5507
  entries: entries,
5286
5508
  definitionName: mapping.definition,
5287
5509
  heldInstanceId: void 0
5288
- }) !== void 0, {filterFailed: filterFailed, allowedRefused: allowedRefused} = useStartVerdicts({
5510
+ }) !== void 0, {filterFailed: filterFailed, unmetRequirement: unmetRequirement} = useStartVerdicts({
5289
5511
  mapping: mapping,
5290
5512
  start: startBlock,
5291
5513
  docId: docId,
5292
5514
  initialValue: initialValue,
5293
5515
  selectedReleaseId: selectedReleaseId,
5516
+ entries: entries,
5294
5517
  hidden: hidden,
5295
5518
  resumable: resumable
5296
5519
  }), {blocked: blocked, tooltip: tooltip} = startGate({
@@ -5299,7 +5522,9 @@ function useStartWorkflow(args) {
5299
5522
  selectedReleaseId: selectedReleaseId,
5300
5523
  releaseActive: releaseActive,
5301
5524
  startFilterFailed: filterFailed,
5302
- startAllowedRefused: allowedRefused
5525
+ ...unmetRequirement !== void 0 ? {
5526
+ unmetRequirement: unmetRequirement
5527
+ } : {}
5303
5528
  });
5304
5529
  return {
5305
5530
  blocked: blocked,
@@ -5321,7 +5546,10 @@ function useStartWorkflow(args) {
5321
5546
  title: "Could not persist the document before starting",
5322
5547
  description: describeError(err)
5323
5548
  }),
5324
- openStartDialog: openStartDialog
5549
+ openStartDialog: request => openStartDialog({
5550
+ ...request,
5551
+ source: source
5552
+ })
5325
5553
  });
5326
5554
  } finally {
5327
5555
  setStarting(!1);
@@ -5331,11 +5559,12 @@ function useStartWorkflow(args) {
5331
5559
  };
5332
5560
  }
5333
5561
 
5334
- function StartWorkflowButton({mapping: mapping, docId: docId, initialValue: initialValue, mode: mode = "default", label: label, iconOnly: iconOnly = !1, tone: tone = "primary"}) {
5562
+ function StartWorkflowButton({mapping: mapping, docId: docId, initialValue: initialValue, source: source, mode: mode = "default", label: label, iconOnly: iconOnly = !1, tone: tone = "primary"}) {
5335
5563
  const {blocked: blocked, tooltip: tooltip, hidden: hidden, starting: starting, start: start} = useStartWorkflow({
5336
5564
  mapping: mapping,
5337
5565
  docId: docId,
5338
- initialValue: initialValue
5566
+ initialValue: initialValue,
5567
+ source: source
5339
5568
  });
5340
5569
  if (hidden) return null;
5341
5570
  const startLabel = label ?? `Start ${mapping.label}`, button = /* @__PURE__ */ jsxRuntime.jsx(ui.Button, {
@@ -5368,7 +5597,7 @@ function useStartableMappings(mappings) {
5368
5597
  }) !== "autonomous");
5369
5598
  }
5370
5599
 
5371
- function StartWorkflowControl({mappings: mappings, docId: docId, initialValue: initialValue, label: label, iconOnly: iconOnly = !1, mode: mode = "default", tone: tone = "primary"}) {
5600
+ function StartWorkflowControl({mappings: mappings, docId: docId, initialValue: initialValue, source: source, label: label, iconOnly: iconOnly = !1, mode: mode = "default", tone: tone = "primary"}) {
5372
5601
  const menuId = react.useId(), startable = useStartableMappings(mappings), [first] = startable;
5373
5602
  if (first === void 0) return null;
5374
5603
  if (startable.length === 1) /* @__PURE__ */
@@ -5381,6 +5610,7 @@ function StartWorkflowControl({mappings: mappings, docId: docId, initialValue: i
5381
5610
  },
5382
5611
  mapping: first,
5383
5612
  mode: mode,
5613
+ source: source,
5384
5614
  tone: tone
5385
5615
  });
5386
5616
  const menuLabel = label ?? "Start a workflow";
@@ -5406,7 +5636,8 @@ function StartWorkflowControl({mappings: mappings, docId: docId, initialValue: i
5406
5636
  children: startable.map(mapping => /* @__PURE__ */ jsxRuntime.jsx(StartWorkflowMenuItem, {
5407
5637
  docId: docId,
5408
5638
  initialValue: initialValue,
5409
- mapping: mapping
5639
+ mapping: mapping,
5640
+ source: source
5410
5641
  }, mappingKey(mapping)))
5411
5642
  }),
5412
5643
  popover: {
@@ -5417,11 +5648,12 @@ function StartWorkflowControl({mappings: mappings, docId: docId, initialValue: i
5417
5648
  });
5418
5649
  }
5419
5650
 
5420
- function StartWorkflowMenuItem({mapping: mapping, docId: docId, initialValue: initialValue}) {
5651
+ function StartWorkflowMenuItem({mapping: mapping, docId: docId, initialValue: initialValue, source: source}) {
5421
5652
  const {blocked: blocked, tooltip: tooltip, starting: starting, start: start} = useStartWorkflow({
5422
5653
  mapping: mapping,
5423
5654
  docId: docId,
5424
- initialValue: initialValue
5655
+ initialValue: initialValue,
5656
+ source: source
5425
5657
  }), item = /* @__PURE__ */ jsxRuntime.jsx(ui.MenuItem, {
5426
5658
  disabled: blocked || starting || !docId,
5427
5659
  onClick: () => {
@@ -5476,13 +5708,15 @@ function RowTerminalActions({actions: actions, activity: activity, instanceId: i
5476
5708
  mode: "ghost",
5477
5709
  inButtonCard: !0
5478
5710
  },
5479
- instanceId: instanceId
5711
+ instanceId: instanceId,
5712
+ surface: "inline-row"
5480
5713
  }) : /* @__PURE__ */ jsxRuntime.jsx(ActionsMenuButton, {
5481
5714
  actions: actions,
5482
5715
  activity: activity,
5483
5716
  inButtonCard: !0,
5484
5717
  instanceId: instanceId,
5485
- label: "Select action"
5718
+ label: "Select action",
5719
+ surface: "inline-row"
5486
5720
  })
5487
5721
  }) : null;
5488
5722
  }
@@ -5580,7 +5814,8 @@ function ForMeList({entry: entry, work: work, identity: identity, onOpenActivity
5580
5814
  filter: {
5581
5815
  kind: "mine",
5582
5816
  identity: identity
5583
- }
5817
+ },
5818
+ surface: "document-view-for-me"
5584
5819
  }) : null ]
5585
5820
  })
5586
5821
  });
@@ -5789,7 +6024,8 @@ function TodoFieldDialog({entry: entry, scope: scope, field: field, title: title
5789
6024
  kind: "field",
5790
6025
  scope: scope,
5791
6026
  field: field
5792
- }
6027
+ },
6028
+ surface: "todo-field-dialog"
5793
6029
  })
5794
6030
  })
5795
6031
  });
@@ -6002,7 +6238,7 @@ function PillButton({children: children, pill: pill, hintDisabled: hintDisabled
6002
6238
  }
6003
6239
 
6004
6240
  function useFieldCommit({entry: entry, editability: editability}) {
6005
- const {editFieldFor: editFieldFor} = useWorkflowContext(), target = editTargetOf(editability);
6241
+ const {editFieldFor: editFieldFor} = useWorkflowContext(), target = workflowReact.editFieldTarget(editability);
6006
6242
  return {
6007
6243
  set: value => editFieldFor(entry.instance._id, {
6008
6244
  target: target,
@@ -6218,8 +6454,9 @@ function AssigneePill({entry: entry, pill: pill, editability: editability}) {
6218
6454
  /* @__PURE__ */
6219
6455
  return jsxRuntime.jsx(PillPopover, {
6220
6456
  content: /* @__PURE__ */ jsxRuntime.jsx(AssigneePicker, {
6221
- onToggle: assignee => {
6222
- setOpen(!1), pick(assignee);
6457
+ onChange: next => {
6458
+ const changed = changedAssignee(current ? [ current ] : [], next);
6459
+ changed && (setOpen(!1), pick(changed));
6223
6460
  },
6224
6461
  value: current ? [ current ] : []
6225
6462
  }),
@@ -6238,10 +6475,8 @@ function AssigneesPill({entry: entry, pill: pill, editability: editability}) {
6238
6475
  /* @__PURE__ */
6239
6476
  return jsxRuntime.jsx(PillPopover, {
6240
6477
  content: /* @__PURE__ */ jsxRuntime.jsx(AssigneePicker, {
6241
- onToggle: assignee => {
6242
- if (saving) return;
6243
- const next = current.some(a => sameAssignee(a, assignee)) ? current.filter(a => !sameAssignee(a, assignee)) : [ ...current, assignee ];
6244
- save(() => set(next));
6478
+ onChange: next => {
6479
+ saving || save(() => set(next));
6245
6480
  },
6246
6481
  value: current
6247
6482
  }),
@@ -6346,15 +6581,15 @@ function Hairline({weight: weight, style: style}) {
6346
6581
  });
6347
6582
  }
6348
6583
 
6349
- function CollapsibleBand({header: header, children: children, background: background = !1, defaultOpen: defaultOpen = !0, sticky: sticky = !1, title: title}) {
6350
- const [open, setOpen] = react.useState(defaultOpen), verb = open ? "Collapse" : "Expand";
6584
+ function CollapsibleBand({header: header, children: children, background: background = !1, defaultOpen: defaultOpen = !0, onToggle: onToggle, open: controlledOpen, sticky: sticky = !1, title: title}) {
6585
+ const [heldOpen, setHeldOpen] = react.useState(defaultOpen), open = controlledOpen ?? heldOpen, toggle = onToggle ?? (() => setHeldOpen(value => !value)), verb = open ? "Collapse" : "Expand";
6351
6586
  /* @__PURE__ */
6352
6587
  return jsxRuntime.jsxs(ui.Stack, {
6353
6588
  gap: 1,
6354
6589
  children: [
6355
6590
  /* @__PURE__ */ jsxRuntime.jsx(ui.Card, {
6356
6591
  onDoubleClick: event => {
6357
- event.target instanceof Element && event.target.closest("a, button") || setOpen(v => !v);
6592
+ event.target instanceof Element && event.target.closest("a, button") || toggle();
6358
6593
  },
6359
6594
  padding: 1,
6360
6595
  radius: 3,
@@ -6375,7 +6610,7 @@ function CollapsibleBand({header: header, children: children, background: backgr
6375
6610
  fontSize: 1,
6376
6611
  icon: open ? ChevronDown.ChevronDownIcon : ChevronRight.ChevronRightIcon,
6377
6612
  mode: "bleed",
6378
- onClick: () => setOpen(v => !v),
6613
+ onClick: toggle,
6379
6614
  padding: 2
6380
6615
  }), header ]
6381
6616
  })
@@ -7286,7 +7521,12 @@ function StageSection({entry: entry, onOpenActivity: onOpenActivity}) {
7286
7521
  }
7287
7522
 
7288
7523
  const VIEW_TAB_CODEC = workflowsTabCodec([ "overview", "for-me" ]), WorkflowsView = props => {
7289
- const {documentId: documentId, schemaType: schemaType} = props, {isDocResolved: isDocResolved, mappings: mappings, discoveryInvalid: discoveryInvalid} = useWorkflowContext(), {entries: entries} = useWorkflowsForDocument(documentId), resolved = isDocResolved(documentId), docTypeMappings = mappingsForDocType(mappings, schemaType.name);
7524
+ const {documentId: documentId, schemaType: schemaType} = props, {isDocResolved: isDocResolved, mappings: mappings, discoveryInvalid: discoveryInvalid} = useWorkflowContext(), {entries: entries} = useWorkflowsForDocument(documentId), {view: view} = useWorkflowsTab();
7525
+ useLogEventOnMount(WorkflowDocumentViewOpened, {
7526
+ tab: view,
7527
+ via: "open"
7528
+ });
7529
+ const resolved = isDocResolved(documentId), docTypeMappings = mappingsForDocType(mappings, schemaType.name);
7290
7530
  if (entries.length === 0) return discoveryInvalid !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Box, {
7291
7531
  padding: 4,
7292
7532
  children: /* @__PURE__ */ jsxRuntime.jsx(InvalidDocNotice, {
@@ -7364,7 +7604,7 @@ function useOpenActivity(entries) {
7364
7604
  }
7365
7605
 
7366
7606
  function WorkflowsPanel({entries: entries, documentId: documentId, docTypeMappings: docTypeMappings, initialValue: initialValue}) {
7367
- const identity = useAssignmentIdentity(), panelId = react.useId(), {params: params} = structure.usePaneRouter(), {view: view, setView: setView} = useWorkflowsTab(), {openActivity: openActivity, setOpenActivity: setOpenActivity, dialogEntry: dialogEntry} = useOpenActivity(entries), active = entries.filter(isLiveEntry), finished = entries.filter(e => !isLiveEntry(e)), forMe = forMeWorkOf(active, identity), [landing] = react.useState(() => focusedLanding(params?.[WORKFLOWS_FOCUS_PARAM], entries.map(e => e.instance._id))), assignedWorkUnknown = active.some(e => e.invalid !== void 0), booting = useDelayedFlag(active.some(e => !e.ready && e.invalid === void 0), BOOT_CUE_DELAY_MS), sectionFor = e => /* @__PURE__ */ jsxRuntime.jsx(WorkflowInstanceSection, {
7607
+ const identity = useAssignmentIdentity(), panelId = react.useId(), {params: params} = structure.usePaneRouter(), {view: view, setView: setView} = useWorkflowsTab(), telemetry2 = workflowReact.useWorkflowTelemetry(), {openActivity: openActivity, setOpenActivity: setOpenActivity, dialogEntry: dialogEntry} = useOpenActivity(entries), active = entries.filter(isLiveEntry), finished = entries.filter(e => !isLiveEntry(e)), forMe = forMeWorkOf(active, identity), [landing] = react.useState(() => focusedLanding(params?.[WORKFLOWS_FOCUS_PARAM], entries.map(e => e.instance._id))), assignedWorkUnknown = active.some(e => e.invalid !== void 0), booting = useDelayedFlag(active.some(e => !e.ready && e.invalid === void 0), BOOT_CUE_DELAY_MS), sectionFor = e => /* @__PURE__ */ jsxRuntime.jsx(WorkflowInstanceSection, {
7368
7608
  defaultOpen: landingDefaultOpen(landing, e.instance._id),
7369
7609
  entry: e,
7370
7610
  onOpenActivity: activityName => setOpenActivity({
@@ -7398,6 +7638,7 @@ function WorkflowsPanel({entries: entries, documentId: documentId, docTypeMappin
7398
7638
  initialValue: initialValue,
7399
7639
  mappings: docTypeMappings,
7400
7640
  mode: "bleed",
7641
+ source: "document-view-header",
7401
7642
  tone: "default"
7402
7643
  })
7403
7644
  }),
@@ -7406,7 +7647,12 @@ function WorkflowsPanel({entries: entries, documentId: documentId, docTypeMappin
7406
7647
  /* @__PURE__ */ jsxRuntime.jsx(TabSwitch, {
7407
7648
  ariaControls: `${panelId}-panel`,
7408
7649
  idPrefix: panelId,
7409
- onSelect: setView,
7650
+ onSelect: next => {
7651
+ next !== view && telemetry2.log(WorkflowDocumentViewOpened, {
7652
+ tab: next,
7653
+ via: "tab-switch"
7654
+ }), setView(next);
7655
+ },
7410
7656
  options: [ {
7411
7657
  value: "overview",
7412
7658
  label: "Overview"
@@ -7480,6 +7726,7 @@ function OverviewEmptyState({mappings: mappings, docId: docId, initialValue: ini
7480
7726
  label: "Start workflow",
7481
7727
  mappings: mappings,
7482
7728
  mode: "ghost",
7729
+ source: "document-view-empty-state",
7483
7730
  tone: "default"
7484
7731
  })
7485
7732
  },
@@ -7513,7 +7760,8 @@ function SectionActivityDialog({entry: entry, activityName: activityName, onClos
7513
7760
  breadcrumb: instanceBreadcrumb(instance, definition),
7514
7761
  definition: definition,
7515
7762
  entry: entry,
7516
- onClose: onClose
7763
+ onClose: onClose,
7764
+ source: "document-view"
7517
7765
  });
7518
7766
  }
7519
7767
 
@@ -7595,13 +7843,61 @@ function workflowIssue(args) {
7595
7843
  if (!workflowEngine.isInputSourced(subject)) return `autoStart: "${docType}" → workflow "${name}" has a self-filling subject (not caller-provided), so the document can't be its subject — skipped.`;
7596
7844
  }
7597
7845
 
7846
+ function actualType$(previews, bareId) {
7847
+ return previews.unstable_observeDocumentPairAvailability(bareId).pipe(operators.switchMap(({draft: draft, published: published}) => draft.available ? previews.observeDocumentTypeFromId(csm.getDraftId(bareId)) : published.available ? previews.observeDocumentTypeFromId(bareId) : draft.reason === "PERMISSION_DENIED" || published.reason === "PERMISSION_DENIED" ? rxjs.of(void 0) : previews.unstable_observeVersionDocumentIds(bareId).pipe(operators.switchMap(([firstVersionId]) => firstVersionId === void 0 ? rxjs.of(null) : previews.observeDocumentTypeFromId(firstVersionId)))), operators.distinctUntilChanged());
7848
+ }
7849
+
7850
+ const REBUILD_DELAY_MS = 5e3;
7851
+
7852
+ function createActualTypeProbeStore(previews) {
7853
+ const verdicts = /* @__PURE__ */ new Map, live = /* @__PURE__ */ new Map, listeners = /* @__PURE__ */ new Set, notify = () => {
7854
+ for (const listener of [ ...listeners ]) listener();
7855
+ }, start = (bareId, entry) => actualType$(previews, bareId).subscribe({
7856
+ next: value => {
7857
+ verdicts.has(bareId) && verdicts.get(bareId) === value || (verdicts.set(bareId, value),
7858
+ notify());
7859
+ },
7860
+ error: err => {
7861
+ console.error(`[workflow-studio-plugin] actual-type probe for "${bareId}" failed:`, err),
7862
+ entry.subscription = void 0, entry.rebuildTimer = setTimeout(() => {
7863
+ entry.rebuildTimer = void 0, !(live.get(bareId) !== entry || entry.count === 0) && (entry.subscription = start(bareId, entry));
7864
+ }, REBUILD_DELAY_MS);
7865
+ }
7866
+ });
7867
+ return {
7868
+ subscribe(listener) {
7869
+ return listeners.add(listener), () => {
7870
+ listeners.delete(listener);
7871
+ };
7872
+ },
7873
+ read: bareId => verdicts.get(bareId),
7874
+ track(bareId) {
7875
+ let entry = live.get(bareId);
7876
+ if (entry === void 0) {
7877
+ const created = {
7878
+ count: 0,
7879
+ subscription: void 0,
7880
+ rebuildTimer: void 0
7881
+ };
7882
+ live.set(bareId, created), created.subscription = start(bareId, created), entry = created;
7883
+ }
7884
+ entry.count += 1;
7885
+ let released = !1;
7886
+ return () => {
7887
+ released || (released = !0, entry.count -= 1, !(entry.count > 0) && (entry.subscription?.unsubscribe(),
7888
+ entry.rebuildTimer !== void 0 && clearTimeout(entry.rebuildTimer), live.get(bareId) === entry && live.delete(bareId)));
7889
+ };
7890
+ }
7891
+ };
7892
+ }
7893
+
7598
7894
  function contentDocumentTypes(schema) {
7599
7895
  return schema.getTypeNames().filter(name => schema.get(name)?.type?.name === "document" && !WORKFLOW_SYSTEM_TYPES.includes(name));
7600
7896
  }
7601
7897
 
7602
7898
  async function readDeployedDefinitions(engine) {
7603
7899
  return (await engine.query({
7604
- groq: workflowEngine.definitionsListGroq("desc")
7900
+ groq: workflowEngine.latestDefinitionsGroq()
7605
7901
  })).map(workflowEngine.assertReadableModel);
7606
7902
  }
7607
7903
 
@@ -7936,7 +8232,7 @@ function WorkflowProvider(props) {
7936
8232
  setSeeded(prev => new Map(prev).set(instance._id, instance));
7937
8233
  }, []), [startRequest2, setStartRequest] = react.useState(void 0), openStartDialog = react.useCallback(r => setStartRequest(r), []), closeStartDialog = react.useCallback(() => setStartRequest(void 0), []), [entriesStore] = react.useState(createEntriesStore);
7938
8234
  react.useEffect(() => () => entriesStore.dispose(), [ entriesStore ]);
7939
- const onReport = react.useCallback((instanceId, report) => {
8235
+ const previewStore = sanity.useDocumentPreviewStore(), actualTypes = react.useMemo(() => createActualTypeProbeStore(previewStore), [ previewStore ]), onReport = react.useCallback((instanceId, report) => {
7940
8236
  entriesStore.report(instanceId, report);
7941
8237
  }, [ entriesStore ]), drainRef = react.useRef(void 0), drainCommitted = react.useCallback(async instanceId => {
7942
8238
  try {
@@ -8019,6 +8315,7 @@ function WorkflowProvider(props) {
8019
8315
  unregister: unregister,
8020
8316
  isDocResolved: isDocResolved,
8021
8317
  entries: entriesStore,
8318
+ actualTypes: actualTypes,
8022
8319
  requestInstance: requestInstance,
8023
8320
  releaseInstance: releaseInstance,
8024
8321
  requestEvaluation: requestEvaluation,
@@ -8045,7 +8342,7 @@ function WorkflowProvider(props) {
8045
8342
  effectHandlers: engine.effectHandlers,
8046
8343
  autoStartByType: autoStartByType,
8047
8344
  autoStartDefinitions: autoStartDefinitions
8048
- }), [ register, unregister, isDocResolved, entriesStore, requestInstance, releaseInstance, requestEvaluation, releaseEvaluation, seedInstance, openStartDialog, closeStartDialog, startRequest2, loading, discoveryInvalid, fireActionFor, editFieldFor, previewFieldFor, discardFieldPreviewFor, drainEffectsFor, completeEffectFor, engine, binding, mappings, issues, starts, fields, latestVersions, autoStartByType, autoStartDefinitions ]);
8345
+ }), [ register, unregister, isDocResolved, entriesStore, actualTypes, requestInstance, releaseInstance, requestEvaluation, releaseEvaluation, seedInstance, openStartDialog, closeStartDialog, startRequest2, loading, discoveryInvalid, fireActionFor, editFieldFor, previewFieldFor, discardFieldPreviewFor, drainEffectsFor, completeEffectFor, engine, binding, mappings, issues, starts, fields, latestVersions, autoStartByType, autoStartDefinitions ]);
8049
8346
  /* @__PURE__ */
8050
8347
  return jsxRuntime.jsxs(WorkflowContext.Provider, {
8051
8348
  value: value,
@@ -8145,13 +8442,13 @@ function logOnce(messages, logged) {
8145
8442
 
8146
8443
  function AssigneesInput({value: value, onChange: onChange}) {
8147
8444
  const {members: members} = useProjectMembers(), [membersOpen, setMembersOpen] = react.useState(!1), roles = react.useMemo(() => [ ...new Set(members.flatMap(m => m.roles)) ].toSorted(), [ members ]), userIds = react.useMemo(() => new Set(value.flatMap(a => a.type === "user" ? [ a.id ] : [])), [ value ]), add = a => {
8148
- value.some(x => sameAssignee(x, a)) || onChange([ ...value, a ]);
8445
+ value.some(x => workflowComponents.sameAssignee(x, a)) || onChange([ ...value, a ]);
8149
8446
  }, remove = i => onChange(value.filter((_, idx) => idx !== i)), toggleUser = id => {
8150
8447
  const user = {
8151
8448
  type: "user",
8152
8449
  id: id
8153
8450
  };
8154
- userIds.has(id) ? onChange(value.filter(a => !sameAssignee(a, user))) : add(user);
8451
+ userIds.has(id) ? onChange(value.filter(a => !workflowComponents.sameAssignee(a, user))) : add(user);
8155
8452
  };
8156
8453
  /* @__PURE__ */
8157
8454
  return jsxRuntime.jsxs(ui.Stack, {
@@ -8518,12 +8815,12 @@ function DocRefsFieldInput({entry: entry, mappedType: mappedType, value: value,
8518
8815
  }
8519
8816
 
8520
8817
  function NotesStartInput({onChange: onChange}) {
8521
- const me = sanity.useCurrentUser(), [body, setBody] = react.useState(""), update = next => {
8818
+ const selfActor = useSelfActor(), [body, setBody] = react.useState(""), update = next => {
8522
8819
  setBody(next);
8523
8820
  const trimmed = next.trim();
8524
8821
  onChange(trimmed === "" ? [] : [ noteRow({
8525
8822
  body: trimmed,
8526
- actor: me ? personActor(me) : void 0,
8823
+ actor: selfActor,
8527
8824
  at: /* @__PURE__ */ (new Date).toISOString()
8528
8825
  }) ]);
8529
8826
  };
@@ -8732,7 +9029,7 @@ function handleStartError(args) {
8732
9029
  toast.push({
8733
9030
  status: "warning",
8734
9031
  title: `${label} can't be started right now`,
8735
- description: "The workflow does not allow another run with these inputs."
9032
+ description: outcome.description
8736
9033
  });
8737
9034
  return;
8738
9035
  }
@@ -8744,7 +9041,7 @@ function handleStartError(args) {
8744
9041
  }
8745
9042
 
8746
9043
  function StartWorkflowForm({request: request, onClose: onClose}) {
8747
- const {definition: definitionName, label: label, mapping: mapping, subjectDocId: subjectDocId} = request, {engine: engine, binding: binding, seedInstance: seedInstance} = useWorkflowContext(), toast = useClosableToast(), {def: definition, error: definitionError} = useLatestDefinition(definitionName), {selectedReleaseId: selectedReleaseId} = sanity.usePerspective(), releaseId = boundReleaseId(mapping, selectedReleaseId), [values, setValues] = react.useState({}), [attempt, setAttempt] = react.useState(void 0), starting = attempt !== void 0, [heldInstanceId, setHeldInstanceId] = react.useState(void 0), [startNew, setStartNew] = react.useState(!1), {entries: entries} = useWorkflowsForDocument(subjectDocId), resumeEntry = presentedResumeEntry({
9044
+ const {definition: definitionName, label: label, mapping: mapping, subjectDocId: subjectDocId} = request, {engine: engine, binding: binding, seedInstance: seedInstance} = useWorkflowContext(), telemetry2 = workflowReact.useWorkflowTelemetry(), toast = useClosableToast(), {def: definition, error: definitionError} = useLatestDefinition(definitionName), {selectedReleaseId: selectedReleaseId} = sanity.usePerspective(), releaseId = boundReleaseId(mapping, selectedReleaseId), [values, setValues] = react.useState({}), [attempt, setAttempt] = react.useState(void 0), starting = attempt !== void 0, [heldInstanceId, setHeldInstanceId] = react.useState(void 0), [startNew, setStartNew] = react.useState(!1), {entries: entries} = useWorkflowsForDocument(subjectDocId), resumeEntry = presentedResumeEntry({
8748
9045
  entries: entries,
8749
9046
  definitionName: definitionName,
8750
9047
  heldInstanceId: heldInstanceId,
@@ -8767,7 +9064,10 @@ function StartWorkflowForm({request: request, onClose: onClose}) {
8767
9064
  [name]: v
8768
9065
  })), heldInstanceId !== void 0 && declineResume();
8769
9066
  }, onStart = async () => {
8770
- setAttempt({
9067
+ telemetry2.log(WorkflowStartDialogSubmitted, {
9068
+ source: request.source,
9069
+ resumed: resuming
9070
+ }), setAttempt({
8771
9071
  resume: resumeEntry
8772
9072
  });
8773
9073
  const instanceId = resumeEntry?.instance._id ?? heldInstanceId ?? workflowEngine.instanceDocId(binding.tag);
@@ -8847,8 +9147,9 @@ function StartWorkflowForm({request: request, onClose: onClose}) {
8847
9147
  }
8848
9148
 
8849
9149
  function StartWorkflowDialog({request: request, onClose: onClose}) {
8850
- /* @__PURE__ */
8851
- return jsxRuntime.jsx(ui.Dialog, {
9150
+ return useLogEventOnMount(WorkflowStartDialogOpened, {
9151
+ source: request.source
9152
+ }), /* @__PURE__ */ jsxRuntime.jsx(ui.Dialog, {
8852
9153
  header: `Start ${request.label}`,
8853
9154
  id: "start-workflow",
8854
9155
  onClose: onClose,
@@ -8987,7 +9288,7 @@ function AutoStartGate(props) {
8987
9288
  }
8988
9289
 
8989
9290
  function AutoStartDriver(props) {
8990
- const {rawDocId: rawDocId, docType: docType, workflows: workflows, value: value, fallback: fallback} = props, {isDocResolved: isDocResolved, autoStartDefinitions: autoStartDefinitions, engine: engine, binding: binding, seedInstance: seedInstance} = useWorkflowContext(), observer = workflowStudio.useStudioObserver({
9291
+ const {rawDocId: rawDocId, docType: docType, workflows: workflows, value: value, fallback: fallback} = props, {isDocResolved: isDocResolved, autoStartDefinitions: autoStartDefinitions, engine: engine, binding: binding, seedInstance: seedInstance} = useWorkflowContext(), telemetry2 = workflowReact.useWorkflowTelemetry(), observer = workflowStudio.useStudioObserver({
8991
9292
  engine: engine
8992
9293
  }), {selectedReleaseId: selectedReleaseId} = sanity.usePerspective(), {entries: entries} = useWorkflowsForDocument(rawDocId), docId = csm.getPublishedId(rawDocId), valueRef = react.useRef(value);
8993
9294
  valueRef.current = value;
@@ -9001,7 +9302,7 @@ function AutoStartDriver(props) {
9001
9302
  if (held !== void 0) return held;
9002
9303
  const id = workflowEngine.instanceDocId(binding.tag);
9003
9304
  return instanceIds.current.set(workflow, id), id;
9004
- }, [ binding.tag ]), [fired, setFired] = react.useState(!1), [settled, setSettled] = react.useState(!1), [failure, setFailure] = react.useState(void 0), firedRef = react.useRef(!1), startAll = react.useCallback(async values => {
9305
+ }, [ binding.tag ]), [fired, setFired] = react.useState(!1), [settled, setSettled] = react.useState(!1), [failure, setFailure] = react.useState(void 0), firedRef = react.useRef(!1), startAll = react.useCallback(async (values, mode) => {
9005
9306
  if (!firedRef.current) {
9006
9307
  firedRef.current = !0, setFired(!0);
9007
9308
  try {
@@ -9013,20 +9314,25 @@ function AutoStartDriver(props) {
9013
9314
  releaseId: selectedReleaseId
9014
9315
  } : {}
9015
9316
  });
9317
+ const requests = buildAutoStartRequests({
9318
+ workflows: pendingRef.current,
9319
+ definitions: autoStartDefinitions,
9320
+ subject: {
9321
+ docId: docId,
9322
+ type: docType
9323
+ },
9324
+ contentResource: binding.contentResource,
9325
+ values: values,
9326
+ instanceIdFor: instanceIdFor
9327
+ });
9328
+ telemetry2.log(WorkflowAutoStartRan, {
9329
+ mode: mode,
9330
+ workflowCount: requests.length
9331
+ });
9016
9332
  const {failure: failure2} = await runStarts({
9017
9333
  engine: engine,
9018
9334
  seed: seedInstance,
9019
- requests: buildAutoStartRequests({
9020
- workflows: pendingRef.current,
9021
- definitions: autoStartDefinitions,
9022
- subject: {
9023
- docId: docId,
9024
- type: docType
9025
- },
9026
- contentResource: binding.contentResource,
9027
- values: values,
9028
- instanceIdFor: instanceIdFor
9029
- })
9335
+ requests: requests
9030
9336
  });
9031
9337
  failure2 !== void 0 && setFailure(failure2);
9032
9338
  } catch (err) {
@@ -9035,7 +9341,7 @@ function AutoStartDriver(props) {
9035
9341
  setSettled(!0);
9036
9342
  }
9037
9343
  }
9038
- }, [ autoStartDefinitions, docId, docType, binding, engine, observer, seedInstance, instanceIdFor, selectedReleaseId ]), retry = react.useCallback(() => {
9344
+ }, [ autoStartDefinitions, docId, docType, binding, engine, observer, seedInstance, instanceIdFor, selectedReleaseId, telemetry2 ]), retry = react.useCallback(() => {
9039
9345
  firedRef.current = !1, setFired(!1), setSettled(!1), setFailure(void 0);
9040
9346
  }, []), action = autoStartAction({
9041
9347
  resolved: definitionsResolved && isDocResolved(docId),
@@ -9045,7 +9351,7 @@ function AutoStartDriver(props) {
9045
9351
  settled: settled
9046
9352
  });
9047
9353
  return react.useEffect(() => {
9048
- action === "silent-start" && startAll({});
9354
+ action === "silent-start" && startAll({}, "silent");
9049
9355
  }, [ action, startAll ]), failure !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(AutoStartFailure, {
9050
9356
  message: failure,
9051
9357
  onProceed: () => setFailure(void 0),
@@ -9057,7 +9363,7 @@ function AutoStartDriver(props) {
9057
9363
  docType: docType,
9058
9364
  inputs: inputs,
9059
9365
  onStart: values => {
9060
- startAll(values);
9366
+ startAll(values, "collect");
9061
9367
  },
9062
9368
  starting: fired,
9063
9369
  workflowCount: pending.length
@@ -9279,7 +9585,9 @@ function finishedLinesOf(entries) {
9279
9585
  }
9280
9586
 
9281
9587
  function WorkflowFormStrip(props) {
9282
- const {mappings: mappings} = props, {isDocResolved: isDocResolved, discoveryInvalid: discoveryInvalid} = useWorkflowContext(), {docId: docId, entries: entries} = useWorkflowsForDocument(props.value?._id ?? null), {params: params, setParams: setParams} = structure.usePaneRouter(), openWorkflowsView = focusId => setParams(focusedViewParams(params, focusId)), active = entries.filter(isLiveEntry), finished = finishedLinesOf(entries), invalid = surfacedInvalid(discoveryInvalid, entries), resolved = docId !== void 0 && isDocResolved(docId);
9588
+ const {mappings: mappings} = props, {isDocResolved: isDocResolved, discoveryInvalid: discoveryInvalid} = useWorkflowContext(), {docId: docId, entries: entries} = useWorkflowsForDocument(props.value?._id ?? null), {params: params, setParams: setParams} = structure.usePaneRouter(), telemetry2 = workflowReact.useWorkflowTelemetry(), openWorkflowsView = focusId => {
9589
+ telemetry2.log(WorkflowFormStripClicked), setParams(focusedViewParams(params, focusId));
9590
+ }, active = entries.filter(isLiveEntry), finished = finishedLinesOf(entries), invalid = surfacedInvalid(discoveryInvalid, entries), resolved = docId !== void 0 && isDocResolved(docId);
9283
9591
  /* @__PURE__ */
9284
9592
  return jsxRuntime.jsxs(ui.Stack, {
9285
9593
  gap: 4,
@@ -9313,7 +9621,8 @@ function StripLines({active: active, docId: docId, finished: finished, initialVa
9313
9621
  initialValue: initialValue,
9314
9622
  label: "Start workflow",
9315
9623
  mappings: mappings,
9316
- mode: "bleed"
9624
+ mode: "bleed",
9625
+ source: "form-strip"
9317
9626
  })
9318
9627
  }) : null ]
9319
9628
  });
@@ -9645,6 +9954,8 @@ exports.ActivityRow = ActivityRow;
9645
9954
 
9646
9955
  exports.BreadcrumbTail = BreadcrumbTail;
9647
9956
 
9957
+ exports.CautionNote = CautionNote;
9958
+
9648
9959
  exports.CollapsibleBand = CollapsibleBand;
9649
9960
 
9650
9961
  exports.DismissablePopover = DismissablePopover;
@@ -9679,6 +9990,14 @@ exports.TrailingHairline = TrailingHairline;
9679
9990
 
9680
9991
  exports.UnreadableDocsNote = UnreadableDocsNote;
9681
9992
 
9993
+ exports.WORKFLOW_API_VERSION = WORKFLOW_API_VERSION;
9994
+
9995
+ exports.WorkflowInstanceDetailViewed = WorkflowInstanceDetailViewed;
9996
+
9997
+ exports.WorkflowTaskFiltersApplied = WorkflowTaskFiltersApplied;
9998
+
9999
+ exports.WorkflowToolOpened = WorkflowToolOpened;
10000
+
9682
10001
  exports.activityRowProps = activityRowProps;
9683
10002
 
9684
10003
  exports.assigneeUserIdsOf = assigneeUserIdsOf;
@@ -9693,8 +10012,6 @@ exports.definitionSnapshotOf = definitionSnapshotOf;
9693
10012
 
9694
10013
  exports.describeError = describeError;
9695
10014
 
9696
- exports.editTargetOf = editTargetOf;
9697
-
9698
10015
  exports.findActivity = findActivity;
9699
10016
 
9700
10017
  exports.findActivityNode = findActivityNode;
@@ -9739,8 +10056,12 @@ exports.stopRowMouseDown = stopRowMouseDown;
9739
10056
 
9740
10057
  exports.useAssignmentIdentity = useAssignmentIdentity;
9741
10058
 
10059
+ exports.useClosableToast = useClosableToast;
10060
+
9742
10061
  exports.useDefinition = useDefinition;
9743
10062
 
10063
+ exports.useLogEventOnMount = useLogEventOnMount;
10064
+
9744
10065
  exports.useProjectMembers = useProjectMembers;
9745
10066
 
9746
10067
  exports.useSaveField = useSaveField;