@sanity/workflow-studio-plugin 0.27.0 → 0.28.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,137 @@
1
1
  # @sanity/workflow-studio-plugin
2
2
 
3
+ ## 0.28.0
4
+
5
+ ### Minor Changes
6
+
7
+ - b9947cb: Both "For me" surfaces — the document Workflows view's tab and the Workflows
8
+ tool's segment — now account for work that reached the reader through a role
9
+ rather than by name. When any listed row is assigned to a role the reader
10
+ holds, a line above the list reads "Including tasks assigned to your role". A
11
+ list whose rows only name the reader shows nothing, and neither does the tool's
12
+ "All documents" tab, which never claimed its rows were the reader's. In the tool
13
+ the line tracks the filtered list, so filtering every role-matched row away
14
+ takes it with it.
15
+
16
+ What counts as assigned is unchanged — role-matched work already appeared in
17
+ "For me" and still does, and the tab's task count is unaffected. Only the
18
+ explanation is new.
19
+
20
+ **No upgrade action required.** The notice derives from the same assignment
21
+ matching the list already used, so no definition, configuration, or role setup
22
+ changes.
23
+
24
+ **Docs impact:** Update the Studio plugin guide where it describes the "For me"
25
+ tab and the Workflows tool's For me segment, to note that role assignment
26
+ surfaces work to every holder of the role and that both surfaces say so when it
27
+ happens.
28
+
29
+ - 6584554: **BREAKING:** assignment surfaces now read the project's role catalog, so a role
30
+ with no current holders is assignable and carries its project title.
31
+
32
+ Previously the only role vocabulary was the roles loaded members happened to
33
+ hold. A role the project defines but nobody has yet could not be offered at all,
34
+ and a role named by a stored value rendered as its bare machine name because no
35
+ membership record carried a title for it. Both are fixed by reading
36
+ `GET /projects/{projectId}/roles`. That read is gated on
37
+ `sanity-project-roles: read`, which the default user-facing project roles carry
38
+ down to viewer, so it is not expected to need an administrator.
39
+
40
+ The catalog also becomes the bound on what a picker offers, which subtracts as
41
+ well as adds: a role a member holds that the catalog does not list stops being
42
+ offerable, though it still labels correctly wherever it is already assigned. On
43
+ a complete catalog nothing is lost, since every held role is in it.
44
+
45
+ Three API changes, all in `@sanity/workflow-components`:
46
+ - `ProjectMembersState` gains a required `roles` field, the project's assignable
47
+ roles. Anything constructing this state by hand must supply it; `roles: []`
48
+ preserves the previous behaviour, since resolution falls back to the roles
49
+ members hold. `MemberPicker` does not take it — it lists members only, and its
50
+ props were narrowed to the three fields it reads.
51
+ - `memberRoleFor` and `roleLabelFor` take a `RoleVocabulary` (`{members, roles}`)
52
+ in place of a bare member array. The state either adapter returns satisfies it,
53
+ so a caller holding one can pass it straight through.
54
+ - `AssigneeBadge` and `AssigneeBadges` take `vocabulary` in place of `members`,
55
+ for the same reason.
56
+
57
+ Not migrating leaves a type error at each call site rather than a silent
58
+ behaviour change.
59
+
60
+ Hosts using `@sanity/workflow-studio` or `@sanity/workflow-sdk` get the catalog
61
+ without changes: both adapters fetch it beside the member list, each behind a
62
+ per-client, per-project cache, so it costs one extra request per project per page
63
+ load however many surfaces read it. A failed roles read is deliberately
64
+ non-fatal — it degrades to the previous member-derived behaviour rather than
65
+ taking down the member list, and therefore every assignment control, with it. It
66
+ is reported once on the console with its cause, because nothing downstream can
67
+ tell an unreadable catalog from a project that defines no assignable roles. That
68
+ empty result is cached too, so a project whose catalog cannot be read stays on
69
+ the member-derived behaviour until the page reloads.
70
+
71
+ **Docs impact:** Update the assignment concepts and any Studio plugin guidance
72
+ that describes which roles can be assigned, to say the catalog is the source,
73
+ that a role with no holders is offered, and that a held role missing from the
74
+ catalog is not. The `@sanity/workflow-components` README covers the new
75
+ `RoleVocabulary` shape and the picker's behaviour.
76
+
77
+ ### Patch Changes
78
+
79
+ - f4405b4: The Workflows tool reports a failed read as a failure, in one critical-toned
80
+ banner, on every surface that derives counts or lists from it: the Workflows
81
+ tab, a workflow's definition panel, the task tabs, a workflow's board, and the
82
+ New workflow picker. A failed read is distinguishable from a project with
83
+ nothing running — it produces no zero counts, no "no tasks" empty state and no
84
+ empty board, and where a count cannot be stated the definition panel shows an
85
+ em-dash. The banner tells an editor plainly that something didn't load and that
86
+ trying later may work; the technical cause is logged to the browser console for
87
+ whoever maintains the Studio.
88
+
89
+ **No upgrade action required.** This is display-only — no API, configuration,
90
+ or stored data changes, and a successful read renders exactly as before.
91
+
92
+ **Docs impact:** None. Only the failed-read path changes; a successful read
93
+ renders identically, so nothing the Workflows tool guide describes about
94
+ active-instance counts, task lists, or the board is affected.
95
+
96
+ - a044ba5: Report a Studio start whose auto-advance lost a write race as the finished run
97
+ it is. Starting a workflow from the Studio while another runtime (a deployed
98
+ Function, a script) drives the same instance could hand the editor a warning
99
+ toast — "'…' started but didn't finish", with a raw `unexpected revision ID`
100
+ mutation error under it — for a run that had in fact completed: the Studio's own
101
+ auto-advance simply lost the write race to whoever committed the equivalent move
102
+ first. That toast was indistinguishable from a genuinely stuck workflow. The
103
+ Studio now confirms the completed start instead of warning about it.
104
+
105
+ Narrow by design: only a lost revision race whose run is already complete is
106
+ reclassified. A conflict that left the run in flight, and any other reason an
107
+ auto-advance failed, still surface as before.
108
+
109
+ `@sanity/workflow-engine` exports `isRevisionConflict`, the predicate that tells
110
+ a lost optimistic-locking race from a real error, so integrations can classify
111
+ one without matching on message text. It answers on the error alone, so narrow
112
+ to a single rev-guarded write before asking — a bare 409 also covers a create-id
113
+ collision.
114
+
115
+ **No upgrade action required.** Engine behaviour is unchanged and the new export
116
+ is additive.
117
+
118
+ **Docs impact:** `isRevisionConflict` is new public engine surface, added to the
119
+ errors section of `docs/reference.md` alongside the concurrency errors it
120
+ classifies; mirror that entry wherever published reference material lists the
121
+ engine's error helpers.
122
+
123
+ - Updated dependencies [1e4a5da]
124
+ - Updated dependencies [6584554]
125
+ - Updated dependencies [6584554]
126
+ - Updated dependencies [5050b06]
127
+ - Updated dependencies [a044ba5]
128
+ - Updated dependencies [6584554]
129
+ - @sanity/workflow-engine@0.28.0
130
+ - @sanity/workflow-components@0.28.0
131
+ - @sanity/workflow-studio@0.28.0
132
+ - @sanity/workflow-diagram@0.28.0
133
+ - @sanity/workflow-react@0.28.0
134
+
3
135
  ## 0.27.0
4
136
 
5
137
  ### Minor Changes
@@ -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"), 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"), 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"), 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"), ErrorOutline = require("@sanity/icons/ErrorOutline"), 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 : {
@@ -722,13 +722,25 @@ function isItemAssignedTo(item, who) {
722
722
  return item.assignee != null && assigneeMatches(item.assignee, who);
723
723
  }
724
724
 
725
+ function matchingAssignees(state, who) {
726
+ 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 ] : []);
727
+ }
728
+
725
729
  function isActivityAssignedTo(args) {
726
- return args.state.some(entry => entry._type === "assignees" ? entry.value.some(a => assigneeMatches(a, args.who)) : entry._type === "assignee" ? entry.value !== null && assigneeMatches(entry.value, args.who) : !1);
730
+ return matchingAssignees(args.state, args.who).length > 0;
731
+ }
732
+
733
+ function isRoleAssignedTo(args) {
734
+ return matchingAssignees(args.state, args.who).some(member => member.type === "role");
735
+ }
736
+
737
+ function isItemRoleAssignedTo(item, who) {
738
+ return isItemAssignedTo(item, who) && item.assignee?.type === "role";
727
739
  }
728
740
 
729
741
  function assignedWork(args) {
730
- const {instance: instance, committed: committed, who: who} = args, evaluation = args.staleEvaluation === "keep" || isEvaluationCurrent(args) ? args.evaluation : void 0, byActivity = stateByActivity(instance), activities = (evaluation?.currentStage.activities ?? []).filter(t => isActivityAssignedTo({
731
- state: byActivity.get(t.activity.name) ?? [],
742
+ 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({
743
+ state: stateOf(t),
732
744
  who: who
733
745
  })), items = deriveTodoItems({
734
746
  instance: instance,
@@ -738,7 +750,11 @@ function assignedWork(args) {
738
750
  return {
739
751
  activities: activities,
740
752
  openItems: items.filter(row => !isTodoDone(row.item)),
741
- doneItems: items.filter(row => isTodoDone(row.item))
753
+ doneItems: items.filter(row => isTodoDone(row.item)),
754
+ roleMatched: activities.some(t => isRoleAssignedTo({
755
+ state: stateOf(t),
756
+ who: who
757
+ })) || items.some(row => isItemRoleAssignedTo(row.item, who))
742
758
  };
743
759
  }
744
760
 
@@ -787,7 +803,8 @@ function forMeWorkOf(entries, identity) {
787
803
  return {
788
804
  work: work,
789
805
  count: work.reduce((n, {count: count}) => n + count, 0),
790
- hasRows: work.some(({shown: shown}) => hasAssignedRows(shown))
806
+ hasRows: work.some(({shown: shown}) => hasAssignedRows(shown)),
807
+ hasRoleMatched: work.some(({shown: shown}) => shown.roleMatched)
791
808
  };
792
809
  }
793
810
 
@@ -1361,9 +1378,10 @@ function projectMembersFrom(users) {
1361
1378
  }
1362
1379
 
1363
1380
  function useProjectMembers() {
1364
- const {users: users, loading: loading, error: error} = workflowStudio.useStudioProjectUsers();
1381
+ const {users: users, roles: roles, loading: loading, error: error} = workflowStudio.useStudioProjectUsers();
1365
1382
  return {
1366
1383
  members: react.useMemo(() => projectMembersFrom(users), [ users ]),
1384
+ roles: roles,
1367
1385
  loading: loading,
1368
1386
  error: error === void 0 ? void 0 : workflowEngine.errorMessage(error)
1369
1387
  };
@@ -1717,10 +1735,12 @@ function PickedValueRow({children: children, onRequestChange: onRequestChange})
1717
1735
  }
1718
1736
 
1719
1737
  function MemberPicker({selectedIds: selectedIds, onSelect: onSelect, unassignRow: unassignRow = !1}) {
1720
- const state = useProjectMembers();
1738
+ const {error: error, loading: loading, members: members} = useProjectMembers();
1721
1739
  /* @__PURE__ */
1722
1740
  return jsxRuntime.jsx(workflowComponents.MemberPicker, {
1723
- ...state,
1741
+ error: error,
1742
+ loading: loading,
1743
+ members: members,
1724
1744
  onSelect: onSelect,
1725
1745
  selectedIds: selectedIds,
1726
1746
  unassignRow: unassignRow
@@ -2504,20 +2524,20 @@ function noteRow(args) {
2504
2524
  }
2505
2525
 
2506
2526
  function AssigneeBadge({assignee: assignee}) {
2507
- const {members: members} = useProjectMembers();
2527
+ const vocabulary = useProjectMembers();
2508
2528
  /* @__PURE__ */
2509
2529
  return jsxRuntime.jsx(workflowComponents.AssigneeBadge, {
2510
2530
  assignee: assignee,
2511
- members: members
2531
+ vocabulary: vocabulary
2512
2532
  });
2513
2533
  }
2514
2534
 
2515
2535
  function AssigneeBadges({assignees: assignees}) {
2516
- const {members: members} = useProjectMembers();
2536
+ const vocabulary = useProjectMembers();
2517
2537
  /* @__PURE__ */
2518
2538
  return jsxRuntime.jsx(workflowComponents.AssigneeBadges, {
2519
2539
  assignees: assignees,
2520
- members: members
2540
+ vocabulary: vocabulary
2521
2541
  });
2522
2542
  }
2523
2543
 
@@ -4144,7 +4164,7 @@ function AvatarButton({avatar: avatar, onClick: onClick, onMouseDown: onMouseDow
4144
4164
  }
4145
4165
 
4146
4166
  function RowAssignees({assignees: assignees, hint: hint}) {
4147
- const ids = assignees.flatMap(item => item.type === "user" ? [ item.id ] : []), {members: members} = useProjectMembers(), roles = assignees.flatMap(item => item.type === "role" ? [ workflowComponents.memberRoleFor(members, item.role) ] : []), displays = useUserDisplays(ids);
4167
+ const ids = assignees.flatMap(item => item.type === "user" ? [ item.id ] : []), vocabulary = useProjectMembers(), roles = assignees.flatMap(item => item.type === "role" ? [ workflowComponents.memberRoleFor(vocabulary, item.role) ] : []), displays = useUserDisplays(ids);
4148
4168
  if (ids.length === 0 && roles.length === 0) return null;
4149
4169
  const bothKinds = roles.length > 0 && displays.length > 0;
4150
4170
  /* @__PURE__ */
@@ -6014,7 +6034,7 @@ function AvatarCapAligned({children: children}) {
6014
6034
  }
6015
6035
 
6016
6036
  function AssigneesFace({assignees: assignees}) {
6017
- const {members: members} = useProjectMembers(), userIds = assignees.flatMap(a => a.type === "user" ? [ a.id ] : []), roles = assignees.flatMap(a => a.type === "role" ? [ workflowComponents.roleLabelFor(members, a.role) ] : []);
6037
+ const vocabulary = useProjectMembers(), userIds = assignees.flatMap(a => a.type === "user" ? [ a.id ] : []), roles = assignees.flatMap(a => a.type === "role" ? [ workflowComponents.roleLabelFor(vocabulary, a.role) ] : []);
6018
6038
  /* @__PURE__ */
6019
6039
  return jsxRuntime.jsxs(jsxRuntime.Fragment, {
6020
6040
  children: [ userIds.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(AvatarCapAligned, {
@@ -7774,18 +7794,23 @@ function StageSection({entry: entry, onOpenActivity: onOpenActivity, surface: su
7774
7794
  });
7775
7795
  }
7776
7796
 
7777
- function CautionNote({action: action, label: label}) {
7797
+ const BANNER_PADDING = 3, ICONS = {
7798
+ caution: /* @__PURE__ */ jsxRuntime.jsx(WarningOutline.WarningOutlineIcon, {}),
7799
+ critical: /* @__PURE__ */ jsxRuntime.jsx(ErrorOutline.ErrorOutlineIcon, {})
7800
+ };
7801
+
7802
+ function NoteBanner({action: action, label: label, tone: tone = "caution"}) {
7778
7803
  /* @__PURE__ */
7779
7804
  return jsxRuntime.jsxs(ui.Card, {
7780
7805
  paddingLeft: 3,
7781
7806
  paddingRight: 2,
7782
- paddingY: 3,
7807
+ paddingY: BANNER_PADDING,
7783
7808
  radius: 3,
7784
7809
  style: {
7785
7810
  alignItems: "center",
7786
7811
  display: "flex"
7787
7812
  },
7788
- tone: "caution",
7813
+ tone: tone,
7789
7814
  children: [
7790
7815
  /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, {
7791
7816
  align: "center",
@@ -7795,7 +7820,7 @@ function CautionNote({action: action, label: label}) {
7795
7820
  /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
7796
7821
  muted: !0,
7797
7822
  size: 1,
7798
- children: /* @__PURE__ */ jsxRuntime.jsx(WarningOutline.WarningOutlineIcon, {})
7823
+ children: ICONS[tone]
7799
7824
  }),
7800
7825
  /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
7801
7826
  muted: !0,
@@ -7832,7 +7857,7 @@ function UnreadableDocsNote({unreadable: unreadable}) {
7832
7857
  if (unreadable.length === 0) return null;
7833
7858
  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.`;
7834
7859
  /* @__PURE__ */
7835
- return jsxRuntime.jsx(CautionNote, {
7860
+ return jsxRuntime.jsx(NoteBanner, {
7836
7861
  action: /* @__PURE__ */ jsxRuntime.jsx(CopyDetailsButton, {
7837
7862
  unreadable: unreadable
7838
7863
  }),
@@ -7878,6 +7903,21 @@ function InvalidDocNotice({invalid: invalid}) {
7878
7903
  });
7879
7904
  }
7880
7905
 
7906
+ function RoleAssignedNotice() {
7907
+ /* @__PURE__ */
7908
+ return jsxRuntime.jsx(ui.Box, {
7909
+ padding: 2,
7910
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, {
7911
+ muted: !0,
7912
+ size: 1,
7913
+ style: {
7914
+ fontStyle: "italic"
7915
+ },
7916
+ children: "Including tasks assigned to your role"
7917
+ })
7918
+ });
7919
+ }
7920
+
7881
7921
  function TabSwitch({ariaControls: ariaControls, idPrefix: idPrefix, options: options, selected: selected, onSelect: onSelect}) {
7882
7922
  /* @__PURE__ */
7883
7923
  return jsxRuntime.jsx(ui.TabList, {
@@ -8142,8 +8182,15 @@ function presentedResumeEntry(args) {
8142
8182
  if (!args.startNew) return findResumeEntry(args);
8143
8183
  }
8144
8184
 
8185
+ function settledByAnotherWriter(cause, instance) {
8186
+ return workflowEngine.isRevisionConflict(cause) && workflowEngine.terminalState(instance) === "completed";
8187
+ }
8188
+
8145
8189
  function classifyStartError(err) {
8146
- return err instanceof workflowEngine.StartNotSettledError ? {
8190
+ return err instanceof workflowEngine.StartNotSettledError ? err.instance !== void 0 && settledByAnotherWriter(err.cause, err.instance) ? {
8191
+ kind: "started-settled-elsewhere",
8192
+ instance: err.instance
8193
+ } : {
8147
8194
  kind: "started-not-settled",
8148
8195
  instance: err.instance,
8149
8196
  description: describeError(err.cause)
@@ -8156,8 +8203,16 @@ function classifyStartError(err) {
8156
8203
  };
8157
8204
  }
8158
8205
 
8206
+ function startProducedRun(outcome) {
8207
+ return outcome.kind === "started-not-settled" || outcome.kind === "started-settled-elsewhere";
8208
+ }
8209
+
8159
8210
  function startOutcomeToast(outcome, label) {
8160
- return outcome.kind === "started-not-settled" ? {
8211
+ return outcome.kind === "started-settled-elsewhere" ? {
8212
+ id: TOAST_ID.start,
8213
+ status: "info",
8214
+ title: `“${label}” started and finished`
8215
+ } : outcome.kind === "started-not-settled" ? {
8161
8216
  id: TOAST_ID.start,
8162
8217
  status: "warning",
8163
8218
  title: `“${label}” started but didn’t finish`,
@@ -8888,10 +8943,10 @@ function OverviewEmptyState({mappings: mappings, docId: docId, initialValue: ini
8888
8943
  }
8889
8944
 
8890
8945
  function ForMeTab({forMe: forMe, assignedWorkUnknown: assignedWorkUnknown, onOpenActivity: onOpenActivity}) {
8891
- return forMe.hasRows ? /* @__PURE__ */ jsxRuntime.jsx(ui.Stack, {
8946
+ return forMe.hasRows ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, {
8892
8947
  gap: GROUP_GAP,
8893
8948
  paddingBottom: 4,
8894
- children: forMe.work.map(({entry: entry, who: who, shown: shown}) => /* @__PURE__ */ jsxRuntime.jsx(ForMeList, {
8949
+ children: [ forMe.hasRoleMatched ? /* @__PURE__ */ jsxRuntime.jsx(RoleAssignedNotice, {}) : null, forMe.work.map(({entry: entry, who: who, shown: shown}) => /* @__PURE__ */ jsxRuntime.jsx(ForMeList, {
8895
8950
  entry: entry,
8896
8951
  identity: who,
8897
8952
  work: shown,
@@ -8900,7 +8955,7 @@ function ForMeTab({forMe: forMe, assignedWorkUnknown: assignedWorkUnknown, onOpe
8900
8955
  activityName: activityName,
8901
8956
  stage: entry.instance.currentStage
8902
8957
  })
8903
- }, entry.instance._id))
8958
+ }, entry.instance._id)) ]
8904
8959
  }) : assignedWorkUnknown ? null : /* @__PURE__ */ jsxRuntime.jsx(ForMeEmptyState, {});
8905
8960
  }
8906
8961
 
@@ -10138,7 +10193,7 @@ function ResumeNote({onStartNew: onStartNew}) {
10138
10193
 
10139
10194
  function handleStartError(args) {
10140
10195
  const {label: label, toast: toast, seedInstance: seedInstance, onClose: onClose} = args, outcome = classifyStartError(args.err);
10141
- toast.push(startOutcomeToast(outcome, label)), outcome.kind === "started-not-settled" && (outcome.instance !== void 0 && seedInstance(outcome.instance),
10196
+ toast.push(startOutcomeToast(outcome, label)), startProducedRun(outcome) && (outcome.instance !== void 0 && seedInstance(outcome.instance),
10142
10197
  onClose());
10143
10198
  }
10144
10199
 
@@ -10491,7 +10546,7 @@ async function startRequest(engine, request) {
10491
10546
  };
10492
10547
  } catch (err) {
10493
10548
  const outcome = classifyStartError(err);
10494
- return outcome.kind === "started-not-settled" ? outcome.instance ? {
10549
+ return startProducedRun(outcome) ? outcome.instance ? {
10495
10550
  instance: outcome.instance
10496
10551
  } : {} : outcome.kind === "not-allowed" ? {} : {
10497
10552
  failure: outcome.description
@@ -11102,8 +11157,6 @@ exports.ActivityRow = ActivityRow;
11102
11157
 
11103
11158
  exports.BreadcrumbTail = BreadcrumbTail;
11104
11159
 
11105
- exports.CautionNote = CautionNote;
11106
-
11107
11160
  exports.CodeChip = CodeChip;
11108
11161
 
11109
11162
  exports.CountedLabel = CountedLabel;
@@ -11134,6 +11187,10 @@ exports.LogEventOnMount = LogEventOnMount;
11134
11187
 
11135
11188
  exports.MetaRow = MetaRow;
11136
11189
 
11190
+ exports.NoteBanner = NoteBanner;
11191
+
11192
+ exports.RoleAssignedNotice = RoleAssignedNotice;
11193
+
11137
11194
  exports.SpinnerSlot = SpinnerSlot;
11138
11195
 
11139
11196
  exports.StageFace = StageFace;
@@ -11210,6 +11267,8 @@ exports.isLiveEntry = isLiveEntry;
11210
11267
 
11211
11268
  exports.isOpenActivityStatus = isOpenActivityStatus;
11212
11269
 
11270
+ exports.isRoleAssignedTo = isRoleAssignedTo;
11271
+
11213
11272
  exports.landingState = landingState;
11214
11273
 
11215
11274
  exports.mappingIssueDetail = mappingIssueDetail;