@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.
@@ -8,9 +8,9 @@ import { useState, useEffect, useMemo, useRef, useSyncExternalStore, useCallback
8
8
 
9
9
  import { useRouter } from "sanity/router";
10
10
 
11
- import { isLiveEntry, AbortWorkflowDialog, isEvaluationStale, useSpaceToken, DocPreviewLink, SpinnerSlot, useWorkflowInstanceEntry, useLogEventOnMount, WorkflowInstanceDetailViewed, LoadingRow, InvalidDocNotice, useDefinition, useContainerToken, openActivityGone, InstanceSnapshotBody, ActivityLog, ActivityDetailDialog, instanceBreadcrumb, CodeChip, instanceTitle, namesNoDeployedDefinition, mappingIssueDetail, formatTimeAgo, formatShortDateTime, useWorkflowContext, readDeployedDefinitions, describeError, EmptyState, CautionNote, HoverHint, DismissablePopover, createSubscribers, useDelayedFlag, definitionSnapshotOf, findActivity, stageTitle, stateByActivity, findActivityNode, rowDateControlState, rowAssignControlState, isActivityAssignedTo, assigneesOf, dueDatesOf, datesOf, isOpenActivityStatus, committedRowFace, activityRowProps, gdrLocality, TOAST_ID, WORKFLOW_API_VERSION, useWorkflowToast, openableSchemaType, formatDate, parseStoredDateValue, useUserDisplays, useProjectMembers, WorkflowTaskFiltersApplied, DocRefFace, Hairline, LinkChip, BreadcrumbTail, StageFace, StaleLock, ActivityRow, WorkflowTitleSeedDrifted, UnreadableDocsNote, ForMeEmptyState, useBadgeCapTrim, CountedLabel, MetaRow, TabSwitch, WORKFLOW_PAGE_TABS, definitionFingerprint, LogEventOnMount, WorkflowBoardWorkflowSelected, WorkflowDefinitionDetailViewed, toolRoute, landingState, TOOL_TABS, tabSelectionNavigates, WorkflowToolOpened, toolTabState, workflowPageState, instanceState, backToTabLabel, useAssignmentIdentity, workflowState } from "./index.js";
11
+ import { isLiveEntry, AbortWorkflowDialog, isEvaluationStale, useSpaceToken, DocPreviewLink, SpinnerSlot, useWorkflowInstanceEntry, useLogEventOnMount, WorkflowInstanceDetailViewed, LoadingRow, InvalidDocNotice, useDefinition, useContainerToken, openActivityGone, InstanceSnapshotBody, ActivityLog, ActivityDetailDialog, instanceBreadcrumb, CodeChip, instanceTitle, namesNoDeployedDefinition, mappingIssueDetail, formatTimeAgo, formatShortDateTime, useWorkflowContext, readDeployedDefinitions, describeError, NoteBanner, EmptyState, HoverHint, DismissablePopover, createSubscribers, useDelayedFlag, definitionSnapshotOf, findActivity, stageTitle, stateByActivity, findActivityNode, rowDateControlState, rowAssignControlState, isRoleAssignedTo, isActivityAssignedTo, assigneesOf, dueDatesOf, datesOf, isOpenActivityStatus, committedRowFace, activityRowProps, gdrLocality, TOAST_ID, WORKFLOW_API_VERSION, useWorkflowToast, openableSchemaType, formatDate, parseStoredDateValue, useUserDisplays, useProjectMembers, WorkflowTaskFiltersApplied, DocRefFace, Hairline, LinkChip, BreadcrumbTail, StageFace, StaleLock, ActivityRow, WorkflowTitleSeedDrifted, UnreadableDocsNote, RoleAssignedNotice, ForMeEmptyState, useBadgeCapTrim, CountedLabel, MetaRow, TabSwitch, WORKFLOW_PAGE_TABS, definitionFingerprint, LogEventOnMount, WorkflowBoardWorkflowSelected, WorkflowDefinitionDetailViewed, toolRoute, landingState, TOOL_TABS, tabSelectionNavigates, WorkflowToolOpened, toolTabState, workflowPageState, instanceState, backToTabLabel, useAssignmentIdentity, workflowState } from "./index.js";
12
12
 
13
- import { entryDocRefs, startKindOf, isSubjectEntry, isInputSourced, latestDeployedDefinitions, terminalState, isStartableDefinition, toBareId, findOpenStageEntry } from "@sanity/workflow-engine";
13
+ import { entryDocRefs, startKindOf, isSubjectEntry, isInputSourced, errorMessage, latestDeployedDefinitions, terminalState, isStartableDefinition, toBareId, findOpenStageEntry } from "@sanity/workflow-engine";
14
14
 
15
15
  import { ArrowLeftIcon } from "@sanity/icons/ArrowLeft";
16
16
 
@@ -476,13 +476,45 @@ function deployedPhrase(definition) {
476
476
  return ago === "" ? formatShortDateTime(deployedAt) : `${formatShortDateTime(deployedAt)} (${ago})`;
477
477
  }
478
478
 
479
- const TOOL_PANEL_PADDING = 3, TOOL_HEADING_PADDING = 2;
479
+ const TOOL_PANEL_PADDING = 3, TOOL_HEADING_PADDING = 2, logged = /* @__PURE__ */ new WeakSet;
480
480
 
481
- function catalogReadError(error) {
482
- return `Could not load the deployed workflows: ${error}`;
481
+ function logReadFailure(what, error) {
482
+ if (typeof error == "object" && error !== null) {
483
+ if (logged.has(error)) return;
484
+ logged.add(error);
485
+ }
486
+ console.error(`[workflow-studio-plugin] could not load ${what}:`, error);
487
+ }
488
+
489
+ function useReadFailureLog(what, error) {
490
+ useEffect(() => {
491
+ error !== void 0 && logReadFailure(what, error);
492
+ }, [ what, error ]);
483
493
  }
484
494
 
485
- const lastRead = /* @__PURE__ */ new WeakMap, issuedReads = /* @__PURE__ */ new WeakMap;
495
+ const INSTANCE_CAP = 200, INSTANCES_READ_FAILED = "Couldn’t load workflow data. Try again later.";
496
+
497
+ function useCappedInstances(filter) {
498
+ const {engine: engine} = useWorkflowContext(), capped = useMemo(() => ({
499
+ ...filter,
500
+ limit: INSTANCE_CAP
501
+ }), [ filter ]), {instances: instances, loading: loading, unreadable: unreadable, error: error} = useWorkflowInstances({
502
+ engine: engine,
503
+ filter: capped
504
+ });
505
+ return useReadFailureLog("workflow data", error), useMemo(() => {
506
+ const rows = instances ?? [];
507
+ return {
508
+ rows: rows,
509
+ truncated: rows.length + unreadable.length === INSTANCE_CAP,
510
+ loading: loading,
511
+ unreadable: unreadable,
512
+ error: error === void 0 ? void 0 : errorMessage(error)
513
+ };
514
+ }, [ instances, loading, unreadable, error ]);
515
+ }
516
+
517
+ const CATALOG_READ_FAILED = "Couldn’t load the deployed workflows. Try again later.", lastRead = /* @__PURE__ */ new WeakMap, issuedReads = /* @__PURE__ */ new WeakMap;
486
518
 
487
519
  function useDeployedDefinitions() {
488
520
  const {engine: engine} = useWorkflowContext(), [definitions, setDefinitions] = useState(() => lastRead.get(engine)?.rows), [error, setError] = useState(void 0);
@@ -497,7 +529,7 @@ function useDeployedDefinitions() {
497
529
  rows: latest
498
530
  }), cancelled || (setDefinitions(latest), setError(void 0));
499
531
  })().catch(err => {
500
- cancelled || setError(describeError(err));
532
+ logReadFailure("the deployed workflows", err), cancelled || setError(describeError(err));
501
533
  }), () => {
502
534
  cancelled = !0;
503
535
  };
@@ -507,46 +539,30 @@ function useDeployedDefinitions() {
507
539
  };
508
540
  }
509
541
 
510
- const INSTANCE_CAP = 200;
511
-
512
- function useCappedInstances(filter) {
513
- const {engine: engine} = useWorkflowContext(), capped = useMemo(() => ({
514
- ...filter,
515
- limit: INSTANCE_CAP
516
- }), [ filter ]), {instances: instances, loading: loading, unreadable: unreadable} = useWorkflowInstances({
517
- engine: engine,
518
- filter: capped
519
- });
520
- return useMemo(() => {
521
- const rows = instances ?? [];
522
- return {
523
- rows: rows,
524
- truncated: rows.length + unreadable.length === INSTANCE_CAP,
525
- loading: loading,
526
- unreadable: unreadable
527
- };
528
- }, [ instances, loading, unreadable ]);
529
- }
530
-
531
542
  const INSTANCE_CAP_COUNT_NOTE = `Counts from the latest ${INSTANCE_CAP} workflows — older ones aren’t counted.`, NEWEST_INSTANCES = {
532
543
  includeCompleted: !0
533
544
  };
534
545
 
535
546
  function useToolInstances() {
536
- const {rows: rows, truncated: truncated, loading: loading, unreadable: unreadable} = useCappedInstances(NEWEST_INSTANCES);
547
+ const {rows: rows, truncated: truncated, loading: loading, unreadable: unreadable, error: error} = useCappedInstances(NEWEST_INSTANCES);
537
548
  return useMemo(() => ({
538
549
  inFlight: rows.filter(instance => terminalState(instance) === "in-flight"),
539
550
  settled: rows.filter(instance => terminalState(instance) !== "in-flight"),
540
551
  truncated: truncated,
541
552
  loading: loading,
542
- unreadable: unreadable
543
- }), [ rows, truncated, loading, unreadable ]);
553
+ unreadable: unreadable,
554
+ error: error
555
+ }), [ rows, truncated, loading, unreadable, error ]);
544
556
  }
545
557
 
546
558
  function activeSummary(active) {
547
559
  return active === 0 ? "No active instances" : pluralize("active instance", active, !0);
548
560
  }
549
561
 
562
+ function activeHeadline(args) {
563
+ if (args.error === void 0) return args.loading ? "counting active instances…" : activeSummary(args.active);
564
+ }
565
+
550
566
  const CARD_MIN_WIDTH = 280, CARD_RADIUS$1 = 3, CARD_PADDING = 4, CARD_MIN_HEIGHT = 180;
551
567
 
552
568
  function OverviewTab({onOpenWorkflow: onOpenWorkflow}) {
@@ -556,13 +572,9 @@ function OverviewTab({onOpenWorkflow: onOpenWorkflow}) {
556
572
  titleOf: name => schema.get(name)?.title
557
573
  })
558
574
  });
559
- if (error !== void 0) /* @__PURE__ */
560
- return jsx(TabStatusRow, {
561
- children: /* @__PURE__ */ jsx(Text, {
562
- muted: !0,
563
- size: 1,
564
- children: catalogReadError(error)
565
- })
575
+ if (error !== void 0) /* @__PURE__ */ return jsx(NoteBanner, {
576
+ label: CATALOG_READ_FAILED,
577
+ tone: "critical"
566
578
  });
567
579
  if (definitions === void 0) /* @__PURE__ */
568
580
  return jsx(TabStatusRow, {
@@ -589,13 +601,20 @@ function OverviewTab({onOpenWorkflow: onOpenWorkflow}) {
589
601
  mappings: mappings,
590
602
  inFlight: instances.inFlight,
591
603
  issues: mappingIssues
592
- }), active = rows.reduce((sum, row) => sum + row.activeCount, 0);
604
+ }), active = rows.reduce((sum, row) => sum + row.activeCount, 0), activity = activeHeadline({
605
+ active: active,
606
+ error: instances.error,
607
+ loading: instances.loading
608
+ });
593
609
  /* @__PURE__ */
594
610
  return jsxs(Stack, {
595
611
  gap: 3,
596
612
  paddingBottom: 4,
597
613
  paddingTop: 3,
598
- children: [ undeployed,
614
+ children: [ undeployed, instances.error === void 0 ? null : /* @__PURE__ */ jsx(NoteBanner, {
615
+ label: INSTANCES_READ_FAILED,
616
+ tone: "critical"
617
+ }),
599
618
  /* @__PURE__ */ jsxs(Flex, {
600
619
  align: "center",
601
620
  gap: 2,
@@ -605,11 +624,10 @@ function OverviewTab({onOpenWorkflow: onOpenWorkflow}) {
605
624
  size: 1,
606
625
  weight: "semibold",
607
626
  children: pluralize("workflow", rows.length, !0)
608
- }),
609
- /* @__PURE__ */ jsx(Text, {
627
+ }), activity === void 0 ? null : /* @__PURE__ */ jsx(Text, {
610
628
  muted: !0,
611
629
  size: 1,
612
- children: instances.loading ? "counting active instances…" : activeSummary(active)
630
+ children: activity
613
631
  }) ]
614
632
  }),
615
633
  /* @__PURE__ */ jsx(Grid, {
@@ -619,7 +637,7 @@ function OverviewTab({onOpenWorkflow: onOpenWorkflow}) {
619
637
  gridTemplateColumns: `repeat(auto-fill, minmax(${CARD_MIN_WIDTH}px, 1fr))`
620
638
  },
621
639
  children: rows.map(row => /* @__PURE__ */ jsx(WorkflowCard, {
622
- countPending: instances.loading,
640
+ countKnown: instances.error === void 0 && !instances.loading,
623
641
  onOpen: () => onOpenWorkflow(row.name),
624
642
  row: row
625
643
  }, row.name))
@@ -636,13 +654,13 @@ function UndeployedWorkflows({notices: notices}) {
636
654
  /* @__PURE__ */ jsx(Stack, {
637
655
  gap: 2,
638
656
  paddingBottom: 1,
639
- children: notices.map(notice => /* @__PURE__ */ jsx(CautionNote, {
657
+ children: notices.map(notice => /* @__PURE__ */ jsx(NoteBanner, {
640
658
  label: notice
641
659
  }, notice))
642
660
  });
643
661
  }
644
662
 
645
- function WorkflowCard({countPending: countPending, onOpen: onOpen, row: row}) {
663
+ function WorkflowCard({countKnown: countKnown, onOpen: onOpen, row: row}) {
646
664
  const flagged = row.brokenBindings.length > 0, card = /* @__PURE__ */ jsx(Card, {
647
665
  as: "button",
648
666
  onClick: onOpen,
@@ -677,11 +695,11 @@ function WorkflowCard({countPending: countPending, onOpen: onOpen, row: row}) {
677
695
  size: 1,
678
696
  weight: "semibold",
679
697
  children: row.title
680
- }), countPending ? null : /* @__PURE__ */ jsx(Text, {
698
+ }), countKnown ? /* @__PURE__ */ jsx(Text, {
681
699
  muted: !0,
682
700
  size: 1,
683
701
  children: activeSummary(row.activeCount)
684
- }) ]
702
+ }) : null ]
685
703
  }) ]
686
704
  })
687
705
  });
@@ -735,7 +753,7 @@ function DefinitionPickerPanel({onPick: onPick}) {
735
753
  const {definitions: definitions, error: error} = useStartableDefinitions(), [query, setQuery] = useState(""), visible = useMemo(() => {
736
754
  const q = query.trim().toLowerCase();
737
755
  return definitions ? q ? definitions.filter(d => `${d.title} ${d.name}`.toLowerCase().includes(q)) : definitions : [];
738
- }, [ definitions, query ]);
756
+ }, [ definitions, query ]), settled = error === void 0 ? definitions : void 0;
739
757
  /* @__PURE__ */
740
758
  return jsx(Box, {
741
759
  padding: 2,
@@ -752,13 +770,14 @@ function DefinitionPickerPanel({onPick: onPick}) {
752
770
  onChange: event => setQuery(event.currentTarget.value),
753
771
  placeholder: "Filter workflows…",
754
772
  value: query
755
- }), error ? /* @__PURE__ */ jsx(MutedNote, {
756
- text: catalogReadError(error)
773
+ }), error ? /* @__PURE__ */ jsx(NoteBanner, {
774
+ label: CATALOG_READ_FAILED,
775
+ tone: "critical"
757
776
  }) : null, !definitions && !error ? /* @__PURE__ */ jsx(LoadingRow, {
758
777
  label: "Loading workflows…"
759
- }) : null, definitions && definitions.length === 0 ? /* @__PURE__ */ jsx(MutedNote, {
778
+ }) : null, settled?.length === 0 ? /* @__PURE__ */ jsx(MutedNote, {
760
779
  text: "No startable workflows are deployed"
761
- }) : null, definitions && definitions.length > 0 && visible.length === 0 ? /* @__PURE__ */ jsx(MutedNote, {
780
+ }) : null, settled !== void 0 && settled.length > 0 && visible.length === 0 ? /* @__PURE__ */ jsx(MutedNote, {
762
781
  text: "No workflows match"
763
782
  }) : null,
764
783
  /* @__PURE__ */ jsx(Stack, {
@@ -1089,6 +1108,10 @@ function taskRowsOf(args) {
1089
1108
  state: fields,
1090
1109
  who: identity
1091
1110
  }),
1111
+ roleMatched: identity !== void 0 && isRoleAssignedTo({
1112
+ state: fields,
1113
+ who: identity
1114
+ }),
1092
1115
  assignControl: rowAssignControlState(controlArgs),
1093
1116
  dateControl: rowDateControlState(controlArgs)
1094
1117
  };
@@ -1171,6 +1194,11 @@ function onlyMyTasks(groups) {
1171
1194
  });
1172
1195
  }
1173
1196
 
1197
+ function hasRoleMatchedTasks(groups) {
1198
+ const bandHasOne = band => band.rows.some(row => row.roleMatched);
1199
+ return groups.withDocuments.some(group => group.instances.some(bandHasOne)) || groups.withoutDocuments.some(bandHasOne);
1200
+ }
1201
+
1174
1202
  function rowActivityEval(entry, row) {
1175
1203
  const evaluation = entry?.evaluation;
1176
1204
  if (!(evaluation === void 0 || evaluation.currentStage.stage.name !== row.stage)) return evaluation.currentStage.activities.find(a => a.activity.name === row.activityName);
@@ -1314,7 +1342,7 @@ function OrphanedWorkflowsNote({orphans: orphans}) {
1314
1342
  /* @__PURE__ */
1315
1343
  return jsxs(Fragment, {
1316
1344
  children: [
1317
- /* @__PURE__ */ jsx(CautionNote, {
1345
+ /* @__PURE__ */ jsx(NoteBanner, {
1318
1346
  action: /* @__PURE__ */ jsx(Button, {
1319
1347
  fontSize: 1,
1320
1348
  mode: "ghost",
@@ -2650,7 +2678,7 @@ function useOrphanedWorkflows(groups) {
2650
2678
  }), [ groups, contentResource, missing ]);
2651
2679
  }
2652
2680
 
2653
- function TasksTab({filterSlot: filterSlot, instances: instances, loading: loading, identity: identity, onOpenInstance: onOpenInstance, onOpenTask: onOpenTask, tab: tab, truncated: truncated, unreadable: unreadable}) {
2681
+ function TasksTab({error: error, filterSlot: filterSlot, instances: instances, loading: loading, identity: identity, onOpenInstance: onOpenInstance, onOpenTask: onOpenTask, tab: tab, truncated: truncated, unreadable: unreadable}) {
2654
2682
  const mineOnly = tab === "for-me", {binding: binding} = useWorkflowContext(), bands = useBandOpenState({
2655
2683
  segment: TASK_BAND_SEGMENTS[tab],
2656
2684
  scope: binding.engineResource.id
@@ -2668,6 +2696,10 @@ function TasksTab({filterSlot: filterSlot, instances: instances, loading: loadin
2668
2696
  }), cut = mineOnly ? onlyMyTasks(filtered) : filtered;
2669
2697
  return orderGroupsByPreviewTitle(cut, titles.titles);
2670
2698
  }, [ listed, filters, mineOnly, titles ]);
2699
+ if (error !== void 0) /* @__PURE__ */ return jsx(NoteBanner, {
2700
+ label: INSTANCES_READ_FAILED,
2701
+ tone: "critical"
2702
+ });
2671
2703
  if (loading || !revealed) /* @__PURE__ */
2672
2704
  return jsx(TabStatusRow, {
2673
2705
  children: /* @__PURE__ */ jsx(LoadingRow, {
@@ -2707,7 +2739,7 @@ function TasksTab({filterSlot: filterSlot, instances: instances, loading: loadin
2707
2739
  }),
2708
2740
  /* @__PURE__ */ jsx(OrphanedWorkflowsNote, {
2709
2741
  orphans: orphans
2710
- }), body, truncated ? /* @__PURE__ */ jsx(MutedNote, {
2742
+ }), mineOnly && hasRoleMatchedTasks(visible) ? /* @__PURE__ */ jsx(RoleAssignedNotice, {}) : null, body, truncated ? /* @__PURE__ */ jsx(MutedNote, {
2711
2743
  text: `Tasks from the latest ${INSTANCE_CAP} workflows — older ones aren’t listed.`
2712
2744
  }) : null ]
2713
2745
  }) ]
@@ -3085,6 +3117,16 @@ function useBoardInstances(definitionName) {
3085
3117
  return useCappedInstances(filter);
3086
3118
  }
3087
3119
 
3120
+ function activeCountFace(args) {
3121
+ return args.error !== void 0 || args.loading ? {
3122
+ count: void 0,
3123
+ note: void 0
3124
+ } : {
3125
+ count: args.count,
3126
+ note: args.truncated ? INSTANCE_CAP_COUNT_NOTE : void 0
3127
+ };
3128
+ }
3129
+
3088
3130
  function DefinitionPanel({definition: definition}) {
3089
3131
  /* @__PURE__ */
3090
3132
  return jsx(Box, {
@@ -3147,6 +3189,23 @@ function SetupIssues({bindings: bindings}) {
3147
3189
  });
3148
3190
  }
3149
3191
 
3192
+ function ActiveCount({face: face}) {
3193
+ /* @__PURE__ */
3194
+ return jsxs(Stack, {
3195
+ gap: 2,
3196
+ children: [
3197
+ /* @__PURE__ */ jsx(Text, {
3198
+ muted: face.count === void 0,
3199
+ size: 1,
3200
+ children: face.count ?? "—"
3201
+ }), face.note === void 0 ? null : /* @__PURE__ */ jsx(Text, {
3202
+ muted: !0,
3203
+ size: 1,
3204
+ children: face.note
3205
+ }) ]
3206
+ });
3207
+ }
3208
+
3150
3209
  function DefinitionFacts({definition: definition}) {
3151
3210
  const {mappingIssues: mappingIssues, mappings: mappings} = useWorkflowContext(), schema = useSchema(), instances = useToolInstances(), snapshotWidth = useContainerToken(2), [row] = definitionCatalog({
3152
3211
  definitions: [ definition ],
@@ -3164,6 +3223,12 @@ function DefinitionFacts({definition: definition}) {
3164
3223
  children: /* @__PURE__ */ jsx(SetupIssues, {
3165
3224
  bindings: row.brokenBindings
3166
3225
  })
3226
+ }), instances.error === void 0 ? null : /* @__PURE__ */ jsx(Box, {
3227
+ flex: "none",
3228
+ children: /* @__PURE__ */ jsx(NoteBanner, {
3229
+ label: INSTANCES_READ_FAILED,
3230
+ tone: "critical"
3231
+ })
3167
3232
  }),
3168
3233
  /* @__PURE__ */ jsx(Box, {
3169
3234
  flex: "none",
@@ -3182,21 +3247,13 @@ function DefinitionFacts({definition: definition}) {
3182
3247
  }),
3183
3248
  /* @__PURE__ */ jsx(MetaRow, {
3184
3249
  label: "Active instances",
3185
- children: instances.loading ? /* @__PURE__ */ jsx(Text, {
3186
- muted: !0,
3187
- size: 1,
3188
- children: "—"
3189
- }) : /* @__PURE__ */ jsxs(Stack, {
3190
- gap: 2,
3191
- children: [
3192
- /* @__PURE__ */ jsx(Text, {
3193
- size: 1,
3194
- children: row?.activeCount ?? 0
3195
- }), instances.truncated ? /* @__PURE__ */ jsx(Text, {
3196
- muted: !0,
3197
- size: 1,
3198
- children: INSTANCE_CAP_COUNT_NOTE
3199
- }) : null ]
3250
+ children: /* @__PURE__ */ jsx(ActiveCount, {
3251
+ face: activeCountFace({
3252
+ count: row?.activeCount ?? 0,
3253
+ error: instances.error,
3254
+ loading: instances.loading,
3255
+ truncated: instances.truncated
3256
+ })
3200
3257
  })
3201
3258
  }),
3202
3259
  /* @__PURE__ */ jsx(MetaRow, {
@@ -3733,11 +3790,11 @@ function usePageSelection(page) {
3733
3790
  }
3734
3791
 
3735
3792
  function WorkflowPage({onOpenWorkflow: onOpenWorkflow, onSelectPage: onSelectPage, page: page, workflowName: workflowName}) {
3736
- const {definitions: definitions, error: error} = useDeployedDefinitions(), selection = resolveWorkflowSelection({
3793
+ const {definitions: definitions, error: catalogError} = useDeployedDefinitions(), selection = resolveWorkflowSelection({
3737
3794
  definitions: definitions,
3738
3795
  routeName: workflowName
3739
3796
  }), selected = resolvedDefinition(selection), view = workflowPageView({
3740
- error: error,
3797
+ error: catalogError,
3741
3798
  page: page,
3742
3799
  selection: selection
3743
3800
  }), instances = useBoardInstances(view.streamName), {board: board, ready: ready, titles: titles} = useBoard({
@@ -3749,9 +3806,9 @@ function WorkflowPage({onOpenWorkflow: onOpenWorkflow, onSelectPage: onSelectPag
3749
3806
  })), revealed = useRevealGate({
3750
3807
  loading: instances.loading,
3751
3808
  ready: ready
3752
- }), waiting = useDelayedFlag(selection.kind === "loading" && error === void 0, WAIT_CUE_DELAY_MS);
3809
+ }), waiting = useDelayedFlag(selection.kind === "loading" && catalogError === void 0, WAIT_CUE_DELAY_MS);
3753
3810
  if (selection.kind === "loading") /* @__PURE__ */ return jsx(UnresolvedPage, {
3754
- error: error,
3811
+ error: catalogError,
3755
3812
  waiting: waiting
3756
3813
  });
3757
3814
  const wiring = {
@@ -3810,7 +3867,8 @@ function WorkflowPage({onOpenWorkflow: onOpenWorkflow, onSelectPage: onSelectPag
3810
3867
  /* @__PURE__ */ jsx(PageBody, {
3811
3868
  board: board,
3812
3869
  catalogEmpty: (definitions ?? []).length === 0,
3813
- error: error,
3870
+ catalogError: catalogError,
3871
+ instancesError: instances.error,
3814
3872
  loading: !revealed,
3815
3873
  page: page,
3816
3874
  selection: selection,
@@ -3848,8 +3906,8 @@ function UnresolvedPage({error: error, waiting: waiting}) {
3848
3906
  overflow: "hidden",
3849
3907
  children: error === void 0 ? /* @__PURE__ */ jsx(WaitingFace, {
3850
3908
  waiting: waiting
3851
- }) : /* @__PURE__ */ jsx(CatalogErrorFace, {
3852
- error: error
3909
+ }) : /* @__PURE__ */ jsx(ReadErrorFace, {
3910
+ text: CATALOG_READ_FAILED
3853
3911
  })
3854
3912
  });
3855
3913
  }
@@ -3865,18 +3923,24 @@ function WaitingFace({waiting: waiting}) {
3865
3923
  });
3866
3924
  }
3867
3925
 
3868
- function CatalogErrorFace({error: error}) {
3926
+ const BANNER_LANE_INSET = 2;
3927
+
3928
+ function ReadErrorFace({text: text}) {
3869
3929
  /* @__PURE__ */
3870
3930
  return jsx(StatusBox, {
3871
- children: /* @__PURE__ */ jsx(MutedNote, {
3872
- text: catalogReadError(error)
3931
+ children: /* @__PURE__ */ jsx(Box, {
3932
+ paddingTop: BANNER_LANE_INSET,
3933
+ children: /* @__PURE__ */ jsx(NoteBanner, {
3934
+ label: text,
3935
+ tone: "critical"
3936
+ })
3873
3937
  })
3874
3938
  });
3875
3939
  }
3876
3940
 
3877
- function PageBody({board: board, catalogEmpty: catalogEmpty, error: error, loading: loading, page: page, selection: selection, wiring: wiring}) {
3878
- if (error !== void 0) /* @__PURE__ */ return jsx(CatalogErrorFace, {
3879
- error: error
3941
+ function PageBody({board: board, catalogEmpty: catalogEmpty, catalogError: catalogError, instancesError: instancesError, loading: loading, page: page, selection: selection, wiring: wiring}) {
3942
+ if (catalogError !== void 0) /* @__PURE__ */ return jsx(ReadErrorFace, {
3943
+ text: CATALOG_READ_FAILED
3880
3944
  });
3881
3945
  if (selection.kind === "unknown") {
3882
3946
  const face = unknownWorkflowFace({
@@ -3894,6 +3958,8 @@ function PageBody({board: board, catalogEmpty: catalogEmpty, error: error, loadi
3894
3958
  }
3895
3959
  return page === "definition" ? /* @__PURE__ */ jsx(DefinitionPanel, {
3896
3960
  definition: selection.definition
3961
+ }) : instancesError !== void 0 ? /* @__PURE__ */ jsx(ReadErrorFace, {
3962
+ text: INSTANCES_READ_FAILED
3897
3963
  }) : loading || board === void 0 ? /* @__PURE__ */ jsx(StatusBox, {
3898
3964
  children: /* @__PURE__ */ jsx(Box, {
3899
3965
  paddingTop: LANE_PADDING,
@@ -4060,6 +4126,7 @@ function HomePanel({filterSlot: filterSlot, identity: identity, instances: insta
4060
4126
  return tab === "overview" ? /* @__PURE__ */ jsx(OverviewTab, {
4061
4127
  onOpenWorkflow: onOpenWorkflow
4062
4128
  }) : /* @__PURE__ */ jsx(TasksTab, {
4129
+ error: instances.error,
4063
4130
  filterSlot: filterSlot,
4064
4131
  identity: identity,
4065
4132
  instances: [ ...instances.inFlight, ...instances.settled ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/workflow-studio-plugin",
3
- "version": "0.27.0",
3
+ "version": "0.28.0",
4
4
  "description": "Sanity Studio plugin for @sanity/workflow-engine: the form strip, a Workflows document view, stage badges, and the document-action lock.",
5
5
  "keywords": [
6
6
  "sanity",
@@ -66,12 +66,12 @@
66
66
  "sanity": "^6",
67
67
  "styled-components": "^6.4.2",
68
68
  "vitest": "^4.1.8",
69
- "@sanity/workflow-components": "0.27.0",
70
- "@sanity/workflow-diagram": "0.27.0",
71
- "@sanity/workflow-engine": "0.27.0",
72
- "@sanity/workflow-engine-test": "0.27.0",
73
- "@sanity/workflow-react": "0.27.0",
74
- "@sanity/workflow-studio": "0.27.0"
69
+ "@sanity/workflow-components": "0.28.0",
70
+ "@sanity/workflow-diagram": "0.28.0",
71
+ "@sanity/workflow-engine": "0.28.0",
72
+ "@sanity/workflow-engine-test": "0.28.0",
73
+ "@sanity/workflow-react": "0.28.0",
74
+ "@sanity/workflow-studio": "0.28.0"
75
75
  },
76
76
  "peerDependencies": {
77
77
  "@sanity/sdk": "^2.12.0",
@@ -79,11 +79,11 @@
79
79
  "react-dom": "^19.2.7",
80
80
  "sanity": "^6.3.0",
81
81
  "styled-components": "^6.4.2",
82
- "@sanity/workflow-components": "0.27.0",
83
- "@sanity/workflow-diagram": "0.27.0",
84
- "@sanity/workflow-react": "0.27.0",
85
- "@sanity/workflow-studio": "0.27.0",
86
- "@sanity/workflow-engine": "0.27.0"
82
+ "@sanity/workflow-diagram": "0.28.0",
83
+ "@sanity/workflow-engine": "0.28.0",
84
+ "@sanity/workflow-react": "0.28.0",
85
+ "@sanity/workflow-studio": "0.28.0",
86
+ "@sanity/workflow-components": "0.28.0"
87
87
  },
88
88
  "engines": {
89
89
  "node": ">=20"