@sanity/sdk-react 3.4.0-rc.0 → 3.4.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.
Files changed (37) hide show
  1. package/dist/_exports/dashboard.d.ts +112 -34
  2. package/dist/_exports/dashboard.d.ts.map +1 -1
  3. package/dist/_exports/dashboard.js +219 -114
  4. package/dist/_exports/dashboard.js.map +1 -1
  5. package/dist/index.d.ts +21 -141
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +66 -147
  8. package/dist/index.js.map +1 -1
  9. package/dist/{useStudioWorkspacesByProjectIdDataset-B5A5kBH9.js → useStudioWorkspacesByProjectIdDataset-Bjwi4cLk.js} +60 -3
  10. package/dist/useStudioWorkspacesByProjectIdDataset-Bjwi4cLk.js.map +1 -0
  11. package/package.json +9 -9
  12. package/src/_exports/dashboard.test-d.ts +3 -0
  13. package/src/_exports/dashboard.ts +11 -2
  14. package/src/_exports/sdk-react.ts +0 -3
  15. package/src/components/auth/AuthBoundary.test.tsx +2 -81
  16. package/src/components/auth/AuthBoundary.tsx +3 -17
  17. package/src/components/auth/LoginCallback.test.tsx +7 -46
  18. package/src/components/auth/LoginCallback.tsx +4 -22
  19. package/src/hooks/dashboard/useAgentResourceContext.test.tsx +67 -2
  20. package/src/hooks/dashboard/useAgentResourceContext.ts +35 -6
  21. package/src/hooks/dashboard/useApplicationContext.test.tsx +95 -0
  22. package/src/hooks/dashboard/useApplicationContext.ts +47 -0
  23. package/src/hooks/dashboard/useCapabilities.test.tsx +84 -0
  24. package/src/hooks/dashboard/useCapabilities.ts +27 -0
  25. package/src/hooks/dashboard/useNavigate.test.ts +392 -5
  26. package/src/hooks/dashboard/useNavigate.ts +169 -26
  27. package/src/hooks/dashboard/useNavigateToStudioDocument.test.ts +116 -9
  28. package/src/hooks/dashboard/useNavigateToStudioDocument.ts +110 -39
  29. package/src/hooks/dashboard/useRecordDocumentHistoryEvent.test.ts +99 -1
  30. package/src/hooks/dashboard/useRecordDocumentHistoryEvent.ts +73 -2
  31. package/dist/useStudioWorkspacesByProjectIdDataset-B5A5kBH9.js.map +0 -1
  32. package/src/hooks/auth/useHandleOAuthCallback.test.tsx +0 -16
  33. package/src/hooks/auth/useHandleOAuthCallback.tsx +0 -49
  34. package/src/hooks/auth/useOAuthAuthorize.test.tsx +0 -16
  35. package/src/hooks/auth/useOAuthAuthorize.tsx +0 -28
  36. package/src/hooks/auth/useOAuthTokens.test.tsx +0 -240
  37. package/src/hooks/auth/useOAuthTokens.tsx +0 -95
@@ -1,12 +1,12 @@
1
- import { a as useWindowConnection, c as useSanityInstance, i as DashboardTokenRefreshProvider, n as useTopic, r as useOrganizationId, s as createStateSourceHook, t as useStudioWorkspacesByProjectIdDataset } from "../useStudioWorkspacesByProjectIdDataset-B5A5kBH9.js";
1
+ import { a as DashboardTokenRefreshProvider, c as createStateSourceHook, i as useOrganizationId, l as useSanityInstance, n as useTopic, o as useWindowConnection, r as useEmit, t as useStudioWorkspacesByProjectIdDataset } from "../useStudioWorkspacesByProjectIdDataset-Bjwi4cLk.js";
2
2
  import { c } from "react-compiler-runtime";
3
3
  import "@sanity/sdk";
4
4
  import { createLogger, getApplicationOrigin, isDashboardEnvironment, requireDashboardMessageBus } from "@sanity/sdk/_internal";
5
- import { useEffect, useRef, useState } from "react";
5
+ import { useCallback, useEffect, useEffectEvent, useRef, useState } from "react";
6
6
  import { SDK_CHANNEL_NAME, SDK_NODE_NAME } from "@sanity/message-protocol";
7
7
  import "@sanity/sdk/comlink";
8
- import { of } from "rxjs";
9
- import { MessageBusError, TopicError, connectMessageBus } from "@sanity/sdk/dashboard";
8
+ import { filter, map, of, pairwise } from "rxjs";
9
+ import { MessageBusError, TopicError, TopicError as TopicError$1, capabilities, connectMessageBus } from "@sanity/sdk/dashboard";
10
10
  import "@sanity/types";
11
11
  import { createInstance } from "@module-federation/runtime";
12
12
  import "@module-federation/runtime/types";
@@ -382,13 +382,53 @@ const createRootBuilder = (Builder, ...segments) => new Builder(appendSegments(n
382
382
  return Object.assign(urls, methods);
383
383
  }, urlFor = createUrls({});
384
384
  /**
385
+ * Publishes what this application is currently showing to the Dashboard message bus, so the host
386
+ * can hold the foreground application's context. Pass `null` when nothing is open.
387
+ *
388
+ * The context is published on mount and whenever it changes, and cleared with `null` on unmount.
389
+ * A change publishes `null` before the new context, as the component has stopped showing the old
390
+ * one. Pass a memoised value: the hook compares by reference, so a new object on every render
391
+ * republishes on every render.
392
+ *
393
+ * The host reads the sending application from `message.meta.appId`, so the payload carries no
394
+ * application ID.
395
+ *
396
+ * @param context - The application context to publish, or `null` to clear it
397
+ *
398
+ * @example
399
+ * ```tsx
400
+ * import {useApplicationContext} from '@sanity/sdk-react/dashboard'
401
+ * import {useMemo} from 'react'
402
+ *
403
+ * function DocumentView({documentId}: {documentId: string}) {
404
+ * const context = useMemo(
405
+ * () => ({resource: {id: 'my-project.production', type: 'dataset' as const}, document: {id: documentId}}),
406
+ * [documentId],
407
+ * )
408
+ * useApplicationContext(context)
409
+ * return <div>Editing {documentId}</div>
410
+ * }
411
+ * ```
412
+ *
413
+ * @public
414
+ * @category Dashboard
415
+ */
416
+ function useApplicationContext(context) {
417
+ let $ = c(4), emit = useEmit("applications.context.update"), t0, t1;
418
+ $[0] !== context || $[1] !== emit ? (t0 = () => (emit(context), () => {
419
+ emit(null);
420
+ }), t1 = [emit, context], $[0] = context, $[1] = emit, $[2] = t0, $[3] = t1) : (t0 = $[2], t1 = $[3]), useEffect(t0, t1);
421
+ }
422
+ /**
385
423
  * @public
386
- * Hook for emitting agent resource context updates to the Dashboard.
387
- * This allows the Agent to understand what resource the user is currently
388
- * interacting with (e.g., which document they're editing).
424
+ * Hook for reporting the resource the user is currently interacting with (for example, which
425
+ * document they're editing) so the Agent can understand their context. The hook reports on mount
426
+ * and again whenever the context changes.
389
427
  *
390
- * The hook will automatically emit the context when it changes, and also
391
- * emit the initial context when the hook is first mounted.
428
+ * The two Dashboard runtimes differ in transport, but the signature is the same:
429
+ * - In an iframe (Comlink), it emits the `dashboard/v1/events/agent/resource/update` event.
430
+ * - In a federated app (message bus), it publishes {@link useApplicationContext}'s
431
+ * `applications.context.update` topic. Reach for `useApplicationContext` directly in new code.
392
432
  *
393
433
  * @category Agent
394
434
  * @param options - The resource context options containing projectId, dataset, and optional documentId
@@ -412,6 +452,19 @@ const createRootBuilder = (Builder, ...segments) => new Builder(appendSegments(n
412
452
  * ```
413
453
  */
414
454
  function useAgentResourceContext(options) {
455
+ return isDashboardEnvironment() ? useBusAgentResourceContext(options) : useComlinkAgentResourceContext(options);
456
+ }
457
+ function useBusAgentResourceContext(t0) {
458
+ let $ = c(4), { projectId, dataset, documentId } = t0, t1;
459
+ $[0] !== dataset || $[1] !== documentId || $[2] !== projectId ? (t1 = projectId && dataset ? {
460
+ resource: {
461
+ id: `${projectId}.${dataset}`,
462
+ type: "dataset"
463
+ },
464
+ document: documentId ? { id: documentId } : null
465
+ } : null, $[0] = dataset, $[1] = documentId, $[2] = projectId, $[3] = t1) : t1 = $[3], useApplicationContext(t1);
466
+ }
467
+ function useComlinkAgentResourceContext(options) {
415
468
  let $ = c(9), { projectId, dataset, documentId } = options, t0;
416
469
  $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = {
417
470
  name: SDK_NODE_NAME,
@@ -622,132 +675,184 @@ function useAuthToken() {
622
675
  return useTopic("auth.token");
623
676
  }
624
677
  /**
625
- * Returns the signed-in user, or `null` while signed out.
678
+ * Returns the capabilities the host provides.
626
679
  *
627
- * Suspends until Dashboard publishes the current user.
680
+ * A capability is something the host provides; an application reads this record to hide its own
681
+ * implementation of anything the host provides, or to skip publishing to a capability the host
682
+ * does not have. A missing key means the host does not provide that capability.
683
+ *
684
+ * Suspends until the host publishes the record.
628
685
  *
629
686
  * @example
630
687
  * ```tsx
631
- * function CurrentUser() {
632
- * const user = useCurrentUser()
633
- * return <span>{user?.name ?? 'Signed out'}</span>
688
+ * function UserMenu() {
689
+ * const {globalUserMenu} = useCapabilities()
690
+ * if (globalUserMenu) return null
691
+ * return <LocalUserMenu />
634
692
  * }
635
693
  * ```
636
694
  *
637
695
  * @public
638
696
  */
639
- function useCurrentUser() {
640
- return useTopic("users.current");
697
+ function useCapabilities() {
698
+ return useTopic("applications.capabilities");
641
699
  }
642
700
  /**
643
- * Returns a stable function that emits a dashboard event topic.
644
- *
645
- * The event is sent immediately. Ignore the lazy result for fire-and-forget delivery, await it
646
- * inside `useTransition` to track a reply, or read it with React `use` to suspend. A reply
647
- * that fails (`NO_RESPONDER`, `TIMEOUT`, `ABORTED`) rejects the result; when read with `use`
648
- * that reaches the nearest error boundary, so pair the `Suspense` with one.
701
+ * Returns the signed-in user, or `null` while signed out.
649
702
  *
650
- * @example Fire and forget
651
- * ```tsx
652
- * function ExpandPanel() {
653
- * const setPanelMode = useEmit('panels.mode.set')
654
- * return (
655
- * <button onClick={() => setPanelMode({name: 'favorites', mode: 'full'})}>
656
- * Expand
657
- * </button>
658
- * )
659
- * }
660
- * ```
703
+ * Suspends until Dashboard publishes the current user.
661
704
  *
662
- * @example Await a reply with Suspense
705
+ * @example
663
706
  * ```tsx
664
- * function Session({request}: {request: MessageBusEmitResult<string>}) {
665
- * use(request)
666
- * return <p>Ready</p>
667
- * }
668
- *
669
- * function SessionAccordion() {
670
- * const refreshToken = useEmit('auth.token.refresh')
671
- * const [request, setRequest] = useState<MessageBusEmitResult<string> | null>(null)
672
- *
673
- * return (
674
- * <details
675
- * onToggle={(event) => setRequest(event.currentTarget.open ? refreshToken() : null)}
676
- * >
677
- * <summary>Session</summary>
678
- * <ErrorBoundary fallback={<p>Could not refresh</p>}>
679
- * <Suspense fallback={<p>Refreshing...</p>}>
680
- * {request && <Session request={request} />}
681
- * </Suspense>
682
- * </ErrorBoundary>
683
- * </details>
684
- * )
707
+ * function CurrentUser() {
708
+ * const user = useCurrentUser()
709
+ * return <span>{user?.name ?? 'Signed out'}</span>
685
710
  * }
686
711
  * ```
687
712
  *
688
713
  * @public
689
714
  */
690
- function useEmit(topic) {
691
- let $ = c(6), instance = useSanityInstance(), t0 = `emit topic "${topic}"`, t1;
692
- $[0] !== instance || $[1] !== t0 ? (t1 = requireDashboardMessageBus(instance, t0), $[0] = instance, $[1] = t0, $[2] = t1) : t1 = $[2];
693
- let messageBus = t1, t2;
694
- return $[3] !== messageBus || $[4] !== topic ? (t2 = (...t3) => {
695
- let args = t3;
696
- return messageBus.emit(topic, ...args);
697
- }, $[3] = messageBus, $[4] = topic, $[5] = t2) : t2 = $[5], t2;
715
+ function useCurrentUser() {
716
+ return useTopic("users.current");
698
717
  }
699
718
  /**
700
719
  * @public
701
720
  *
702
721
  * A helper hook designed to be injected into routing components for apps within the Dashboard.
703
- * While the Dashboard can usually handle navigation, there are special cases when you
704
- * are already within a target app, and need to navigate to another route inside of that app.
722
+ * It keeps the app's router and the Dashboard in two-way sync: `navigateFn` receives the
723
+ * navigations the Dashboard asks the app to perform, and the returned function reports the app's
724
+ * own in-app navigations back to the Dashboard so the browser URL and the Dashboard's router
725
+ * follow along.
705
726
  *
706
- * For example, your user might "favorite" a document inside of your application.
707
- * If they click on the Dashboard favorites item in the sidebar, and are already within your application,
708
- * there needs to be some way for the dashboard to signal to your application to reroute to where that document was favorited.
727
+ * A navigation the app reports is not echoed back through `navigateFn`. The returned function is
728
+ * referentially stable.
709
729
  *
710
- * This hook is intended to receive those messages, and takes a function to route to the correct path.
730
+ * The two Dashboard runtimes differ:
731
+ * - In an iframe (Comlink), inbound `type` may be `'push'`, `'replace'` or `'pop'`. Reporting is
732
+ * optional because the bridge already forwards the iframe's own `pushState`; a reported `type`
733
+ * is ignored and the host applies the URL as a `replace`.
734
+ * - In a federated app (message bus), inbound `type` is `'push'` or `'replace'`; `'pop'` is never
735
+ * sent. Reporting is required because the app's router does not reach the host, and `type` is
736
+ * honoured. Until the Dashboard publishes the app's base path, reports are dropped with a
737
+ * console warning.
711
738
  *
712
739
  * @param navigateFn - Function to handle navigation; should accept:
713
740
  * - `path`: a string, which will be a relative path (for example, 'my-route')
714
741
  * - `type`: 'push', 'replace', or 'pop', which will be the type of navigation to perform
742
+ * @returns A function the app calls to report its own in-app navigations to the Dashboard.
715
743
  *
716
744
  * @example
717
745
  * ```tsx
718
746
  * import {useNavigate} from '@sanity/sdk-react/dashboard'
719
- * import {BrowserRouter, useNavigate as useRouterNavigate} from 'react-router'
720
- * import {Suspense} from 'react'
747
+ * import {useEffect} from 'react'
748
+ * import {useLocation, useNavigate as useRouterNavigate} from 'react-router'
721
749
  *
722
- * function DashboardNavigationHandler() {
723
- * const navigate = useRouterNavigate()
724
- * useNavigate(({path, type}) => {
725
- * navigate(path, {replace: type === 'replace'})
750
+ * function DashboardNavigationSync() {
751
+ * const routerNavigate = useRouterNavigate()
752
+ * const {pathname, search, hash} = useLocation()
753
+ * const navigate = useNavigate(({path, type}) => {
754
+ * routerNavigate(path, {replace: type === 'replace'})
726
755
  * })
756
+ * useEffect(() => {
757
+ * navigate({path: `${pathname.slice(1)}${search}${hash}`})
758
+ * }, [navigate, pathname, search, hash])
727
759
  * return null
728
760
  * }
729
- *
730
- * // Wrap the component with Suspense since the hook may suspend
731
- * function MyApp() {
732
- * return (
733
- * <BrowserRouter>
734
- * <Suspense>
735
- * <DashboardNavigationHandler />
736
- * </Suspense>
737
- * </BrowserRouter>
738
- * )
739
- * }
740
761
  * ```
741
762
  */
742
763
  function useNavigate(navigateFn) {
743
- let $ = c(2), t0;
764
+ return isDashboardEnvironment() ? useBusNavigate(navigateFn) : useComlinkNavigate(navigateFn);
765
+ }
766
+ function useComlinkNavigate(navigateFn) {
767
+ let $ = c(4), t0;
744
768
  $[0] === navigateFn ? t0 = $[1] : (t0 = {
745
769
  name: SDK_NODE_NAME,
746
770
  connectTo: SDK_CHANNEL_NAME,
747
771
  onMessage: { "dashboard/v1/history/change-path": (data) => {
748
772
  navigateFn(data);
749
773
  } }
750
- }, $[0] = navigateFn, $[1] = t0), useWindowConnection(t0);
774
+ }, $[0] = navigateFn, $[1] = t0);
775
+ let { sendMessage } = useWindowConnection(t0), t1;
776
+ return $[2] === sendMessage ? t1 = $[3] : (t1 = (t2) => {
777
+ let { path } = t2;
778
+ return sendMessage("dashboard/v1/bridge/listeners/history/update-url", { url: new URL(path, window.location.origin).href });
779
+ }, $[2] = sendMessage, $[3] = t1), t1;
780
+ }
781
+ function joinPath(base, path) {
782
+ let root = base.replace(/\/$/, "");
783
+ return path ? `${root}/${path}` : root;
784
+ }
785
+ function useBusNavigate(navigateFn) {
786
+ let $ = c(9), instance = useSanityInstance(), t0;
787
+ $[0] === instance ? t0 = $[1] : (t0 = requireDashboardMessageBus(instance, "navigate"), $[0] = instance, $[1] = t0);
788
+ let bus = t0, navigate = useEffectEvent(navigateFn), ownRequest = useRef(null), t1;
789
+ $[2] !== bus || $[3] !== navigate ? (t1 = () => {
790
+ let sub = bus.subscribe("navigation.location").pipe(pairwise(), filter((pair) => {
791
+ let [prev, curr] = pair;
792
+ return curr?.transition === null && curr.appId === bus.appId && prev?.transition?.to.appId === bus.appId && prev.transition.to.path === curr.path;
793
+ }), filter((t2) => {
794
+ let [, curr_0] = t2, suppress = curr_0.path === ownRequest.current;
795
+ return ownRequest.current = null, !suppress;
796
+ }), map(_temp$1)).subscribe((change) => navigate(change));
797
+ return () => sub.unsubscribe();
798
+ }, $[2] = bus, $[3] = navigate, $[4] = t1) : t1 = $[4];
799
+ let t2;
800
+ $[5] === bus ? t2 = $[6] : (t2 = [bus], $[5] = bus, $[6] = t2), useEffect(t1, t2);
801
+ let t3;
802
+ return $[7] === bus ? t3 = $[8] : (t3 = (t4) => {
803
+ let { path, type: t5 } = t4, type = t5 === void 0 ? "push" : t5, own = path.replace(/^\//, "");
804
+ ownRequest.current = own;
805
+ let clearIfStale = () => {
806
+ ownRequest.current === own && (ownRequest.current = null);
807
+ };
808
+ bus.query("applications.base-path").then((base) => {
809
+ if (!base.ok) throw new TopicError$1("applications.base-path");
810
+ return bus.emit("navigation.location.update", {
811
+ url: joinPath(base.value, own),
812
+ history: type
813
+ });
814
+ }).then((reply) => {
815
+ reply.ok || clearIfStale();
816
+ }, (error) => {
817
+ console.warn("Failed to report navigation to the Dashboard", error), clearIfStale();
818
+ });
819
+ }, $[7] = bus, $[8] = t3), t3;
820
+ }
821
+ function _temp$1(t0) {
822
+ let [prev_0, curr_1] = t0;
823
+ return {
824
+ path: curr_1.path,
825
+ type: prev_0.transition.navigationType
826
+ };
827
+ }
828
+ function useComlinkStudioNavigator(documentHandle) {
829
+ let $ = c(5), t0;
830
+ $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = {
831
+ name: SDK_NODE_NAME,
832
+ connectTo: SDK_CHANNEL_NAME
833
+ }, $[0] = t0) : t0 = $[0];
834
+ let { sendMessage } = useWindowConnection(t0), t1;
835
+ return $[1] !== documentHandle.documentId || $[2] !== documentHandle.documentType || $[3] !== sendMessage ? (t1 = (workspace) => {
836
+ let message = {
837
+ type: "dashboard/v1/bridge/navigate-to-resource",
838
+ data: {
839
+ resourceId: workspace.id,
840
+ resourceType: "studio",
841
+ path: `/intent/edit/id=${documentHandle.documentId};type=${documentHandle.documentType}`
842
+ }
843
+ };
844
+ sendMessage(message.type, message.data);
845
+ }, $[1] = documentHandle.documentId, $[2] = documentHandle.documentType, $[3] = sendMessage, $[4] = t1) : t1 = $[4], t1;
846
+ }
847
+ function useBusStudioNavigator(documentHandle) {
848
+ let $ = c(4), navigate = useEmit("navigation.location.update"), t0;
849
+ return $[0] !== documentHandle.documentId || $[1] !== documentHandle.documentType || $[2] !== navigate ? (t0 = (workspace) => {
850
+ let url = urlFor.studios(workspace.userApplicationId).workspace(workspace.name).intent("edit", {
851
+ id: documentHandle.documentId,
852
+ type: documentHandle.documentType
853
+ }).url();
854
+ navigate({ url }).then(_temp, _temp2);
855
+ }, $[0] = documentHandle.documentId, $[1] = documentHandle.documentType, $[2] = navigate, $[3] = t0) : t0 = $[3], t0;
751
856
  }
752
857
  /**
753
858
  * @public
@@ -757,6 +862,9 @@ function useNavigate(navigateFn) {
757
862
  * Uses the `projectId` and `dataset` properties of the {@link DocumentHandle} you provide to resolve the correct Studio.
758
863
  * This will only work if you have deployed a studio with a workspace with this `projectId` / `dataset` combination.
759
864
  *
865
+ * Works in both Dashboard runtimes: it sends the navigation over the Comlink connection in the
866
+ * iframe runtime and over the message bus in the federated runtime.
867
+ *
760
868
  * @remarks If you write your own Document Handle to pass to this hook (as opposed to a Document Handle generated by another hook),
761
869
  * it must include values for `documentId`, `documentType`, `projectId`, and `dataset`.
762
870
  *
@@ -794,41 +902,38 @@ function useNavigate(navigateFn) {
794
902
  * }
795
903
  * ```
796
904
  */
905
+ function _temp2(error) {
906
+ console.warn("Failed to navigate to studio document", error);
907
+ }
908
+ function _temp(reply) {
909
+ reply.ok === !1 && console.warn("Failed to navigate to studio document", reply);
910
+ }
797
911
  function useNavigateToStudioDocument(documentHandle, preferredStudioUrl) {
798
- let $ = c(8), { workspacesByProjectIdAndDataset } = useStudioWorkspacesByProjectIdDataset(), t0;
799
- $[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = {
800
- name: SDK_NODE_NAME,
801
- connectTo: SDK_CHANNEL_NAME
802
- }, $[0] = t0) : t0 = $[0];
803
- let { sendMessage } = useWindowConnection(t0), t1;
804
- $[1] !== documentHandle || $[2] !== preferredStudioUrl || $[3] !== sendMessage || $[4] !== workspacesByProjectIdAndDataset ? (t1 = () => {
912
+ let { workspacesByProjectIdAndDataset } = useStudioWorkspacesByProjectIdDataset(), sendToWorkspace = isDashboardEnvironment() ? useBusStudioNavigator(documentHandle) : useComlinkStudioNavigator(documentHandle);
913
+ return { navigateToStudioDocument: useCallback(() => {
805
914
  let { projectId, dataset } = documentHandle;
806
915
  if (!projectId || !dataset) {
807
916
  console.warn("Project ID and dataset are required to navigate to a studio document");
808
917
  return;
809
918
  }
810
- let workspace;
811
- if (preferredStudioUrl) workspace = [...workspacesByProjectIdAndDataset[`${projectId}:${dataset}`] || [], ...workspacesByProjectIdAndDataset["NO_PROJECT_ID:NO_DATASET"] || []].find((w) => w.url === preferredStudioUrl);
812
- else {
813
- let workspaces = workspacesByProjectIdAndDataset[`${projectId}:${dataset}`];
814
- workspaces?.length > 1 && (console.warn("Multiple workspaces found for document and no preferred studio url", documentHandle), console.warn("Using the first one", workspaces[0])), workspace = workspaces?.[0];
815
- }
919
+ let workspace = resolveWorkspace(documentHandle, workspacesByProjectIdAndDataset, preferredStudioUrl);
816
920
  if (!workspace) {
817
921
  console.warn(`No workspace found for document with projectId: ${projectId} and dataset: ${dataset}${preferredStudioUrl ? ` or with preferred studio url: ${preferredStudioUrl}` : ""}`);
818
922
  return;
819
923
  }
820
- let message = {
821
- type: "dashboard/v1/bridge/navigate-to-resource",
822
- data: {
823
- resourceId: workspace.id,
824
- resourceType: "studio",
825
- path: `/intent/edit/id=${documentHandle.documentId};type=${documentHandle.documentType}`
826
- }
827
- };
828
- sendMessage(message.type, message.data);
829
- }, $[1] = documentHandle, $[2] = preferredStudioUrl, $[3] = sendMessage, $[4] = workspacesByProjectIdAndDataset, $[5] = t1) : t1 = $[5];
830
- let navigateToStudioDocument = t1, t2;
831
- return $[6] === navigateToStudioDocument ? t2 = $[7] : (t2 = { navigateToStudioDocument }, $[6] = navigateToStudioDocument, $[7] = t2), t2;
924
+ sendToWorkspace(workspace);
925
+ }, [
926
+ documentHandle,
927
+ workspacesByProjectIdAndDataset,
928
+ preferredStudioUrl,
929
+ sendToWorkspace
930
+ ]) };
931
+ }
932
+ function resolveWorkspace(documentHandle, workspacesByProjectIdAndDataset, preferredStudioUrl) {
933
+ let { projectId, dataset } = documentHandle, key = `${projectId}:${dataset}`;
934
+ if (preferredStudioUrl) return [...workspacesByProjectIdAndDataset[key] || [], ...workspacesByProjectIdAndDataset["NO_PROJECT_ID:NO_DATASET"] || []].find((w) => w.url === preferredStudioUrl);
935
+ let workspaces = workspacesByProjectIdAndDataset[key];
936
+ return workspaces && workspaces.length > 1 && (console.warn("Multiple workspaces found for document and no preferred studio url", documentHandle), console.warn("Using the first one", workspaces[0])), workspaces?.[0];
832
937
  }
833
938
  const remoteClientStates = /* @__PURE__ */ new WeakMap();
834
939
  /** Returns the instance's remote client state, creating it on first use. @internal */
@@ -925,6 +1030,6 @@ function useComlinkWindowTitle(viewTitle) {
925
1030
  };
926
1031
  }, [viewTitle, appTitle]);
927
1032
  }
928
- export { MessageBusError, DashboardTokenRefreshProvider as TokenRefreshProvider, TopicError, UrlBuilder, connectMessageBus, createRemoteInstance, urlFor, useAgentResourceContext, useApplication, useApplicationBasePath, useApplicationConfig, useApplicationConfigs, useApplicationForegroundId, useApplications, useAuthToken, useCurrentUser, useEmit, useNavigate, useNavigateToStudioDocument, useOrganizationId, useRemoteClient, useTopic, useWindowTitle };
1033
+ export { MessageBusError, DashboardTokenRefreshProvider as TokenRefreshProvider, TopicError, UrlBuilder, capabilities, connectMessageBus, createRemoteInstance, urlFor, useAgentResourceContext, useApplication, useApplicationBasePath, useApplicationConfig, useApplicationConfigs, useApplicationContext, useApplicationForegroundId, useApplications, useAuthToken, useCapabilities, useCurrentUser, useEmit, useNavigate, useNavigateToStudioDocument, useOrganizationId, useRemoteClient, useTopic, useWindowTitle };
929
1034
 
930
1035
  //# sourceMappingURL=dashboard.js.map