@sanity/sdk-react 3.0.0-rc.2 → 3.0.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 +209 -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 +134 -532
- package/dist/index.js.map +1 -1
- package/dist/useStudioWorkspacesByProjectIdDataset-I4S3CuR5.js +177 -0
- package/dist/useStudioWorkspacesByProjectIdDataset-I4S3CuR5.js.map +1 -0
- package/package.json +9 -8
- package/src/_exports/dashboard.ts +11 -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/{WorkbenchTokenRefresh.tsx → DashboardTokenRefresh.tsx} +14 -14
- package/src/context/OrganizationResourcesProvider.test.tsx +9 -9
- package/src/context/OrganizationResourcesProvider.tsx +2 -2
- package/src/context/{workbenchToken.ts → dashboardToken.ts} +13 -13
- 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/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,11 +1,12 @@
|
|
|
1
|
+
import { a as useSanityInstance, i as createStateSourceHook, n as useOrganizationId, o as SanityInstanceContext, r as useWindowConnection, t as useStudioWorkspacesByProjectIdDataset } from "./useStudioWorkspacesByProjectIdDataset-I4S3CuR5.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, getAuthState, getClientState, getCommentThreadsState, getCommentsState, getCorsErrorProjectId, getCurrentUserState,
|
|
4
|
+
import { AuthStateType, application, applications, applyDocumentActions, checkPermissions, createComment, createDocument, createSanityInstance, datasets, deleteApplication, editDocument, favorites, getActiveReleasesState, getAllReleasesState, getAuthState, 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";
|
|
4
5
|
import { PREVIEW_PROJECTION, createGroqSearchFilter, getClientErrorApiBody, getClientErrorApiDescription, getCommentsOptionsKey, getQueryKey, getUsersKey, initTelemetry, isDeepEqual, isProjectUserNotFoundClientError, isStudioConfig, parseCommentsOptionsKey, parseQueryKey, parseUsersKey, pickProperties, 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 { getOrCreateChannel, getOrCreateController, releaseChannel } from "@sanity/sdk/comlink";
|
|
9
10
|
import { EMPTY, Observable, distinctUntilChanged, filter, firstValueFrom, from, identity, of, startWith, switchMap } from "rxjs";
|
|
10
11
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
11
12
|
import { catchError, switchMap as switchMap$1 } from "rxjs/operators";
|
|
@@ -14,23 +15,6 @@ import { agentGenerate, agentPatch, agentPrompt, agentTransform, agentTranslate
|
|
|
14
15
|
import "groq";
|
|
15
16
|
import "@sanity/types";
|
|
16
17
|
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
18
|
/**
|
|
35
19
|
* @internal
|
|
36
20
|
* A React hook that subscribes to authentication state changes.
|
|
@@ -52,61 +36,11 @@ function createStateSourceHook(options) {
|
|
|
52
36
|
* }
|
|
53
37
|
* ```
|
|
54
38
|
*/
|
|
55
|
-
const useAuthState = createStateSourceHook(getAuthState)
|
|
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
|
-
}
|
|
39
|
+
const useAuthState = createStateSourceHook(getAuthState);
|
|
106
40
|
/**
|
|
107
41
|
* Component that handles token refresh in dashboard mode
|
|
108
42
|
*/
|
|
109
|
-
function DashboardTokenRefresh(t0) {
|
|
43
|
+
function DashboardTokenRefresh$1(t0) {
|
|
110
44
|
let $ = c(14), { children } = t0, instance = useSanityInstance(), isTokenRefreshInProgress = useRef(!1), timeoutRef = useRef(null), processed401ErrorRef = useRef(null), authState = useAuthState(), t1;
|
|
111
45
|
$[0] === Symbol.for("react.memo_cache_sentinel") ? (t1 = () => {
|
|
112
46
|
timeoutRef.current &&= (clearTimeout(timeoutRef.current), null);
|
|
@@ -159,12 +93,12 @@ const ComlinkTokenRefreshProvider = (t0) => {
|
|
|
159
93
|
let $ = c(2), { children } = t0, instance = useSanityInstance(), isInDashboard = getIsInDashboardState(instance).getCurrent(), isStudio = isStudioConfig(instance.config);
|
|
160
94
|
if (isInDashboard && !isStudio) {
|
|
161
95
|
let t1;
|
|
162
|
-
return $[0] === children ? t1 = $[1] : (t1 = /* @__PURE__ */ jsx(DashboardTokenRefresh, { children }), $[0] = children, $[1] = t1), t1;
|
|
96
|
+
return $[0] === children ? t1 = $[1] : (t1 = /* @__PURE__ */ jsx(DashboardTokenRefresh$1, { children }), $[0] = children, $[1] = t1), t1;
|
|
163
97
|
}
|
|
164
98
|
return children;
|
|
165
99
|
}, OS_BUS_KEY = Symbol.for("sanity.os.bus");
|
|
166
100
|
/**
|
|
167
|
-
* Whether this app is running as a federated remote inside the
|
|
101
|
+
* Whether this app is running as a federated remote inside the dashboard.
|
|
168
102
|
*
|
|
169
103
|
* Federation shares the host's realm, so the installed bus is visible on
|
|
170
104
|
* `globalThis`. This is `false` in a standalone app, where we must never import
|
|
@@ -175,15 +109,15 @@ const ComlinkTokenRefreshProvider = (t0) => {
|
|
|
175
109
|
*
|
|
176
110
|
* @internal
|
|
177
111
|
*/
|
|
178
|
-
function
|
|
112
|
+
function isDashboardEnvironment() {
|
|
179
113
|
return typeof globalThis == "object" && OS_BUS_KEY in globalThis;
|
|
180
114
|
}
|
|
181
115
|
/**
|
|
182
|
-
* Observes the session token issued by the
|
|
116
|
+
* Observes the session token issued by the dashboard "OS", tracking the OS auth
|
|
183
117
|
* state over time.
|
|
184
118
|
*
|
|
185
|
-
* Returns `undefined` when the app is not embedded in the
|
|
186
|
-
* caller uses its normal auth flow. Inside the
|
|
119
|
+
* Returns `undefined` when the app is not embedded in the dashboard, so the
|
|
120
|
+
* caller uses its normal auth flow. Inside the dashboard, subscribes to the
|
|
187
121
|
* `auth.token` state topic, emitting the current token — or `null` when the OS
|
|
188
122
|
* is signed out — and re-emitting as the OS auth state changes, so sign-in/out
|
|
189
123
|
* propagates instead of being captured once. Any bus error is treated as "no
|
|
@@ -191,34 +125,34 @@ function isWorkbenchEnvironment() {
|
|
|
191
125
|
*
|
|
192
126
|
* @internal
|
|
193
127
|
*/
|
|
194
|
-
function
|
|
195
|
-
if (
|
|
128
|
+
function observeDashboardToken() {
|
|
129
|
+
if (isDashboardEnvironment()) return from(import("@sanity/workbench")).pipe(switchMap$1(({ os }) => os.subscribe("auth.token")), catchError(() => of(null)));
|
|
196
130
|
}
|
|
197
131
|
/**
|
|
198
|
-
* Asks the
|
|
132
|
+
* Asks the dashboard "OS" to reissue the session token, e.g. after its current
|
|
199
133
|
* one was rejected with a 401. Fire-and-forget: the reissued token arrives via
|
|
200
|
-
* the `auth.token` subscription in {@link
|
|
201
|
-
* the
|
|
134
|
+
* the `auth.token` subscription in {@link observeDashboardToken}. No-op outside
|
|
135
|
+
* the dashboard.
|
|
202
136
|
*
|
|
203
137
|
* @internal
|
|
204
138
|
*/
|
|
205
|
-
function
|
|
206
|
-
|
|
139
|
+
function refreshDashboardToken() {
|
|
140
|
+
isDashboardEnvironment() && import("@sanity/workbench").then(({ os }) => os.emit("auth.token.refresh", void 0), () => {});
|
|
207
141
|
}
|
|
208
142
|
/**
|
|
209
|
-
* Keeps the SDK auth token in sync with the
|
|
143
|
+
* Keeps the SDK auth token in sync with the dashboard "OS".
|
|
210
144
|
*
|
|
211
|
-
* When running as a federated remote inside the
|
|
145
|
+
* When running as a federated remote inside the dashboard the OS owns the
|
|
212
146
|
* session, so we subscribe to its `auth.token` stream and mirror each value into
|
|
213
147
|
* the auth store — a token logs us in, `null` logs us out, and later OS
|
|
214
148
|
* sign-in/out propagates automatically. When a request is rejected with a 401
|
|
215
149
|
* (the token expired), we ask the OS to reissue rather than tearing the session
|
|
216
150
|
* down; the new token arrives back through the same subscription.
|
|
217
151
|
*/
|
|
218
|
-
function
|
|
152
|
+
function DashboardTokenRefresh(t0) {
|
|
219
153
|
let $ = c(8), { children } = t0, instance = useSanityInstance(), authState = useAuthState(), processed401ErrorRef = useRef(null), t1, t2;
|
|
220
154
|
$[0] === instance ? (t1 = $[1], t2 = $[2]) : (t1 = () => {
|
|
221
|
-
let token$ =
|
|
155
|
+
let token$ = observeDashboardToken();
|
|
222
156
|
if (!token$) return;
|
|
223
157
|
let subscription = token$.subscribe((token) => setAuthToken(instance, token));
|
|
224
158
|
return () => subscription.unsubscribe();
|
|
@@ -226,21 +160,21 @@ function WorkbenchTokenRefresh(t0) {
|
|
|
226
160
|
let t3;
|
|
227
161
|
$[3] !== authState.error || $[4] !== authState.type ? (t3 = () => {
|
|
228
162
|
let has401Error = authState.type === AuthStateType.ERROR && authState.error?.statusCode === 401;
|
|
229
|
-
has401Error && processed401ErrorRef.current !== authState.error ? (processed401ErrorRef.current = authState.error,
|
|
163
|
+
has401Error && processed401ErrorRef.current !== authState.error ? (processed401ErrorRef.current = authState.error, refreshDashboardToken()) : has401Error || (processed401ErrorRef.current = null);
|
|
230
164
|
}, $[3] = authState.error, $[4] = authState.type, $[5] = t3) : t3 = $[5];
|
|
231
165
|
let t4;
|
|
232
166
|
return $[6] === authState ? t4 = $[7] : (t4 = [authState], $[6] = authState, $[7] = t4), useEffect(t3, t4), children;
|
|
233
167
|
}
|
|
234
168
|
/**
|
|
235
|
-
* Provides
|
|
169
|
+
* Provides dashboard OS token refresh. No-op outside the dashboard, where the
|
|
236
170
|
* app uses its normal auth flow.
|
|
237
|
-
* @
|
|
171
|
+
* @internal
|
|
238
172
|
*/
|
|
239
|
-
const
|
|
173
|
+
const DashboardTokenRefreshProvider = (t0) => {
|
|
240
174
|
let $ = c(2), { children } = t0;
|
|
241
|
-
if (
|
|
175
|
+
if (isDashboardEnvironment()) {
|
|
242
176
|
let t1;
|
|
243
|
-
return $[0] === children ? t1 = $[1] : (t1 = /* @__PURE__ */ jsx(
|
|
177
|
+
return $[0] === children ? t1 = $[1] : (t1 = /* @__PURE__ */ jsx(DashboardTokenRefresh, { children }), $[0] = children, $[1] = t1), t1;
|
|
244
178
|
}
|
|
245
179
|
return children;
|
|
246
180
|
};
|
|
@@ -699,7 +633,7 @@ function AuthBoundary(t0) {
|
|
|
699
633
|
let t4;
|
|
700
634
|
$[7] === props ? t4 = $[8] : (t4 = /* @__PURE__ */ jsx(AuthSwitch, { ...props }), $[7] = props, $[8] = t4);
|
|
701
635
|
let t5;
|
|
702
|
-
return $[9] !== FallbackComponent || $[10] !== t3 || $[11] !== t4 ? (t5 = /* @__PURE__ */ jsx(ComlinkTokenRefreshProvider, { children: /* @__PURE__ */ jsx(
|
|
636
|
+
return $[9] !== FallbackComponent || $[10] !== t3 || $[11] !== t4 ? (t5 = /* @__PURE__ */ jsx(ComlinkTokenRefreshProvider, { children: /* @__PURE__ */ jsx(DashboardTokenRefreshProvider, { children: /* @__PURE__ */ jsx(ErrorBoundary, {
|
|
703
637
|
FallbackComponent,
|
|
704
638
|
resetKeys: t3,
|
|
705
639
|
children: t4
|
|
@@ -712,7 +646,7 @@ function AuthSwitch(t0) {
|
|
|
712
646
|
$[6] === instance.config ? t3 = $[7] : (t3 = isStudioConfig(instance.config), $[6] = instance.config, $[7] = t3);
|
|
713
647
|
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
648
|
if ($[8] !== isLoggedOut || $[9] !== isStudio || $[10] !== loginUrl ? (t4 = () => {
|
|
715
|
-
isLoggedOut && !isInIframe() && !isStudio && !
|
|
649
|
+
isLoggedOut && !isInIframe() && !isStudio && !isDashboardEnvironment() && (window.location.href = loginUrl);
|
|
716
650
|
}, t5 = [
|
|
717
651
|
isLoggedOut,
|
|
718
652
|
loginUrl,
|
|
@@ -771,31 +705,6 @@ SDKStudioContext.displayName = "SDKStudioContext";
|
|
|
771
705
|
*/
|
|
772
706
|
const DEFAULT_RESOURCE_NAME = "default";
|
|
773
707
|
/**
|
|
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
708
|
* Gets the id of the first resource from a settled request result. The request
|
|
800
709
|
* is already scoped to a single organization, so the first item is the one we want.
|
|
801
710
|
*/
|
|
@@ -870,7 +779,7 @@ function InferredResourcesProvider(t0) {
|
|
|
870
779
|
function OrganizationResourcesProvider(t0) {
|
|
871
780
|
let $ = c(10), { resources: t1, inferMediaLibraryAndCanvas, children } = t0, t2;
|
|
872
781
|
$[0] === t1 ? t2 = $[1] : (t2 = t1 === void 0 ? {} : t1, $[0] = t1, $[1] = t2);
|
|
873
|
-
let explicitResources = t2, instance = useSanityInstance(), orgId =
|
|
782
|
+
let explicitResources = t2, instance = useSanityInstance(), orgId = useOrganizationId();
|
|
874
783
|
if (!inferMediaLibraryAndCanvas || !orgId) {
|
|
875
784
|
let t3;
|
|
876
785
|
return $[2] !== children || $[3] !== explicitResources ? (t3 = /* @__PURE__ */ jsx(ResourcesContext.Provider, {
|
|
@@ -1885,71 +1794,6 @@ function useAgentPatch(resourceHandle) {
|
|
|
1885
1794
|
return $[2] !== instance || $[3] !== resource ? (t1 = (options) => firstValueFrom(agentPatch(instance, options, resource)), $[2] = instance, $[3] = resource, $[4] = t1) : t1 = $[4], t1;
|
|
1886
1795
|
}
|
|
1887
1796
|
/**
|
|
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
1797
|
* Returns a single application by id.
|
|
1954
1798
|
*
|
|
1955
1799
|
* The hook suspends until the first fetch succeeds, so `data` is always present.
|
|
@@ -2300,311 +2144,52 @@ function useResource() {
|
|
|
2300
2144
|
return useEffectiveContextResource();
|
|
2301
2145
|
}
|
|
2302
2146
|
/**
|
|
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.
|
|
2147
|
+
* Resolves {@link UseFavoriteProps} into the {@link FavoriteDocumentContext}
|
|
2148
|
+
* shared by the favorites fetcher and mutation, defaulting a studio `resourceId`
|
|
2149
|
+
* from the instance's project and dataset.
|
|
2312
2150
|
*
|
|
2313
|
-
* This hook is intended to receive those messages, and takes a function to route to the correct path.
|
|
2314
|
-
*
|
|
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
2151
|
* @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
2152
|
*/
|
|
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;
|
|
2153
|
+
function useFavoriteContext(t0) {
|
|
2154
|
+
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
2155
|
if (resourceType === "studio" && (!projectId || !dataset)) throw Error("projectId and dataset are required for studio resources");
|
|
2406
2156
|
let resourceId = resourceType === "studio" && !paramResourceId ? `${projectId}.${dataset}` : paramResourceId;
|
|
2407
2157
|
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
|
-
}), [
|
|
2158
|
+
let t1;
|
|
2159
|
+
return $[0] !== documentId || $[1] !== documentType || $[2] !== resourceId || $[3] !== resourceType || $[4] !== schemaName ? (t1 = {
|
|
2415
2160
|
documentId,
|
|
2416
2161
|
documentType,
|
|
2417
2162
|
resourceId,
|
|
2418
2163
|
resourceType,
|
|
2419
2164
|
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
|
-
};
|
|
2165
|
+
}, $[0] = documentId, $[1] = documentType, $[2] = resourceId, $[3] = resourceType, $[4] = schemaName, $[5] = t1) : t1 = $[5], t1;
|
|
2453
2166
|
}
|
|
2167
|
+
const useFavoriteStatus = createFetcherHook(favorites);
|
|
2454
2168
|
/**
|
|
2455
|
-
* Hook that fetches studio workspaces and organizes them by projectId:dataset
|
|
2456
2169
|
* @internal
|
|
2457
2170
|
*
|
|
2458
|
-
*
|
|
2459
|
-
*
|
|
2460
|
-
* import {useStudioWorkspacesByProjectIdDataset} from '@sanity/sdk-react'
|
|
2461
|
-
* import {Card, Code, Button} from '@sanity/ui'
|
|
2462
|
-
* import {Suspense} from 'react'
|
|
2463
|
-
*
|
|
2464
|
-
* function WorkspacesCard() {
|
|
2465
|
-
* const {workspacesByProjectIdAndDataset, error} = useStudioWorkspacesByProjectIdDataset()
|
|
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
|
-
* }
|
|
2477
|
-
*
|
|
2478
|
-
* // Wrap the component with Suspense since the hook may suspend
|
|
2479
|
-
* function DashboardWorkspaces() {
|
|
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.
|
|
2171
|
+
* Reads whether a document is currently favorited. The write-side counterpart is
|
|
2172
|
+
* {@link useUpdateFavorite}.
|
|
2533
2173
|
*
|
|
2534
|
-
*
|
|
2535
|
-
*
|
|
2174
|
+
* The hook suspends until the first favorite status resolves, so wrap the
|
|
2175
|
+
* component in a `<Suspense>` boundary.
|
|
2536
2176
|
*
|
|
2537
|
-
* @
|
|
2538
|
-
*
|
|
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
|
|
2177
|
+
* @param props - The document handle plus the resource it lives in.
|
|
2178
|
+
* @returns `true` when the document is favorited, otherwise `false`.
|
|
2546
2179
|
*
|
|
2547
2180
|
* @example
|
|
2548
2181
|
* ```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
|
-
* }
|
|
2182
|
+
* function FavoriteLabel(props: DocumentActionProps) {
|
|
2183
|
+
* const {documentId, documentType} = props
|
|
2184
|
+
* const isFavorited = useFavorite({documentId, documentType, resourceType: 'studio'})
|
|
2562
2185
|
*
|
|
2563
|
-
*
|
|
2564
|
-
* function MyDocumentAction({documentHandle}: {documentHandle: DocumentHandle}) {
|
|
2565
|
-
* return (
|
|
2566
|
-
* <Suspense fallback={<Button text="Loading..." disabled />}>
|
|
2567
|
-
* <NavigateButton documentHandle={documentHandle} />
|
|
2568
|
-
* </Suspense>
|
|
2569
|
-
* )
|
|
2186
|
+
* return <span>{isFavorited ? 'Favorited' : 'Not favorited'}</span>
|
|
2570
2187
|
* }
|
|
2571
2188
|
* ```
|
|
2572
2189
|
*/
|
|
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;
|
|
2190
|
+
function useFavorite(props) {
|
|
2191
|
+
let context = useFavoriteContext(props), { data } = useFavoriteStatus(context);
|
|
2192
|
+
return data.isFavorited;
|
|
2608
2193
|
}
|
|
2609
2194
|
/**
|
|
2610
2195
|
* @internal
|
|
@@ -2682,75 +2267,65 @@ function useRecordDocumentHistoryEvent(t0) {
|
|
|
2682
2267
|
let recordEvent = t2, t3;
|
|
2683
2268
|
return $[8] === recordEvent ? t3 = $[9] : (t3 = { recordEvent }, $[8] = recordEvent, $[9] = t3), t3;
|
|
2684
2269
|
}
|
|
2685
|
-
|
|
2686
|
-
return resource.manifest?.title || resource.activeDeployment?.manifest?.title || resource.title;
|
|
2687
|
-
}
|
|
2270
|
+
const useSetFavorite = createMutationHook(setFavorite);
|
|
2688
2271
|
/**
|
|
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:
|
|
2272
|
+
* @internal
|
|
2694
2273
|
*
|
|
2695
|
-
*
|
|
2696
|
-
*
|
|
2274
|
+
* Adds or removes a document from favorites. The read-side counterpart is
|
|
2275
|
+
* {@link useFavorite}, which reflects the change once the mutation settles.
|
|
2697
2276
|
*
|
|
2698
|
-
*
|
|
2277
|
+
* Unlike {@link useFavorite}, this hook does not suspend.
|
|
2699
2278
|
*
|
|
2700
|
-
* @param
|
|
2279
|
+
* @param props - The document handle plus the resource it lives in.
|
|
2280
|
+
* @returns `favorite`/`unfavorite` actions and the `{isPending, error, reset}`
|
|
2281
|
+
* mutation state.
|
|
2701
2282
|
*
|
|
2702
2283
|
* @example
|
|
2703
2284
|
* ```tsx
|
|
2704
|
-
*
|
|
2285
|
+
* function FavoriteButton(props: DocumentActionProps) {
|
|
2286
|
+
* const {documentId, documentType} = props
|
|
2287
|
+
* const handle = {documentId, documentType, resourceType: 'studio'} as const
|
|
2288
|
+
* const isFavorited = useFavorite(handle)
|
|
2289
|
+
* const {favorite, unfavorite, isPending} = useUpdateFavorite(handle)
|
|
2705
2290
|
*
|
|
2706
|
-
*
|
|
2707
|
-
*
|
|
2708
|
-
*
|
|
2291
|
+
* return (
|
|
2292
|
+
* <Button
|
|
2293
|
+
* disabled={isPending}
|
|
2294
|
+
* onClick={() => (isFavorited ? unfavorite() : favorite())}
|
|
2295
|
+
* text={isFavorited ? 'Remove from favorites' : 'Add to favorites'}
|
|
2296
|
+
* />
|
|
2297
|
+
* )
|
|
2709
2298
|
* }
|
|
2710
2299
|
*
|
|
2711
|
-
* //
|
|
2712
|
-
*
|
|
2713
|
-
*
|
|
2714
|
-
*
|
|
2715
|
-
*
|
|
2716
|
-
*
|
|
2717
|
-
*
|
|
2718
|
-
* useWindowTitle()
|
|
2719
|
-
* return <Outlet />
|
|
2300
|
+
* // Wrap the component with Suspense since useFavorite suspends
|
|
2301
|
+
* function MyDocumentAction(props: DocumentActionProps) {
|
|
2302
|
+
* return (
|
|
2303
|
+
* <Suspense fallback={<Button text="Loading..." disabled />}>
|
|
2304
|
+
* <FavoriteButton {...props} />
|
|
2305
|
+
* </Suspense>
|
|
2306
|
+
* )
|
|
2720
2307
|
* }
|
|
2721
|
-
*
|
|
2722
|
-
* // Browser tab: "My App | Sanity"
|
|
2723
2308
|
* ```
|
|
2724
|
-
*
|
|
2725
|
-
* @public
|
|
2726
2309
|
*/
|
|
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]);
|
|
2310
|
+
function useUpdateFavorite(props) {
|
|
2311
|
+
let $ = c(12), context = useFavoriteContext(props), { mutate, isPending, error, reset } = useSetFavorite(), t0;
|
|
2312
|
+
$[0] !== context || $[1] !== mutate ? (t0 = () => mutate({
|
|
2313
|
+
...context,
|
|
2314
|
+
isFavorited: !0
|
|
2315
|
+
}), $[0] = context, $[1] = mutate, $[2] = t0) : t0 = $[2];
|
|
2316
|
+
let favorite = t0, t1;
|
|
2317
|
+
$[3] !== context || $[4] !== mutate ? (t1 = () => mutate({
|
|
2318
|
+
...context,
|
|
2319
|
+
isFavorited: !1
|
|
2320
|
+
}), $[3] = context, $[4] = mutate, $[5] = t1) : t1 = $[5];
|
|
2321
|
+
let unfavorite = t1, t2;
|
|
2322
|
+
return $[6] !== error || $[7] !== favorite || $[8] !== isPending || $[9] !== reset || $[10] !== unfavorite ? (t2 = {
|
|
2323
|
+
favorite,
|
|
2324
|
+
unfavorite,
|
|
2325
|
+
isPending,
|
|
2326
|
+
error,
|
|
2327
|
+
reset
|
|
2328
|
+
}, $[6] = error, $[7] = favorite, $[8] = isPending, $[9] = reset, $[10] = unfavorite, $[11] = t2) : t2 = $[11], t2;
|
|
2754
2329
|
}
|
|
2755
2330
|
/**
|
|
2756
2331
|
* Resolves the effective `projectId` for project-scoped hooks (`useProject`,
|
|
@@ -2773,17 +2348,44 @@ function useResolvedProjectId(options) {
|
|
|
2773
2348
|
let { resource } = useNormalizedResourceOptions(t0), contextProjectId = useContext(ProjectContext), t1;
|
|
2774
2349
|
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
2350
|
}
|
|
2776
|
-
const useDatasetsBase =
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2351
|
+
const useDatasetsBase = createFetcherHook(datasets);
|
|
2352
|
+
/**
|
|
2353
|
+
* Returns metadata for each dataset the current user has access to.
|
|
2354
|
+
*
|
|
2355
|
+
* @category Datasets
|
|
2356
|
+
* @param options - Optional project/resource to read datasets for. Defaults to
|
|
2357
|
+
* the resource named in `ResourceProvider`/`SDKProvider`.
|
|
2358
|
+
* @returns A {@link FetcherHookResult} whose `data` is the metadata for the
|
|
2359
|
+
* datasets.
|
|
2360
|
+
*
|
|
2361
|
+
* @example
|
|
2362
|
+
* ```tsx
|
|
2363
|
+
* const {data: datasets} = useDatasets()
|
|
2364
|
+
*
|
|
2365
|
+
* return (
|
|
2366
|
+
* <select>
|
|
2367
|
+
* {datasets.map((dataset) => (
|
|
2368
|
+
* <option key={dataset.name}>{dataset.name}</option>
|
|
2369
|
+
* ))}
|
|
2370
|
+
* </select>
|
|
2371
|
+
* )
|
|
2372
|
+
* ```
|
|
2373
|
+
*
|
|
2374
|
+
* @remarks
|
|
2375
|
+
* The `projectId` is resolved in order from:
|
|
2376
|
+
* 1. an explicit `projectId` option
|
|
2377
|
+
* 2. A legacy ProjectContext (e.g. a `<ResourceProvider projectId="…">` with no dataset), then
|
|
2378
|
+
* 3. The active resource (`ResourceProvider`/`SDKProvider`)
|
|
2379
|
+
* 4. `instance.config`.
|
|
2380
|
+
* @public
|
|
2381
|
+
*/
|
|
2382
|
+
function useDatasets(options) {
|
|
2781
2383
|
let $ = c(3), projectId = useResolvedProjectId(options), t0;
|
|
2782
2384
|
return $[0] !== options || $[1] !== projectId ? (t0 = projectId ? {
|
|
2783
2385
|
...options,
|
|
2784
2386
|
projectId
|
|
2785
2387
|
} : options, $[0] = options, $[1] = projectId, $[2] = t0) : t0 = $[2], useDatasetsBase(t0);
|
|
2786
|
-
}
|
|
2388
|
+
}
|
|
2787
2389
|
/**
|
|
2788
2390
|
* @internal
|
|
2789
2391
|
*
|
|
@@ -4515,7 +4117,7 @@ function useUsers(options) {
|
|
|
4515
4117
|
loadMore
|
|
4516
4118
|
}, $[20] = data, $[21] = hasMore, $[22] = isPending, $[23] = loadMore, $[24] = t8) : t8 = $[24], t8;
|
|
4517
4119
|
}
|
|
4518
|
-
var version = "3.0.0
|
|
4120
|
+
var version = "3.0.0";
|
|
4519
4121
|
function getEnv(key) {
|
|
4520
4122
|
if (import.meta.env) return import.meta.env[key];
|
|
4521
4123
|
if (typeof process < "u" && process.env) return process.env[key];
|
|
@@ -4526,6 +4128,6 @@ function getEnv(key) {
|
|
|
4526
4128
|
* @internal
|
|
4527
4129
|
*/
|
|
4528
4130
|
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,
|
|
4131
|
+
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
4132
|
|
|
4531
4133
|
//# sourceMappingURL=index.js.map
|