@sanity/sdk-react 3.0.0-rc.2 → 3.1.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/dist/_exports/dashboard.d.ts +250 -0
- package/dist/_exports/dashboard.d.ts.map +1 -0
- package/dist/_exports/dashboard.js +278 -0
- package/dist/_exports/dashboard.js.map +1 -0
- package/dist/index.d.ts +86 -261
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +114 -616
- package/dist/index.js.map +1 -1
- package/dist/useStudioWorkspacesByProjectIdDataset-DxUlukmF.js +317 -0
- package/dist/useStudioWorkspacesByProjectIdDataset-DxUlukmF.js.map +1 -0
- package/package.json +12 -11
- package/src/_exports/dashboard.ts +12 -0
- package/src/_exports/sdk-react.ts +2 -12
- package/src/components/SDKProvider.test.tsx +5 -5
- package/src/components/auth/AuthBoundary.tsx +5 -5
- package/src/context/{WorkbenchTokenRefresh.test.tsx → DashboardTokenRefresh.test.tsx} +26 -26
- package/src/context/DashboardTokenRefresh.tsx +95 -0
- package/src/context/OrganizationResourcesProvider.test.tsx +9 -9
- package/src/context/OrganizationResourcesProvider.tsx +2 -2
- package/src/context/dashboardToken.ts +63 -0
- package/src/hooks/comlink/useWindowConnection.ts +1 -1
- package/src/hooks/{agent → dashboard}/useAgentResourceContext.ts +1 -1
- package/src/hooks/dashboard/useFavorite.test.tsx +101 -0
- package/src/hooks/dashboard/useFavorite.ts +34 -0
- package/src/hooks/dashboard/useFavoriteContext.ts +61 -0
- package/src/hooks/dashboard/{useDashboardNavigate.test.ts → useNavigate.test.ts} +3 -3
- package/src/hooks/dashboard/{useDashboardNavigate.ts → useNavigate.ts} +5 -5
- package/src/hooks/dashboard/useNavigateToStudioDocument.ts +2 -1
- package/src/hooks/{auth/useDashboardOrganizationId.test.tsx → dashboard/useOrganizationId.test.tsx} +4 -4
- package/src/hooks/{auth/useDashboardOrganizationId.tsx → dashboard/useOrganizationId.tsx} +2 -2
- package/src/hooks/dashboard/useUpdateFavorite.test.tsx +146 -0
- package/src/hooks/dashboard/useUpdateFavorite.ts +74 -0
- package/src/hooks/dashboard/useWindowTitle.ts +1 -1
- package/src/hooks/datasets/useDatasets.test.tsx +29 -22
- package/src/hooks/datasets/useDatasets.ts +31 -53
- package/src/hooks/document/useCreateDocument.ts +2 -1
- package/src/utils/resolveOrgResources.test.ts +2 -2
- package/src/utils/resolveOrgResources.ts +2 -2
- package/src/context/WorkbenchTokenRefresh.tsx +0 -61
- package/src/context/workbenchToken.ts +0 -63
- package/src/hooks/dashboard/useManageFavorite.test.tsx +0 -379
- package/src/hooks/dashboard/useManageFavorite.ts +0 -173
- /package/src/hooks/{agent → dashboard}/useAgentResourceContext.test.tsx +0 -0
package/dist/index.js
CHANGED
|
@@ -1,108 +1,19 @@
|
|
|
1
|
+
import { a as useWindowConnection, c as useSanityInstance, i as isDashboardEnvironment, l as SanityInstanceContext, n as useOrganizationId, o as useAuthState, r as DashboardTokenRefreshProvider, s as createStateSourceHook, t as useStudioWorkspacesByProjectIdDataset } from "./useStudioWorkspacesByProjectIdDataset-DxUlukmF.js";
|
|
1
2
|
import { c } from "react-compiler-runtime";
|
|
2
3
|
import { ClientError, CorsOriginError } from "@sanity/client";
|
|
3
|
-
import { AuthStateType, application, applications, applyDocumentActions, checkPermissions, createComment, createDocument, createSanityInstance, deleteApplication, editDocument, getActiveReleasesState, getAllReleasesState,
|
|
4
|
-
import { PREVIEW_PROJECTION, createGroqSearchFilter, getClientErrorApiBody, getClientErrorApiDescription, getCommentsOptionsKey, getQueryKey, getUsersKey, initTelemetry, isDeepEqual, isProjectUserNotFoundClientError, isStudioConfig, parseCommentsOptionsKey, parseQueryKey, parseUsersKey, pickProperties, trackHookMounted, transformProjectionToPreview } from "@sanity/sdk/_internal";
|
|
4
|
+
import { AuthStateType, application, applications, applyDocumentActions, checkPermissions, createComment, createDocument, createSanityInstance, datasets, deleteApplication, editDocument, favorites, getActiveReleasesState, getAllReleasesState, getClientState, getCommentThreadsState, getCommentsState, getCorsErrorProjectId, getCurrentUserState, getDocumentPresence, getDocumentState, getDocumentSyncStatus, getIsInDashboardState, getLoginUrlState, getPermissionsState, getPerspectiveState, getPresence, getProjectionState, getQueryState, getTokenState, getUsersState, handleAuthCallback, installation, installations, isDatasetResource, isImportError, isMediaLibraryResource, loadMoreUsers, logout, observeOrganizationVerificationState, organization, organizations, project, projects, removeComment, replyToComment, reportPresence, resolveCommentThreads, resolveComments, resolveDocument, resolveProjection, resolveQuery, resolveUsers, setAuthToken, setCommentStatus, setFavorite, subscribeDocumentEvents, updateApplication, updateComment } from "@sanity/sdk";
|
|
5
|
+
import { PREVIEW_PROJECTION, createGroqSearchFilter, getClientErrorApiBody, getClientErrorApiDescription, getCommentsOptionsKey, getQueryKey, getUsersKey, initTelemetry, isDeepEqual, isProjectUserNotFoundClientError, isStudioConfig, parseCommentsOptionsKey, parseQueryKey, parseUsersKey, pickProperties, randomUuid, trackHookMounted, transformProjectionToPreview } from "@sanity/sdk/_internal";
|
|
5
6
|
import { StrictMode, Suspense, createContext, use, useCallback, useContext, useEffect, useInsertionEffect, useMemo, useRef, useState, useSyncExternalStore, useTransition } from "react";
|
|
6
7
|
import { ErrorBoundary, getErrorMessage } from "react-error-boundary";
|
|
7
8
|
import { SDK_CHANNEL_NAME, SDK_NODE_NAME } from "@sanity/message-protocol";
|
|
8
|
-
import {
|
|
9
|
-
import { EMPTY, Observable, distinctUntilChanged, filter, firstValueFrom,
|
|
9
|
+
import { getOrCreateChannel, getOrCreateController, releaseChannel } from "@sanity/sdk/comlink";
|
|
10
|
+
import { EMPTY, Observable, distinctUntilChanged, filter, firstValueFrom, identity, startWith, switchMap } from "rxjs";
|
|
10
11
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
11
|
-
import { catchError, switchMap as switchMap$1 } from "rxjs/operators";
|
|
12
12
|
import { createRoot } from "react-dom/client";
|
|
13
13
|
import { agentGenerate, agentPatch, agentPrompt, agentTransform, agentTranslate } from "@sanity/sdk/agent";
|
|
14
14
|
import "groq";
|
|
15
15
|
import "@sanity/types";
|
|
16
16
|
export * from "@sanity/sdk";
|
|
17
|
-
const SanityInstanceContext = createContext(null), useSanityInstance = () => {
|
|
18
|
-
let instance = useContext(SanityInstanceContext);
|
|
19
|
-
if (!instance) throw Error("SanityInstance context not found. Please ensure that your component is wrapped in a ResourceProvider or a SanityApp component.");
|
|
20
|
-
return instance;
|
|
21
|
-
};
|
|
22
|
-
function createStateSourceHook(options) {
|
|
23
|
-
let getState = typeof options == "function" ? options : options.getState, suspense = "shouldSuspend" in options && "suspender" in options ? options : void 0;
|
|
24
|
-
function useHook(...t0) {
|
|
25
|
-
let $ = c(3), params = t0, instance = useSanityInstance();
|
|
26
|
-
if (suspense?.suspender && suspense?.shouldSuspend?.(instance, ...params)) throw suspense.suspender(instance, ...params);
|
|
27
|
-
let t1;
|
|
28
|
-
$[0] !== instance || $[1] !== params ? (t1 = getState(instance, ...params), $[0] = instance, $[1] = params, $[2] = t1) : t1 = $[2];
|
|
29
|
-
let state = t1;
|
|
30
|
-
return useSyncExternalStore(state.subscribe, state.getCurrent);
|
|
31
|
-
}
|
|
32
|
-
return useHook;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* @internal
|
|
36
|
-
* A React hook that subscribes to authentication state changes.
|
|
37
|
-
*
|
|
38
|
-
* This hook provides access to the current authentication state type from the Sanity auth store.
|
|
39
|
-
* It automatically re-renders when the authentication state changes.
|
|
40
|
-
*
|
|
41
|
-
* @remarks
|
|
42
|
-
* The hook uses `useSyncExternalStore` to safely subscribe to auth state changes
|
|
43
|
-
* and ensure consistency between server and client rendering.
|
|
44
|
-
*
|
|
45
|
-
* @returns The current authentication state type
|
|
46
|
-
*
|
|
47
|
-
* @example
|
|
48
|
-
* ```tsx
|
|
49
|
-
* function AuthStatus() {
|
|
50
|
-
* const authState = useAuthState()
|
|
51
|
-
* return <div>Current auth state: {authState}</div>
|
|
52
|
-
* }
|
|
53
|
-
* ```
|
|
54
|
-
*/
|
|
55
|
-
const useAuthState = createStateSourceHook(getAuthState), useNodeState = createStateSourceHook({
|
|
56
|
-
getState: getNodeState,
|
|
57
|
-
shouldSuspend: (instance, nodeInput) => getNodeState(instance, nodeInput).getCurrent() === void 0,
|
|
58
|
-
suspender: (instance, nodeInput) => firstValueFrom(getNodeState(instance, nodeInput).observable.pipe(filter(Boolean)))
|
|
59
|
-
});
|
|
60
|
-
/**
|
|
61
|
-
* @internal
|
|
62
|
-
* Hook to wrap a Comlink node in a React hook.
|
|
63
|
-
* Our store functionality takes care of the lifecycle of the node,
|
|
64
|
-
* as well as sharing a single node between invocations if they share the same name.
|
|
65
|
-
*
|
|
66
|
-
* Generally not to be used directly, but to be used as a dependency of
|
|
67
|
-
* Comlink-powered hooks like `useManageFavorite`.
|
|
68
|
-
*/
|
|
69
|
-
function useWindowConnection(t0) {
|
|
70
|
-
let $ = c(19), { name, connectTo, onMessage } = t0, t1;
|
|
71
|
-
$[0] !== connectTo || $[1] !== name ? (t1 = {
|
|
72
|
-
name,
|
|
73
|
-
connectTo
|
|
74
|
-
}, $[0] = connectTo, $[1] = name, $[2] = t1) : t1 = $[2];
|
|
75
|
-
let { node } = useNodeState(t1), t2;
|
|
76
|
-
$[3] === Symbol.for("react.memo_cache_sentinel") ? (t2 = [], $[3] = t2) : t2 = $[3];
|
|
77
|
-
let messageUnsubscribers = useRef(t2), instance = useSanityInstance(), t3;
|
|
78
|
-
$[4] !== node || $[5] !== onMessage ? (t3 = () => (onMessage && Object.entries(onMessage).forEach((t4) => {
|
|
79
|
-
let [type, handler] = t4, messageUnsubscribe = node.on(type, handler);
|
|
80
|
-
messageUnsubscribe && messageUnsubscribers.current.push(messageUnsubscribe);
|
|
81
|
-
}), () => {
|
|
82
|
-
messageUnsubscribers.current.forEach(_temp$9), messageUnsubscribers.current = [];
|
|
83
|
-
}), $[4] = node, $[5] = onMessage, $[6] = t3) : t3 = $[6];
|
|
84
|
-
let t4;
|
|
85
|
-
$[7] !== instance || $[8] !== name || $[9] !== node || $[10] !== onMessage ? (t4 = [
|
|
86
|
-
instance,
|
|
87
|
-
name,
|
|
88
|
-
onMessage,
|
|
89
|
-
node
|
|
90
|
-
], $[7] = instance, $[8] = name, $[9] = node, $[10] = onMessage, $[11] = t4) : t4 = $[11], useEffect(t3, t4);
|
|
91
|
-
let t5;
|
|
92
|
-
$[12] === node ? t5 = $[13] : (t5 = (type_0, data) => {
|
|
93
|
-
node.post(type_0, data);
|
|
94
|
-
}, $[12] = node, $[13] = t5);
|
|
95
|
-
let sendMessage = t5, t6;
|
|
96
|
-
$[14] === node ? t6 = $[15] : (t6 = (type_1, data_0, fetchOptions) => node.fetch(type_1, data_0, fetchOptions ?? {}), $[14] = node, $[15] = t6);
|
|
97
|
-
let fetch = t6, t7;
|
|
98
|
-
return $[16] !== fetch || $[17] !== sendMessage ? (t7 = {
|
|
99
|
-
sendMessage,
|
|
100
|
-
fetch
|
|
101
|
-
}, $[16] = fetch, $[17] = sendMessage, $[18] = t7) : t7 = $[18], t7;
|
|
102
|
-
}
|
|
103
|
-
function _temp$9(unsubscribe) {
|
|
104
|
-
return unsubscribe();
|
|
105
|
-
}
|
|
106
17
|
/**
|
|
107
18
|
* Component that handles token refresh in dashboard mode
|
|
108
19
|
*/
|
|
@@ -162,87 +73,6 @@ const ComlinkTokenRefreshProvider = (t0) => {
|
|
|
162
73
|
return $[0] === children ? t1 = $[1] : (t1 = /* @__PURE__ */ jsx(DashboardTokenRefresh, { children }), $[0] = children, $[1] = t1), t1;
|
|
163
74
|
}
|
|
164
75
|
return children;
|
|
165
|
-
}, OS_BUS_KEY = Symbol.for("sanity.os.bus");
|
|
166
|
-
/**
|
|
167
|
-
* Whether this app is running as a federated remote inside the workbench.
|
|
168
|
-
*
|
|
169
|
-
* Federation shares the host's realm, so the installed bus is visible on
|
|
170
|
-
* `globalThis`. This is `false` in a standalone app, where we must never import
|
|
171
|
-
* `@sanity/workbench` (it would install a bus and add bundle weight for no
|
|
172
|
-
* reason). Note: this is a different embedding model to the Core UI iframe,
|
|
173
|
-
* which is detected separately via the dashboard context — that signal is not
|
|
174
|
-
* set on the federation path.
|
|
175
|
-
*
|
|
176
|
-
* @internal
|
|
177
|
-
*/
|
|
178
|
-
function isWorkbenchEnvironment() {
|
|
179
|
-
return typeof globalThis == "object" && OS_BUS_KEY in globalThis;
|
|
180
|
-
}
|
|
181
|
-
/**
|
|
182
|
-
* Observes the session token issued by the workbench "OS", tracking the OS auth
|
|
183
|
-
* state over time.
|
|
184
|
-
*
|
|
185
|
-
* Returns `undefined` when the app is not embedded in the workbench, so the
|
|
186
|
-
* caller uses its normal auth flow. Inside the workbench, subscribes to the
|
|
187
|
-
* `auth.token` state topic, emitting the current token — or `null` when the OS
|
|
188
|
-
* is signed out — and re-emitting as the OS auth state changes, so sign-in/out
|
|
189
|
-
* propagates instead of being captured once. Any bus error is treated as "no
|
|
190
|
-
* token" (`null`). The token is used in-memory only and never persisted.
|
|
191
|
-
*
|
|
192
|
-
* @internal
|
|
193
|
-
*/
|
|
194
|
-
function observeWorkbenchToken() {
|
|
195
|
-
if (isWorkbenchEnvironment()) return from(import("@sanity/workbench")).pipe(switchMap$1(({ os }) => os.subscribe("auth.token")), catchError(() => of(null)));
|
|
196
|
-
}
|
|
197
|
-
/**
|
|
198
|
-
* Asks the workbench "OS" to reissue the session token, e.g. after its current
|
|
199
|
-
* one was rejected with a 401. Fire-and-forget: the reissued token arrives via
|
|
200
|
-
* the `auth.token` subscription in {@link observeWorkbenchToken}. No-op outside
|
|
201
|
-
* the workbench.
|
|
202
|
-
*
|
|
203
|
-
* @internal
|
|
204
|
-
*/
|
|
205
|
-
function refreshWorkbenchToken() {
|
|
206
|
-
isWorkbenchEnvironment() && import("@sanity/workbench").then(({ os }) => os.emit("auth.token.refresh", void 0), () => {});
|
|
207
|
-
}
|
|
208
|
-
/**
|
|
209
|
-
* Keeps the SDK auth token in sync with the workbench "OS".
|
|
210
|
-
*
|
|
211
|
-
* When running as a federated remote inside the workbench the OS owns the
|
|
212
|
-
* session, so we subscribe to its `auth.token` stream and mirror each value into
|
|
213
|
-
* the auth store — a token logs us in, `null` logs us out, and later OS
|
|
214
|
-
* sign-in/out propagates automatically. When a request is rejected with a 401
|
|
215
|
-
* (the token expired), we ask the OS to reissue rather than tearing the session
|
|
216
|
-
* down; the new token arrives back through the same subscription.
|
|
217
|
-
*/
|
|
218
|
-
function WorkbenchTokenRefresh(t0) {
|
|
219
|
-
let $ = c(8), { children } = t0, instance = useSanityInstance(), authState = useAuthState(), processed401ErrorRef = useRef(null), t1, t2;
|
|
220
|
-
$[0] === instance ? (t1 = $[1], t2 = $[2]) : (t1 = () => {
|
|
221
|
-
let token$ = observeWorkbenchToken();
|
|
222
|
-
if (!token$) return;
|
|
223
|
-
let subscription = token$.subscribe((token) => setAuthToken(instance, token));
|
|
224
|
-
return () => subscription.unsubscribe();
|
|
225
|
-
}, t2 = [instance], $[0] = instance, $[1] = t1, $[2] = t2), useEffect(t1, t2);
|
|
226
|
-
let t3;
|
|
227
|
-
$[3] !== authState.error || $[4] !== authState.type ? (t3 = () => {
|
|
228
|
-
let has401Error = authState.type === AuthStateType.ERROR && authState.error?.statusCode === 401;
|
|
229
|
-
has401Error && processed401ErrorRef.current !== authState.error ? (processed401ErrorRef.current = authState.error, refreshWorkbenchToken()) : has401Error || (processed401ErrorRef.current = null);
|
|
230
|
-
}, $[3] = authState.error, $[4] = authState.type, $[5] = t3) : t3 = $[5];
|
|
231
|
-
let t4;
|
|
232
|
-
return $[6] === authState ? t4 = $[7] : (t4 = [authState], $[6] = authState, $[7] = t4), useEffect(t3, t4), children;
|
|
233
|
-
}
|
|
234
|
-
/**
|
|
235
|
-
* Provides workbench OS token refresh. No-op outside the workbench, where the
|
|
236
|
-
* app uses its normal auth flow.
|
|
237
|
-
* @public
|
|
238
|
-
*/
|
|
239
|
-
const WorkbenchTokenRefreshProvider = (t0) => {
|
|
240
|
-
let $ = c(2), { children } = t0;
|
|
241
|
-
if (isWorkbenchEnvironment()) {
|
|
242
|
-
let t1;
|
|
243
|
-
return $[0] === children ? t1 = $[1] : (t1 = /* @__PURE__ */ jsx(WorkbenchTokenRefresh, { children }), $[0] = children, $[1] = t1), t1;
|
|
244
|
-
}
|
|
245
|
-
return children;
|
|
246
76
|
};
|
|
247
77
|
/**
|
|
248
78
|
* @internal
|
|
@@ -699,7 +529,7 @@ function AuthBoundary(t0) {
|
|
|
699
529
|
let t4;
|
|
700
530
|
$[7] === props ? t4 = $[8] : (t4 = /* @__PURE__ */ jsx(AuthSwitch, { ...props }), $[7] = props, $[8] = t4);
|
|
701
531
|
let t5;
|
|
702
|
-
return $[9] !== FallbackComponent || $[10] !== t3 || $[11] !== t4 ? (t5 = /* @__PURE__ */ jsx(ComlinkTokenRefreshProvider, { children: /* @__PURE__ */ jsx(
|
|
532
|
+
return $[9] !== FallbackComponent || $[10] !== t3 || $[11] !== t4 ? (t5 = /* @__PURE__ */ jsx(ComlinkTokenRefreshProvider, { children: /* @__PURE__ */ jsx(DashboardTokenRefreshProvider, { children: /* @__PURE__ */ jsx(ErrorBoundary, {
|
|
703
533
|
FallbackComponent,
|
|
704
534
|
resetKeys: t3,
|
|
705
535
|
children: t4
|
|
@@ -712,7 +542,7 @@ function AuthSwitch(t0) {
|
|
|
712
542
|
$[6] === instance.config ? t3 = $[7] : (t3 = isStudioConfig(instance.config), $[6] = instance.config, $[7] = t3);
|
|
713
543
|
let isStudio = t3, orgError = useVerifyOrgProjects(!verifyOrganization || isStudio || authState.type !== AuthStateType.LOGGED_IN, projectIds), isLoggedOut = authState.type === AuthStateType.LOGGED_OUT && !authState.isDestroyingSession, loginUrl = useLoginUrl(), t4, t5;
|
|
714
544
|
if ($[8] !== isLoggedOut || $[9] !== isStudio || $[10] !== loginUrl ? (t4 = () => {
|
|
715
|
-
isLoggedOut && !isInIframe() && !isStudio && !
|
|
545
|
+
isLoggedOut && !isInIframe() && !isStudio && !isDashboardEnvironment() && (window.location.href = loginUrl);
|
|
716
546
|
}, t5 = [
|
|
717
547
|
isLoggedOut,
|
|
718
548
|
loginUrl,
|
|
@@ -771,31 +601,6 @@ SDKStudioContext.displayName = "SDKStudioContext";
|
|
|
771
601
|
*/
|
|
772
602
|
const DEFAULT_RESOURCE_NAME = "default";
|
|
773
603
|
/**
|
|
774
|
-
* @public
|
|
775
|
-
*
|
|
776
|
-
* A React hook that retrieves the dashboard organization ID that is currently selected in the Sanity Dashboard.
|
|
777
|
-
*
|
|
778
|
-
* @example
|
|
779
|
-
* ```tsx
|
|
780
|
-
* function DashboardComponent() {
|
|
781
|
-
* const orgId = useDashboardOrganizationId()
|
|
782
|
-
*
|
|
783
|
-
* if (!orgId) return null
|
|
784
|
-
*
|
|
785
|
-
* return <div>Organization ID: {String(orgId)}</div>
|
|
786
|
-
* }
|
|
787
|
-
* ```
|
|
788
|
-
*
|
|
789
|
-
* @category Dashboard
|
|
790
|
-
* @returns The dashboard organization ID (string | undefined)
|
|
791
|
-
*/
|
|
792
|
-
function useDashboardOrganizationId() {
|
|
793
|
-
let $ = c(2), instance = useSanityInstance(), t0;
|
|
794
|
-
$[0] === instance ? t0 = $[1] : (t0 = getDashboardOrganizationId(instance), $[0] = instance, $[1] = t0);
|
|
795
|
-
let { subscribe, getCurrent } = t0;
|
|
796
|
-
return useSyncExternalStore(subscribe, getCurrent);
|
|
797
|
-
}
|
|
798
|
-
/**
|
|
799
604
|
* Gets the id of the first resource from a settled request result. The request
|
|
800
605
|
* is already scoped to a single organization, so the first item is the one we want.
|
|
801
606
|
*/
|
|
@@ -813,11 +618,11 @@ async function resolveOrgResources(instance, organizationId) {
|
|
|
813
618
|
apiVersion: "v2026-07-09",
|
|
814
619
|
scope: "global"
|
|
815
620
|
}).observable), [mediaLibrariesResult, canvasesResult] = await Promise.allSettled([client.request({
|
|
816
|
-
|
|
621
|
+
url: "/media-libraries",
|
|
817
622
|
query: { organizationId },
|
|
818
623
|
tag: "org-resources.media-libraries"
|
|
819
624
|
}), client.request({
|
|
820
|
-
|
|
625
|
+
url: "/canvases",
|
|
821
626
|
query: { organizationId },
|
|
822
627
|
tag: "org-resources.canvases"
|
|
823
628
|
})]), mediaLibraryId = getFirstResourceId(mediaLibrariesResult), canvasId = getFirstResourceId(canvasesResult);
|
|
@@ -870,7 +675,7 @@ function InferredResourcesProvider(t0) {
|
|
|
870
675
|
function OrganizationResourcesProvider(t0) {
|
|
871
676
|
let $ = c(10), { resources: t1, inferMediaLibraryAndCanvas, children } = t0, t2;
|
|
872
677
|
$[0] === t1 ? t2 = $[1] : (t2 = t1 === void 0 ? {} : t1, $[0] = t1, $[1] = t2);
|
|
873
|
-
let explicitResources = t2, instance = useSanityInstance(), orgId =
|
|
678
|
+
let explicitResources = t2, instance = useSanityInstance(), orgId = useOrganizationId();
|
|
874
679
|
if (!inferMediaLibraryAndCanvas || !orgId) {
|
|
875
680
|
let t3;
|
|
876
681
|
return $[2] !== children || $[3] !== explicitResources ? (t3 = /* @__PURE__ */ jsx(ResourcesContext.Provider, {
|
|
@@ -1885,71 +1690,6 @@ function useAgentPatch(resourceHandle) {
|
|
|
1885
1690
|
return $[2] !== instance || $[3] !== resource ? (t1 = (options) => firstValueFrom(agentPatch(instance, options, resource)), $[2] = instance, $[3] = resource, $[4] = t1) : t1 = $[4], t1;
|
|
1886
1691
|
}
|
|
1887
1692
|
/**
|
|
1888
|
-
* @public
|
|
1889
|
-
* Hook for emitting agent resource context updates to the Dashboard.
|
|
1890
|
-
* This allows the Agent to understand what resource the user is currently
|
|
1891
|
-
* interacting with (e.g., which document they're editing).
|
|
1892
|
-
*
|
|
1893
|
-
* The hook will automatically emit the context when it changes, and also
|
|
1894
|
-
* emit the initial context when the hook is first mounted.
|
|
1895
|
-
*
|
|
1896
|
-
* @category Agent
|
|
1897
|
-
* @param options - The resource context options containing projectId, dataset, and optional documentId
|
|
1898
|
-
*
|
|
1899
|
-
* @example
|
|
1900
|
-
* ```tsx
|
|
1901
|
-
* import {useAgentResourceContext} from '@sanity/sdk-react'
|
|
1902
|
-
*
|
|
1903
|
-
* function MyComponent() {
|
|
1904
|
-
* const documentId = 'my-document-id'
|
|
1905
|
-
*
|
|
1906
|
-
* // Automatically updates the Agent's context whenever the document changes
|
|
1907
|
-
* useAgentResourceContext({
|
|
1908
|
-
* projectId: 'my-project',
|
|
1909
|
-
* dataset: 'production',
|
|
1910
|
-
* documentId,
|
|
1911
|
-
* })
|
|
1912
|
-
*
|
|
1913
|
-
* return <div>Editing document: {documentId}</div>
|
|
1914
|
-
* }
|
|
1915
|
-
* ```
|
|
1916
|
-
*/
|
|
1917
|
-
function useAgentResourceContext(options) {
|
|
1918
|
-
let $ = c(9), { projectId, dataset, documentId } = options, t0;
|
|
1919
|
-
$[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = {
|
|
1920
|
-
name: SDK_NODE_NAME,
|
|
1921
|
-
connectTo: SDK_CHANNEL_NAME
|
|
1922
|
-
}, $[0] = t0) : t0 = $[0];
|
|
1923
|
-
let { sendMessage } = useWindowConnection(t0), lastContextRef = useRef(null), t1;
|
|
1924
|
-
$[1] !== dataset || $[2] !== documentId || $[3] !== projectId || $[4] !== sendMessage ? (t1 = () => {
|
|
1925
|
-
if (!projectId || !dataset) {
|
|
1926
|
-
console.warn("[useAgentResourceContext] projectId and dataset are required", {
|
|
1927
|
-
projectId,
|
|
1928
|
-
dataset
|
|
1929
|
-
});
|
|
1930
|
-
return;
|
|
1931
|
-
}
|
|
1932
|
-
let contextKey = `${projectId}:${dataset}:${documentId || ""}`;
|
|
1933
|
-
if (lastContextRef.current !== contextKey) try {
|
|
1934
|
-
let message = {
|
|
1935
|
-
type: "dashboard/v1/events/agent/resource/update",
|
|
1936
|
-
data: {
|
|
1937
|
-
projectId,
|
|
1938
|
-
dataset,
|
|
1939
|
-
documentId
|
|
1940
|
-
}
|
|
1941
|
-
};
|
|
1942
|
-
sendMessage(message.type, message.data), lastContextRef.current = contextKey;
|
|
1943
|
-
} catch (t2) {
|
|
1944
|
-
console.error("[useAgentResourceContext] Failed to update context:", t2);
|
|
1945
|
-
}
|
|
1946
|
-
}, $[1] = dataset, $[2] = documentId, $[3] = projectId, $[4] = sendMessage, $[5] = t1) : t1 = $[5];
|
|
1947
|
-
let updateContext = t1, t2, t3;
|
|
1948
|
-
$[6] === updateContext ? (t2 = $[7], t3 = $[8]) : (t2 = () => {
|
|
1949
|
-
updateContext();
|
|
1950
|
-
}, t3 = [updateContext], $[6] = updateContext, $[7] = t2, $[8] = t3), useEffect(t2, t3);
|
|
1951
|
-
}
|
|
1952
|
-
/**
|
|
1953
1693
|
* Returns a single application by id.
|
|
1954
1694
|
*
|
|
1955
1695
|
* The hook suspends until the first fetch succeeds, so `data` is always present.
|
|
@@ -2300,311 +2040,52 @@ function useResource() {
|
|
|
2300
2040
|
return useEffectiveContextResource();
|
|
2301
2041
|
}
|
|
2302
2042
|
/**
|
|
2303
|
-
* @
|
|
2304
|
-
*
|
|
2305
|
-
*
|
|
2306
|
-
* While the Dashboard can usually handle navigation, there are special cases when you
|
|
2307
|
-
* are already within a target app, and need to navigate to another route inside of that app.
|
|
2308
|
-
*
|
|
2309
|
-
* For example, your user might "favorite" a document inside of your application.
|
|
2310
|
-
* If they click on the Dashboard favorites item in the sidebar, and are already within your application,
|
|
2311
|
-
* there needs to be some way for the dashboard to signal to your application to reroute to where that document was favorited.
|
|
2312
|
-
*
|
|
2313
|
-
* This hook is intended to receive those messages, and takes a function to route to the correct path.
|
|
2043
|
+
* Resolves {@link UseFavoriteProps} into the {@link FavoriteDocumentContext}
|
|
2044
|
+
* shared by the favorites fetcher and mutation, defaulting a studio `resourceId`
|
|
2045
|
+
* from the instance's project and dataset.
|
|
2314
2046
|
*
|
|
2315
|
-
* @param navigateFn - Function to handle navigation; should accept:
|
|
2316
|
-
* - `path`: a string, which will be a relative path (for example, 'my-route')
|
|
2317
|
-
* - `type`: 'push', 'replace', or 'pop', which will be the type of navigation to perform
|
|
2318
|
-
*
|
|
2319
|
-
* @example
|
|
2320
|
-
* ```tsx
|
|
2321
|
-
* import {useDashboardNavigate} from '@sanity/sdk-react'
|
|
2322
|
-
* import {BrowserRouter, useNavigate} from 'react-router'
|
|
2323
|
-
* import {Suspense} from 'react'
|
|
2324
|
-
*
|
|
2325
|
-
* function DashboardNavigationHandler() {
|
|
2326
|
-
* const navigate = useNavigate()
|
|
2327
|
-
* useDashboardNavigate(({path, type}) => {
|
|
2328
|
-
* navigate(path, {replace: type === 'replace'})
|
|
2329
|
-
* })
|
|
2330
|
-
* return null
|
|
2331
|
-
* }
|
|
2332
|
-
*
|
|
2333
|
-
* // Wrap the component with Suspense since the hook may suspend
|
|
2334
|
-
* function MyApp() {
|
|
2335
|
-
* return (
|
|
2336
|
-
* <BrowserRouter>
|
|
2337
|
-
* <Suspense>
|
|
2338
|
-
* <DashboardNavigationHandler />
|
|
2339
|
-
* </Suspense>
|
|
2340
|
-
* </BrowserRouter>
|
|
2341
|
-
* )
|
|
2342
|
-
* }
|
|
2343
|
-
* ```
|
|
2344
|
-
*/
|
|
2345
|
-
function useDashboardNavigate(navigateFn) {
|
|
2346
|
-
let $ = c(2), t0;
|
|
2347
|
-
$[0] === navigateFn ? t0 = $[1] : (t0 = {
|
|
2348
|
-
name: SDK_NODE_NAME,
|
|
2349
|
-
connectTo: SDK_CHANNEL_NAME,
|
|
2350
|
-
onMessage: { "dashboard/v1/history/change-path": (data) => {
|
|
2351
|
-
navigateFn(data);
|
|
2352
|
-
} }
|
|
2353
|
-
}, $[0] = navigateFn, $[1] = t0), useWindowConnection(t0);
|
|
2354
|
-
}
|
|
2355
|
-
/**
|
|
2356
2047
|
* @internal
|
|
2357
|
-
*
|
|
2358
|
-
* This hook provides functionality to add and remove documents from favorites,
|
|
2359
|
-
* and tracks the current favorite status of the document.
|
|
2360
|
-
* @param documentHandle - The document handle containing document ID and type, like `{_id: '123', _type: 'book'}`
|
|
2361
|
-
* @returns An object containing:
|
|
2362
|
-
* - `favorite` - Function to add document to favorites
|
|
2363
|
-
* - `unfavorite` - Function to remove document from favorites
|
|
2364
|
-
* - `isFavorited` - Boolean indicating if document is currently favorited
|
|
2365
|
-
*
|
|
2366
|
-
* @example
|
|
2367
|
-
* ```tsx
|
|
2368
|
-
* function FavoriteButton(props: DocumentActionProps) {
|
|
2369
|
-
* const {documentId, documentType} = props
|
|
2370
|
-
* const {favorite, unfavorite, isFavorited} = useManageFavorite({
|
|
2371
|
-
* documentId,
|
|
2372
|
-
* documentType
|
|
2373
|
-
* })
|
|
2374
|
-
*
|
|
2375
|
-
* return (
|
|
2376
|
-
* <Button
|
|
2377
|
-
* onClick={() => isFavorited ? unfavorite() : favorite()}
|
|
2378
|
-
* text={isFavorited ? 'Remove from favorites' : 'Add to favorites'}
|
|
2379
|
-
* />
|
|
2380
|
-
* )
|
|
2381
|
-
* }
|
|
2382
|
-
*
|
|
2383
|
-
* // Wrap the component with Suspense since the hook may suspend
|
|
2384
|
-
* function MyDocumentAction(props: DocumentActionProps) {
|
|
2385
|
-
* return (
|
|
2386
|
-
* <Suspense
|
|
2387
|
-
* fallback={
|
|
2388
|
-
* <Button
|
|
2389
|
-
* text="Loading..."
|
|
2390
|
-
* disabled
|
|
2391
|
-
* />
|
|
2392
|
-
* }
|
|
2393
|
-
* >
|
|
2394
|
-
* <FavoriteButton {...props} />
|
|
2395
|
-
* </Suspense>
|
|
2396
|
-
* )
|
|
2397
|
-
* }
|
|
2398
|
-
* ```
|
|
2399
2048
|
*/
|
|
2400
|
-
function
|
|
2401
|
-
let {
|
|
2402
|
-
name: SDK_NODE_NAME,
|
|
2403
|
-
connectTo: SDK_CHANNEL_NAME
|
|
2404
|
-
}), instance = useSanityInstance(), { config } = instance, instanceProjectId = config?.projectId, instanceDataset = config?.dataset, projectId = paramProjectId ?? instanceProjectId, dataset = paramDataset ?? instanceDataset;
|
|
2049
|
+
function useFavoriteContext(t0) {
|
|
2050
|
+
let $ = c(6), { documentId, documentType, projectId: paramProjectId, dataset: paramDataset, resourceId: paramResourceId, resourceType, schemaName } = t0, { config } = useSanityInstance(), projectId = paramProjectId ?? config?.projectId, dataset = paramDataset ?? config?.dataset;
|
|
2405
2051
|
if (resourceType === "studio" && (!projectId || !dataset)) throw Error("projectId and dataset are required for studio resources");
|
|
2406
2052
|
let resourceId = resourceType === "studio" && !paramResourceId ? `${projectId}.${dataset}` : paramResourceId;
|
|
2407
2053
|
if (!resourceId) throw Error("resourceId is required for media-library and canvas resources");
|
|
2408
|
-
let
|
|
2409
|
-
|
|
2410
|
-
documentType,
|
|
2411
|
-
resourceId,
|
|
2412
|
-
resourceType,
|
|
2413
|
-
schemaName
|
|
2414
|
-
}), [
|
|
2054
|
+
let t1;
|
|
2055
|
+
return $[0] !== documentId || $[1] !== documentType || $[2] !== resourceId || $[3] !== resourceType || $[4] !== schemaName ? (t1 = {
|
|
2415
2056
|
documentId,
|
|
2416
2057
|
documentType,
|
|
2417
2058
|
resourceId,
|
|
2418
2059
|
resourceType,
|
|
2419
2060
|
schemaName
|
|
2420
|
-
]
|
|
2421
|
-
if (!(!fetch || !documentId || !documentType || !resourceType)) try {
|
|
2422
|
-
let payload = {
|
|
2423
|
-
eventType: action,
|
|
2424
|
-
document: {
|
|
2425
|
-
id: documentId,
|
|
2426
|
-
type: documentType,
|
|
2427
|
-
resource: {
|
|
2428
|
-
id: resourceId,
|
|
2429
|
-
type: resourceType,
|
|
2430
|
-
...schemaName ? { schemaName } : {}
|
|
2431
|
-
}
|
|
2432
|
-
}
|
|
2433
|
-
};
|
|
2434
|
-
(await fetch("dashboard/v1/events/favorite/mutate", payload)).success && await resolveFavoritesState(instance, context);
|
|
2435
|
-
} catch (err) {
|
|
2436
|
-
throw console.error(`Failed to ${action === "added" ? "favorite" : "unfavorite"} document:`, err), err;
|
|
2437
|
-
}
|
|
2438
|
-
}, [
|
|
2439
|
-
fetch,
|
|
2440
|
-
documentId,
|
|
2441
|
-
documentType,
|
|
2442
|
-
resourceId,
|
|
2443
|
-
resourceType,
|
|
2444
|
-
schemaName,
|
|
2445
|
-
instance,
|
|
2446
|
-
context
|
|
2447
|
-
]);
|
|
2448
|
-
return {
|
|
2449
|
-
favorite: useCallback(() => handleFavoriteAction("added"), [handleFavoriteAction]),
|
|
2450
|
-
unfavorite: useCallback(() => handleFavoriteAction("removed"), [handleFavoriteAction]),
|
|
2451
|
-
isFavorited
|
|
2452
|
-
};
|
|
2061
|
+
}, $[0] = documentId, $[1] = documentType, $[2] = resourceId, $[3] = resourceType, $[4] = schemaName, $[5] = t1) : t1 = $[5], t1;
|
|
2453
2062
|
}
|
|
2063
|
+
const useFavoriteStatus = createFetcherHook(favorites);
|
|
2454
2064
|
/**
|
|
2455
|
-
* Hook that fetches studio workspaces and organizes them by projectId:dataset
|
|
2456
2065
|
* @internal
|
|
2457
2066
|
*
|
|
2458
|
-
*
|
|
2459
|
-
*
|
|
2460
|
-
* import {useStudioWorkspacesByProjectIdDataset} from '@sanity/sdk-react'
|
|
2461
|
-
* import {Card, Code, Button} from '@sanity/ui'
|
|
2462
|
-
* import {Suspense} from 'react'
|
|
2067
|
+
* Reads whether a document is currently favorited. The write-side counterpart is
|
|
2068
|
+
* {@link useUpdateFavorite}.
|
|
2463
2069
|
*
|
|
2464
|
-
*
|
|
2465
|
-
*
|
|
2466
|
-
* if (error) {
|
|
2467
|
-
* return <div>Error: {error}</div>
|
|
2468
|
-
* }
|
|
2469
|
-
* return (
|
|
2470
|
-
* <Card padding={4} radius={2} shadow={1}>
|
|
2471
|
-
* <Code language="json">
|
|
2472
|
-
* {JSON.stringify(workspacesByProjectIdAndDataset, null, 2)}
|
|
2473
|
-
* </Code>
|
|
2474
|
-
* </Card>
|
|
2475
|
-
* )
|
|
2476
|
-
* }
|
|
2070
|
+
* The hook suspends until the first favorite status resolves, so wrap the
|
|
2071
|
+
* component in a `<Suspense>` boundary.
|
|
2477
2072
|
*
|
|
2478
|
-
*
|
|
2479
|
-
*
|
|
2480
|
-
* return (
|
|
2481
|
-
* <Suspense fallback={<Button text="Loading..." disabled />}>
|
|
2482
|
-
* <WorkspacesCard />
|
|
2483
|
-
* </Suspense>
|
|
2484
|
-
* )
|
|
2485
|
-
* }
|
|
2486
|
-
* ```
|
|
2487
|
-
*/
|
|
2488
|
-
function useStudioWorkspacesByProjectIdDataset() {
|
|
2489
|
-
let $ = c(8), t0;
|
|
2490
|
-
$[0] === Symbol.for("react.memo_cache_sentinel") ? (t0 = {}, $[0] = t0) : t0 = $[0];
|
|
2491
|
-
let [workspacesByProjectIdAndDataset, setWorkspacesByProjectIdAndDataset] = useState(t0), [error, setError] = useState(null), t1;
|
|
2492
|
-
$[1] === Symbol.for("react.memo_cache_sentinel") ? (t1 = {
|
|
2493
|
-
name: SDK_NODE_NAME,
|
|
2494
|
-
connectTo: SDK_CHANNEL_NAME
|
|
2495
|
-
}, $[1] = t1) : t1 = $[1];
|
|
2496
|
-
let { fetch } = useWindowConnection(t1), t2, t3;
|
|
2497
|
-
$[2] === fetch ? (t2 = $[3], t3 = $[4]) : (t2 = () => {
|
|
2498
|
-
if (!fetch) return;
|
|
2499
|
-
let fetchWorkspaces = async function fetchWorkspaces(signal) {
|
|
2500
|
-
try {
|
|
2501
|
-
let data = await fetch("dashboard/v1/context", void 0, { signal }), workspaceMap = {}, noProjectIdAndDataset = [];
|
|
2502
|
-
data.context.availableResources.forEach((resource) => {
|
|
2503
|
-
if (resource.type !== "studio") return;
|
|
2504
|
-
if (!resource.projectId || !resource.dataset) {
|
|
2505
|
-
noProjectIdAndDataset.push(resource);
|
|
2506
|
-
return;
|
|
2507
|
-
}
|
|
2508
|
-
let key = `${resource.projectId}:${resource.dataset}`;
|
|
2509
|
-
workspaceMap[key] || (workspaceMap[key] = []), workspaceMap[key].push(resource);
|
|
2510
|
-
}), noProjectIdAndDataset.length > 0 && (workspaceMap["NO_PROJECT_ID:NO_DATASET"] = noProjectIdAndDataset), setWorkspacesByProjectIdAndDataset(workspaceMap), setError(null);
|
|
2511
|
-
} catch (t4) {
|
|
2512
|
-
let err = t4;
|
|
2513
|
-
if (err instanceof Error) {
|
|
2514
|
-
if (err.name === "AbortError") return;
|
|
2515
|
-
setError("Failed to fetch workspaces");
|
|
2516
|
-
}
|
|
2517
|
-
}
|
|
2518
|
-
}, controller = new AbortController();
|
|
2519
|
-
return fetchWorkspaces(controller.signal), () => {
|
|
2520
|
-
controller.abort();
|
|
2521
|
-
};
|
|
2522
|
-
}, t3 = [fetch], $[2] = fetch, $[3] = t2, $[4] = t3), useEffect(t2, t3);
|
|
2523
|
-
let t4;
|
|
2524
|
-
return $[5] !== error || $[6] !== workspacesByProjectIdAndDataset ? (t4 = {
|
|
2525
|
-
workspacesByProjectIdAndDataset,
|
|
2526
|
-
error
|
|
2527
|
-
}, $[5] = error, $[6] = workspacesByProjectIdAndDataset, $[7] = t4) : t4 = $[7], t4;
|
|
2528
|
-
}
|
|
2529
|
-
/**
|
|
2530
|
-
* @public
|
|
2531
|
-
*
|
|
2532
|
-
* Hook that provides a function to navigate to a given document in its parent Studio.
|
|
2533
|
-
*
|
|
2534
|
-
* Uses the `projectId` and `dataset` properties of the {@link DocumentHandle} you provide to resolve the correct Studio.
|
|
2535
|
-
* This will only work if you have deployed a studio with a workspace with this `projectId` / `dataset` combination.
|
|
2536
|
-
*
|
|
2537
|
-
* @remarks If you write your own Document Handle to pass to this hook (as opposed to a Document Handle generated by another hook),
|
|
2538
|
-
* it must include values for `documentId`, `documentType`, `projectId`, and `dataset`.
|
|
2539
|
-
*
|
|
2540
|
-
* @category Documents
|
|
2541
|
-
* @param documentHandle - The document handle for the document to navigate to
|
|
2542
|
-
* @param preferredStudioUrl - The preferred studio url to navigate to if you have multiple
|
|
2543
|
-
* studios with the same projectId and dataset
|
|
2544
|
-
* @returns An object containing:
|
|
2545
|
-
* - `navigateToStudioDocument` - Function that when called will navigate to the studio document
|
|
2073
|
+
* @param props - The document handle plus the resource it lives in.
|
|
2074
|
+
* @returns `true` when the document is favorited, otherwise `false`.
|
|
2546
2075
|
*
|
|
2547
2076
|
* @example
|
|
2548
2077
|
* ```tsx
|
|
2549
|
-
*
|
|
2550
|
-
*
|
|
2551
|
-
*
|
|
2552
|
-
*
|
|
2553
|
-
* function NavigateButton({documentHandle}: {documentHandle: DocumentHandle}) {
|
|
2554
|
-
* const {navigateToStudioDocument} = useNavigateToStudioDocument(documentHandle)
|
|
2555
|
-
* return (
|
|
2556
|
-
* <Button
|
|
2557
|
-
* onClick={navigateToStudioDocument}
|
|
2558
|
-
* text="Navigate to Studio Document"
|
|
2559
|
-
* />
|
|
2560
|
-
* )
|
|
2561
|
-
* }
|
|
2078
|
+
* function FavoriteLabel(props: DocumentActionProps) {
|
|
2079
|
+
* const {documentId, documentType} = props
|
|
2080
|
+
* const isFavorited = useFavorite({documentId, documentType, resourceType: 'studio'})
|
|
2562
2081
|
*
|
|
2563
|
-
*
|
|
2564
|
-
* function MyDocumentAction({documentHandle}: {documentHandle: DocumentHandle}) {
|
|
2565
|
-
* return (
|
|
2566
|
-
* <Suspense fallback={<Button text="Loading..." disabled />}>
|
|
2567
|
-
* <NavigateButton documentHandle={documentHandle} />
|
|
2568
|
-
* </Suspense>
|
|
2569
|
-
* )
|
|
2082
|
+
* return <span>{isFavorited ? 'Favorited' : 'Not favorited'}</span>
|
|
2570
2083
|
* }
|
|
2571
2084
|
* ```
|
|
2572
2085
|
*/
|
|
2573
|
-
function
|
|
2574
|
-
let
|
|
2575
|
-
|
|
2576
|
-
name: SDK_NODE_NAME,
|
|
2577
|
-
connectTo: SDK_CHANNEL_NAME
|
|
2578
|
-
}, $[0] = t0) : t0 = $[0];
|
|
2579
|
-
let { sendMessage } = useWindowConnection(t0), t1;
|
|
2580
|
-
$[1] !== documentHandle || $[2] !== preferredStudioUrl || $[3] !== sendMessage || $[4] !== workspacesByProjectIdAndDataset ? (t1 = () => {
|
|
2581
|
-
let { projectId, dataset } = documentHandle;
|
|
2582
|
-
if (!projectId || !dataset) {
|
|
2583
|
-
console.warn("Project ID and dataset are required to navigate to a studio document");
|
|
2584
|
-
return;
|
|
2585
|
-
}
|
|
2586
|
-
let workspace;
|
|
2587
|
-
if (preferredStudioUrl) workspace = [...workspacesByProjectIdAndDataset[`${projectId}:${dataset}`] || [], ...workspacesByProjectIdAndDataset["NO_PROJECT_ID:NO_DATASET"] || []].find((w) => w.url === preferredStudioUrl);
|
|
2588
|
-
else {
|
|
2589
|
-
let workspaces = workspacesByProjectIdAndDataset[`${projectId}:${dataset}`];
|
|
2590
|
-
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];
|
|
2591
|
-
}
|
|
2592
|
-
if (!workspace) {
|
|
2593
|
-
console.warn(`No workspace found for document with projectId: ${projectId} and dataset: ${dataset}${preferredStudioUrl ? ` or with preferred studio url: ${preferredStudioUrl}` : ""}`);
|
|
2594
|
-
return;
|
|
2595
|
-
}
|
|
2596
|
-
let message = {
|
|
2597
|
-
type: "dashboard/v1/bridge/navigate-to-resource",
|
|
2598
|
-
data: {
|
|
2599
|
-
resourceId: workspace.id,
|
|
2600
|
-
resourceType: "studio",
|
|
2601
|
-
path: `/intent/edit/id=${documentHandle.documentId};type=${documentHandle.documentType}`
|
|
2602
|
-
}
|
|
2603
|
-
};
|
|
2604
|
-
sendMessage(message.type, message.data);
|
|
2605
|
-
}, $[1] = documentHandle, $[2] = preferredStudioUrl, $[3] = sendMessage, $[4] = workspacesByProjectIdAndDataset, $[5] = t1) : t1 = $[5];
|
|
2606
|
-
let navigateToStudioDocument = t1, t2;
|
|
2607
|
-
return $[6] === navigateToStudioDocument ? t2 = $[7] : (t2 = { navigateToStudioDocument }, $[6] = navigateToStudioDocument, $[7] = t2), t2;
|
|
2086
|
+
function useFavorite(props) {
|
|
2087
|
+
let context = useFavoriteContext(props), { data } = useFavoriteStatus(context);
|
|
2088
|
+
return data.isFavorited;
|
|
2608
2089
|
}
|
|
2609
2090
|
/**
|
|
2610
2091
|
* @internal
|
|
@@ -2682,75 +2163,65 @@ function useRecordDocumentHistoryEvent(t0) {
|
|
|
2682
2163
|
let recordEvent = t2, t3;
|
|
2683
2164
|
return $[8] === recordEvent ? t3 = $[9] : (t3 = { recordEvent }, $[8] = recordEvent, $[9] = t3), t3;
|
|
2684
2165
|
}
|
|
2685
|
-
|
|
2686
|
-
return resource.manifest?.title || resource.activeDeployment?.manifest?.title || resource.title;
|
|
2687
|
-
}
|
|
2166
|
+
const useSetFavorite = createMutationHook(setFavorite);
|
|
2688
2167
|
/**
|
|
2689
|
-
*
|
|
2690
|
-
* from the manifest.
|
|
2691
|
-
*
|
|
2692
|
-
* This follows the same convention as Sanity Studio workspaces, where the
|
|
2693
|
-
* workspace name is always present in the title:
|
|
2168
|
+
* @internal
|
|
2694
2169
|
*
|
|
2695
|
-
*
|
|
2696
|
-
*
|
|
2170
|
+
* Adds or removes a document from favorites. The read-side counterpart is
|
|
2171
|
+
* {@link useFavorite}, which reflects the change once the mutation settles.
|
|
2697
2172
|
*
|
|
2698
|
-
*
|
|
2173
|
+
* Unlike {@link useFavorite}, this hook does not suspend.
|
|
2699
2174
|
*
|
|
2700
|
-
* @param
|
|
2175
|
+
* @param props - The document handle plus the resource it lives in.
|
|
2176
|
+
* @returns `favorite`/`unfavorite` actions and the `{isPending, error, reset}`
|
|
2177
|
+
* mutation state.
|
|
2701
2178
|
*
|
|
2702
2179
|
* @example
|
|
2703
2180
|
* ```tsx
|
|
2704
|
-
*
|
|
2181
|
+
* function FavoriteButton(props: DocumentActionProps) {
|
|
2182
|
+
* const {documentId, documentType} = props
|
|
2183
|
+
* const handle = {documentId, documentType, resourceType: 'studio'} as const
|
|
2184
|
+
* const isFavorited = useFavorite(handle)
|
|
2185
|
+
* const {favorite, unfavorite, isPending} = useUpdateFavorite(handle)
|
|
2705
2186
|
*
|
|
2706
|
-
*
|
|
2707
|
-
*
|
|
2708
|
-
*
|
|
2187
|
+
* return (
|
|
2188
|
+
* <Button
|
|
2189
|
+
* disabled={isPending}
|
|
2190
|
+
* onClick={() => (isFavorited ? unfavorite() : favorite())}
|
|
2191
|
+
* text={isFavorited ? 'Remove from favorites' : 'Add to favorites'}
|
|
2192
|
+
* />
|
|
2193
|
+
* )
|
|
2709
2194
|
* }
|
|
2710
2195
|
*
|
|
2711
|
-
* //
|
|
2712
|
-
*
|
|
2713
|
-
*
|
|
2714
|
-
*
|
|
2715
|
-
*
|
|
2716
|
-
*
|
|
2717
|
-
*
|
|
2718
|
-
* useWindowTitle()
|
|
2719
|
-
* return <Outlet />
|
|
2196
|
+
* // Wrap the component with Suspense since useFavorite suspends
|
|
2197
|
+
* function MyDocumentAction(props: DocumentActionProps) {
|
|
2198
|
+
* return (
|
|
2199
|
+
* <Suspense fallback={<Button text="Loading..." disabled />}>
|
|
2200
|
+
* <FavoriteButton {...props} />
|
|
2201
|
+
* </Suspense>
|
|
2202
|
+
* )
|
|
2720
2203
|
* }
|
|
2721
|
-
*
|
|
2722
|
-
* // Browser tab: "My App | Sanity"
|
|
2723
2204
|
* ```
|
|
2724
|
-
*
|
|
2725
|
-
* @public
|
|
2726
2205
|
*/
|
|
2727
|
-
function
|
|
2728
|
-
let
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
};
|
|
2747
|
-
}, [fetch]), useEffect(() => {
|
|
2748
|
-
if (!appTitle) return;
|
|
2749
|
-
let previous = document.title;
|
|
2750
|
-
return document.title = viewTitle ? `${viewTitle} | ${appTitle}` : appTitle, () => {
|
|
2751
|
-
document.title = previous;
|
|
2752
|
-
};
|
|
2753
|
-
}, [viewTitle, appTitle]);
|
|
2206
|
+
function useUpdateFavorite(props) {
|
|
2207
|
+
let $ = c(12), context = useFavoriteContext(props), { mutate, isPending, error, reset } = useSetFavorite(), t0;
|
|
2208
|
+
$[0] !== context || $[1] !== mutate ? (t0 = () => mutate({
|
|
2209
|
+
...context,
|
|
2210
|
+
isFavorited: !0
|
|
2211
|
+
}), $[0] = context, $[1] = mutate, $[2] = t0) : t0 = $[2];
|
|
2212
|
+
let favorite = t0, t1;
|
|
2213
|
+
$[3] !== context || $[4] !== mutate ? (t1 = () => mutate({
|
|
2214
|
+
...context,
|
|
2215
|
+
isFavorited: !1
|
|
2216
|
+
}), $[3] = context, $[4] = mutate, $[5] = t1) : t1 = $[5];
|
|
2217
|
+
let unfavorite = t1, t2;
|
|
2218
|
+
return $[6] !== error || $[7] !== favorite || $[8] !== isPending || $[9] !== reset || $[10] !== unfavorite ? (t2 = {
|
|
2219
|
+
favorite,
|
|
2220
|
+
unfavorite,
|
|
2221
|
+
isPending,
|
|
2222
|
+
error,
|
|
2223
|
+
reset
|
|
2224
|
+
}, $[6] = error, $[7] = favorite, $[8] = isPending, $[9] = reset, $[10] = unfavorite, $[11] = t2) : t2 = $[11], t2;
|
|
2754
2225
|
}
|
|
2755
2226
|
/**
|
|
2756
2227
|
* Resolves the effective `projectId` for project-scoped hooks (`useProject`,
|
|
@@ -2773,17 +2244,44 @@ function useResolvedProjectId(options) {
|
|
|
2773
2244
|
let { resource } = useNormalizedResourceOptions(t0), contextProjectId = useContext(ProjectContext), t1;
|
|
2774
2245
|
return $[2] !== contextProjectId || $[3] !== options?.projectId || $[4] !== resource ? (t1 = options?.projectId ?? contextProjectId ?? (resource && isDatasetResource(resource) ? resource.projectId : void 0), $[2] = contextProjectId, $[3] = options?.projectId, $[4] = resource, $[5] = t1) : t1 = $[5], t1;
|
|
2775
2246
|
}
|
|
2776
|
-
const useDatasetsBase =
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2247
|
+
const useDatasetsBase = createFetcherHook(datasets);
|
|
2248
|
+
/**
|
|
2249
|
+
* Returns metadata for each dataset the current user has access to.
|
|
2250
|
+
*
|
|
2251
|
+
* @category Datasets
|
|
2252
|
+
* @param options - Optional project/resource to read datasets for. Defaults to
|
|
2253
|
+
* the resource named in `ResourceProvider`/`SDKProvider`.
|
|
2254
|
+
* @returns A {@link FetcherHookResult} whose `data` is the metadata for the
|
|
2255
|
+
* datasets.
|
|
2256
|
+
*
|
|
2257
|
+
* @example
|
|
2258
|
+
* ```tsx
|
|
2259
|
+
* const {data: datasets} = useDatasets()
|
|
2260
|
+
*
|
|
2261
|
+
* return (
|
|
2262
|
+
* <select>
|
|
2263
|
+
* {datasets.map((dataset) => (
|
|
2264
|
+
* <option key={dataset.name}>{dataset.name}</option>
|
|
2265
|
+
* ))}
|
|
2266
|
+
* </select>
|
|
2267
|
+
* )
|
|
2268
|
+
* ```
|
|
2269
|
+
*
|
|
2270
|
+
* @remarks
|
|
2271
|
+
* The `projectId` is resolved in order from:
|
|
2272
|
+
* 1. an explicit `projectId` option
|
|
2273
|
+
* 2. A legacy ProjectContext (e.g. a `<ResourceProvider projectId="…">` with no dataset), then
|
|
2274
|
+
* 3. The active resource (`ResourceProvider`/`SDKProvider`)
|
|
2275
|
+
* 4. `instance.config`.
|
|
2276
|
+
* @public
|
|
2277
|
+
*/
|
|
2278
|
+
function useDatasets(options) {
|
|
2781
2279
|
let $ = c(3), projectId = useResolvedProjectId(options), t0;
|
|
2782
2280
|
return $[0] !== options || $[1] !== projectId ? (t0 = projectId ? {
|
|
2783
2281
|
...options,
|
|
2784
2282
|
projectId
|
|
2785
2283
|
} : options, $[0] = options, $[1] = projectId, $[2] = t0) : t0 = $[2], useDatasetsBase(t0);
|
|
2786
|
-
}
|
|
2284
|
+
}
|
|
2787
2285
|
/**
|
|
2788
2286
|
* @internal
|
|
2789
2287
|
*
|
|
@@ -3043,7 +2541,7 @@ function useCreateDocument(options) {
|
|
|
3043
2541
|
trackHookUsage(useSanityInstance(), "useCreateDocument");
|
|
3044
2542
|
let apply = useApplyDocumentActions(), t0;
|
|
3045
2543
|
return $[0] !== apply || $[1] !== options ? (t0 = async (initialValue, overrides) => {
|
|
3046
|
-
let documentId = overrides?.documentId ?? options.documentId ??
|
|
2544
|
+
let documentId = overrides?.documentId ?? options.documentId ?? randomUuid(), handle = {
|
|
3047
2545
|
...options,
|
|
3048
2546
|
documentId
|
|
3049
2547
|
};
|
|
@@ -4515,7 +4013,7 @@ function useUsers(options) {
|
|
|
4515
4013
|
loadMore
|
|
4516
4014
|
}, $[20] = data, $[21] = hasMore, $[22] = isPending, $[23] = loadMore, $[24] = t8) : t8 = $[24], t8;
|
|
4517
4015
|
}
|
|
4518
|
-
var version = "3.
|
|
4016
|
+
var version = "3.1.0";
|
|
4519
4017
|
function getEnv(key) {
|
|
4520
4018
|
if (import.meta.env) return import.meta.env[key];
|
|
4521
4019
|
if (typeof process < "u" && process.env) return process.env[key];
|
|
@@ -4526,6 +4024,6 @@ function getEnv(key) {
|
|
|
4526
4024
|
* @internal
|
|
4527
4025
|
*/
|
|
4528
4026
|
const REACT_SDK_VERSION = getEnv("PKG_VERSION") || `${version}-development`;
|
|
4529
|
-
export { AuthBoundary, ComlinkTokenRefreshProvider, REACT_SDK_VERSION, ResourceProvider, SDKProvider, SDKStudioContext, SanityApp, SanityInstanceProvider, renderSanityApp, useActiveReleases, useAgentGenerate, useAgentPatch, useAgentPrompt,
|
|
4027
|
+
export { AuthBoundary, ComlinkTokenRefreshProvider, REACT_SDK_VERSION, ResourceProvider, SDKProvider, SDKStudioContext, SanityApp, SanityInstanceProvider, renderSanityApp, useActiveReleases, useAgentGenerate, useAgentPatch, useAgentPrompt, useAgentTransform, useAgentTranslate, useAllReleases, useApplication, useApplications, useApplyDocumentActions, useApplyReleaseActions, useAuthState, useAuthToken, useCheckPermissions, useClient, useCommentActions, useCommentThreads, useComments, useCreateDocument, useCurrentUser, useDatasets, useDeleteApplication, useDocument, useDocumentEvent, useDocumentPermissions, useDocumentPreview, useDocumentProjection, useDocumentSyncStatus, useDocuments, useEditDocument, useFavorite, useFrameConnection, useHandleAuthCallback, useInstallation, useInstallations, useLogOut, useLoginUrl, useOrganization, useOrganizations, usePaginatedDocuments, usePerspective, usePresence, usePresenceForDocument, useProject, useProjects, useQuery, useRecordDocumentHistoryEvent, useReportPresence, useResource, useSanityInstance, useStudioWorkspacesByProjectIdDataset, useUpdateApplication, useUpdateFavorite, useUser, useUsers, useVerifyOrgProjects, useWindowConnection };
|
|
4530
4028
|
|
|
4531
4029
|
//# sourceMappingURL=index.js.map
|