@sanity/sdk-react 3.0.0-rc.0 → 3.0.0-rc.2
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/README.md +103 -155
- package/dist/index.d.ts +2488 -2019
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4435 -1529
- package/dist/index.js.map +1 -1
- package/package.json +55 -59
- package/src/_exports/index.ts +2 -4
- package/src/_exports/sdk-react.ts +30 -18
- package/src/components/SDKProvider.test.tsx +173 -32
- package/src/components/SDKProvider.tsx +87 -28
- package/src/components/SanityApp.test.tsx +68 -12
- package/src/components/SanityApp.tsx +93 -87
- package/src/components/auth/AuthBoundary.recovery.test.tsx +86 -0
- package/src/components/auth/AuthBoundary.test.tsx +7 -7
- package/src/components/auth/AuthBoundary.tsx +29 -6
- package/src/components/auth/DashboardAccessRequest.tsx +37 -0
- package/src/components/auth/LoginError.test.tsx +191 -5
- package/src/components/auth/LoginError.tsx +104 -61
- package/src/components/errors/ChunkLoadError.test.tsx +59 -0
- package/src/components/errors/ChunkLoadError.tsx +56 -0
- package/src/components/errors/CorsErrorComponent.tsx +2 -2
- package/src/components/errors/chunkReloadStorage.ts +57 -0
- package/src/config/handles.ts +29 -27
- package/src/constants.ts +5 -0
- package/src/context/ComlinkTokenRefresh.test.tsx +10 -27
- package/src/context/ComlinkTokenRefresh.tsx +3 -5
- package/src/context/DefaultResourceContext.ts +3 -3
- package/src/context/OrganizationResourcesProvider.test.tsx +189 -0
- package/src/context/OrganizationResourcesProvider.tsx +111 -0
- package/src/context/PerspectiveContext.ts +3 -3
- package/src/context/ProjectContext.ts +15 -0
- package/src/context/ResourceProvider.test.tsx +93 -90
- package/src/context/ResourceProvider.tsx +62 -93
- package/src/context/SDKStudioContext.test.tsx +28 -33
- package/src/context/SanityInstanceProvider.test.tsx +100 -0
- package/src/context/SanityInstanceProvider.tsx +71 -0
- package/src/context/WorkbenchTokenRefresh.test.tsx +106 -0
- package/src/context/WorkbenchTokenRefresh.tsx +61 -0
- package/src/context/renderSanityApp.test.tsx +151 -49
- package/src/context/renderSanityApp.tsx +12 -8
- package/src/context/workbenchToken.ts +63 -0
- package/src/hooks/access/useCheckPermissions.test-d.ts +15 -0
- package/src/hooks/access/useCheckPermissions.test.tsx +53 -0
- package/src/hooks/access/useCheckPermissions.ts +24 -0
- package/src/hooks/agent/agentActions.test.tsx +2 -2
- package/src/hooks/agent/agentActions.ts +52 -72
- package/src/hooks/agent/useAgentResourceContext.ts +1 -1
- package/src/hooks/applications/useApplication.test-d.ts +30 -0
- package/src/hooks/applications/useApplication.ts +22 -0
- package/src/hooks/applications/useApplications.test-d.ts +31 -0
- package/src/hooks/applications/useApplications.ts +25 -0
- package/src/hooks/applications/useDeleteApplication.test-d.ts +12 -0
- package/src/hooks/applications/useDeleteApplication.ts +11 -0
- package/src/hooks/applications/useUpdateApplication.test-d.ts +12 -0
- package/src/hooks/applications/useUpdateApplication.ts +11 -0
- package/src/hooks/auth/useDashboardOrganizationId.test.tsx +2 -8
- package/src/hooks/auth/useVerifyOrgProjects.test.tsx +8 -32
- package/src/hooks/auth/useVerifyOrgProjects.tsx +13 -6
- package/src/hooks/client/useClient.test.tsx +1 -4
- package/src/hooks/client/useClient.ts +1 -0
- package/src/hooks/comlink/useFrameConnection.test.tsx +3 -2
- package/src/hooks/comlink/useFrameConnection.ts +1 -1
- package/src/hooks/comlink/useWindowConnection.test.tsx +4 -3
- package/src/hooks/comlink/useWindowConnection.ts +2 -3
- package/src/hooks/comments/useCommentActions.test.tsx +150 -0
- package/src/hooks/comments/useCommentActions.ts +109 -0
- package/src/hooks/comments/useCommentList.ts +79 -0
- package/src/hooks/comments/useCommentThreads.test.tsx +107 -0
- package/src/hooks/comments/useCommentThreads.ts +73 -0
- package/src/hooks/comments/useComments.test.tsx +242 -0
- package/src/hooks/comments/useComments.ts +59 -0
- package/src/hooks/context/useResource.test.tsx +32 -0
- package/src/hooks/context/useResource.ts +24 -0
- package/src/hooks/context/useSanityInstance.test.tsx +18 -1
- package/src/hooks/context/useSanityInstance.ts +6 -6
- package/src/hooks/dashboard/useManageFavorite.test.tsx +110 -46
- package/src/hooks/dashboard/useManageFavorite.ts +11 -17
- package/src/hooks/dashboard/useNavigateToStudioDocument.test.ts +5 -7
- package/src/hooks/dashboard/useNavigateToStudioDocument.ts +2 -6
- package/src/hooks/dashboard/useRecordDocumentHistoryEvent.test.ts +0 -2
- package/src/hooks/dashboard/useRecordDocumentHistoryEvent.ts +2 -2
- package/src/hooks/dashboard/useWindowTitle.test.ts +244 -0
- package/src/hooks/dashboard/useWindowTitle.ts +114 -0
- package/src/hooks/datasets/useDatasets.test.tsx +116 -0
- package/src/hooks/datasets/useDatasets.ts +33 -13
- package/src/hooks/document/useApplyDocumentActions.test.tsx +48 -0
- package/src/hooks/document/useApplyDocumentActions.ts +66 -48
- package/src/hooks/document/useCreateDocument.test.tsx +83 -0
- package/src/hooks/document/useCreateDocument.ts +117 -0
- package/src/hooks/document/useDocument.test.tsx +37 -8
- package/src/hooks/document/useDocument.ts +131 -66
- package/src/hooks/document/useDocumentEvent.test.tsx +16 -4
- package/src/hooks/document/useDocumentEvent.ts +16 -10
- package/src/hooks/document/useDocumentPermissions.test.tsx +8 -7
- package/src/hooks/document/useDocumentPermissions.ts +71 -39
- package/src/hooks/document/useDocumentSyncStatus.test.ts +1 -0
- package/src/hooks/document/useDocumentSyncStatus.ts +13 -9
- package/src/hooks/document/useEditDocument.test.tsx +21 -14
- package/src/hooks/document/useEditDocument.ts +163 -17
- package/src/hooks/documents/useDocuments.test.tsx +64 -44
- package/src/hooks/documents/useDocuments.ts +31 -20
- package/src/hooks/helpers/createCallbackHook.test.tsx +13 -19
- package/src/hooks/helpers/createFetcherHook.test.tsx +180 -0
- package/src/hooks/helpers/createFetcherHook.ts +69 -0
- package/src/hooks/helpers/createMutationHook.test.tsx +125 -0
- package/src/hooks/helpers/createMutationHook.tsx +93 -0
- package/src/hooks/helpers/createStateSourceHook.test.tsx +10 -10
- package/src/hooks/helpers/createStateSourceHook.tsx +2 -1
- package/src/hooks/{document/useApplyDocumentActions.test.ts → helpers/useApplyActions.test.tsx} +92 -53
- package/src/hooks/helpers/useApplyActions.ts +68 -0
- package/src/hooks/helpers/useNormalizedResourceOptions.test.tsx +226 -0
- package/src/hooks/helpers/useNormalizedResourceOptions.ts +79 -48
- package/src/hooks/helpers/useResolvedProjectId.test.tsx +59 -0
- package/src/hooks/helpers/useResolvedProjectId.ts +35 -0
- package/src/hooks/helpers/useTrackHookUsage.ts +37 -0
- package/src/hooks/installations/useInstallation.test-d.ts +19 -0
- package/src/hooks/installations/useInstallation.ts +22 -0
- package/src/hooks/installations/useInstallations.test-d.ts +26 -0
- package/src/hooks/installations/useInstallations.ts +25 -0
- package/src/hooks/organizations/useOrganization.test-d.ts +60 -0
- package/src/hooks/organizations/useOrganization.test.ts +63 -0
- package/src/hooks/organizations/useOrganization.ts +34 -0
- package/src/hooks/organizations/useOrganizations.test-d.ts +68 -0
- package/src/hooks/organizations/useOrganizations.test.ts +63 -0
- package/src/hooks/organizations/useOrganizations.ts +39 -0
- package/src/hooks/paginatedDocuments/usePaginatedDocuments.test.tsx +34 -27
- package/src/hooks/paginatedDocuments/usePaginatedDocuments.ts +35 -22
- package/src/hooks/presence/usePresence.test.tsx +0 -15
- package/src/hooks/presence/usePresence.ts +22 -20
- package/src/hooks/presence/usePresenceForDocument.test.tsx +141 -0
- package/src/hooks/presence/usePresenceForDocument.ts +104 -0
- package/src/hooks/presence/useReportPresence.test.tsx +202 -0
- package/src/hooks/presence/useReportPresence.ts +170 -0
- package/src/hooks/preview/useDocumentPreview.test.tsx +0 -1
- package/src/hooks/preview/useDocumentPreview.tsx +12 -14
- package/src/hooks/projection/useDocumentProjection.test.tsx +78 -9
- package/src/hooks/projection/useDocumentProjection.ts +81 -2
- package/src/hooks/projects/useProject.test-d.ts +56 -0
- package/src/hooks/projects/useProject.test.tsx +120 -0
- package/src/hooks/projects/useProject.ts +42 -43
- package/src/hooks/projects/useProjects.test-d.ts +60 -0
- package/src/hooks/projects/useProjects.test.ts +45 -98
- package/src/hooks/projects/useProjects.ts +17 -32
- package/src/hooks/query/useQuery.test.tsx +6 -5
- package/src/hooks/query/useQuery.ts +94 -17
- package/src/hooks/releases/useActiveReleases.test.tsx +13 -7
- package/src/hooks/releases/useActiveReleases.ts +28 -24
- package/src/hooks/releases/useAllReleases.test.tsx +93 -0
- package/src/hooks/releases/useAllReleases.ts +62 -0
- package/src/hooks/releases/useApplyReleaseActions.test.tsx +66 -0
- package/src/hooks/releases/useApplyReleaseActions.ts +82 -0
- package/src/hooks/releases/usePerspective.test.tsx +18 -10
- package/src/hooks/releases/usePerspective.ts +13 -17
- package/src/hooks/users/useUser.test.tsx +3 -9
- package/src/hooks/users/useUser.ts +4 -8
- package/src/hooks/users/useUsers.test.tsx +103 -7
- package/src/hooks/users/useUsers.ts +38 -5
- package/src/utils/resolveOrgResources.test.ts +111 -0
- package/src/utils/resolveOrgResources.ts +69 -0
- package/src/hooks/context/useDefaultResource.test.tsx +0 -25
- package/src/hooks/context/useDefaultResource.ts +0 -30
- package/src/hooks/dashboard/useDispatchIntent.test.ts +0 -254
- package/src/hooks/dashboard/useDispatchIntent.ts +0 -157
- package/src/hooks/dashboard/utils/useResourceIdFromDocumentHandle.test.ts +0 -107
- package/src/hooks/dashboard/utils/useResourceIdFromDocumentHandle.ts +0 -39
- package/src/hooks/datasets/useDatasets.test.ts +0 -66
- package/src/hooks/helpers/useNormalizedResourceOptions.test.ts +0 -65
- package/src/hooks/projects/useProject.test.ts +0 -79
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
|
-
type DocumentHandle
|
|
2
|
+
type DocumentHandle,
|
|
3
|
+
type DocumentOptions,
|
|
3
4
|
getDocumentSyncStatus,
|
|
4
5
|
resolveDocument,
|
|
5
6
|
type SanityInstance,
|
|
6
7
|
type StateSource,
|
|
7
8
|
} from '@sanity/sdk'
|
|
9
|
+
import {identity} from 'rxjs'
|
|
8
10
|
|
|
9
|
-
import {type DocumentHandle} from '../../config/handles'
|
|
10
11
|
import {createStateSourceHook} from '../helpers/createStateSourceHook'
|
|
11
12
|
import {useNormalizedResourceOptions} from '../helpers/useNormalizedResourceOptions'
|
|
12
13
|
|
|
@@ -15,9 +16,9 @@ type UseDocumentSyncStatus = {
|
|
|
15
16
|
* Exposes the document's sync status between local and remote document states.
|
|
16
17
|
*
|
|
17
18
|
* @category Documents
|
|
18
|
-
* @param doc - The document handle to get sync status for. If you pass a `
|
|
19
|
-
* the document will be read from the specified
|
|
20
|
-
* the
|
|
19
|
+
* @param doc - The document handle to get sync status for. If you pass a `DocumentHandle` with specified `projectId` and `dataset`,
|
|
20
|
+
* the document will be read from the specified Sanity project and dataset that is included in the handle. If no `projectId` or `dataset` is provided,
|
|
21
|
+
* the document will use the nearest instance from context.
|
|
21
22
|
* @returns `true` if local changes are synced with remote, `false` if changes are pending. Note: Suspense handles loading states.
|
|
22
23
|
* @example Show sync status indicator
|
|
23
24
|
* ```tsx
|
|
@@ -49,18 +50,21 @@ type UseDocumentSyncStatus = {
|
|
|
49
50
|
const useDocumentSyncStatusValue = createStateSourceHook({
|
|
50
51
|
getState: getDocumentSyncStatus as (
|
|
51
52
|
instance: SanityInstance,
|
|
52
|
-
doc:
|
|
53
|
+
doc: DocumentHandle,
|
|
53
54
|
) => StateSource<boolean>,
|
|
54
|
-
shouldSuspend: (instance, doc:
|
|
55
|
+
shouldSuspend: (instance, doc: DocumentHandle) =>
|
|
55
56
|
getDocumentSyncStatus(instance, doc).getCurrent() === undefined,
|
|
56
|
-
suspender: (instance, doc:
|
|
57
|
+
suspender: (instance, doc: DocumentHandle) => resolveDocument(instance, doc),
|
|
58
|
+
getConfig: identity,
|
|
57
59
|
})
|
|
58
60
|
|
|
59
61
|
/**
|
|
60
62
|
* @public
|
|
61
63
|
* @function
|
|
62
64
|
*/
|
|
63
|
-
export const useDocumentSyncStatus: UseDocumentSyncStatus = (
|
|
65
|
+
export const useDocumentSyncStatus: UseDocumentSyncStatus = (
|
|
66
|
+
options: DocumentOptions<string | undefined>,
|
|
67
|
+
) => {
|
|
64
68
|
const normalizedOptions = useNormalizedResourceOptions(options)
|
|
65
69
|
return useDocumentSyncStatusValue(normalizedOptions)
|
|
66
70
|
}
|
|
@@ -39,12 +39,11 @@ const doc = {
|
|
|
39
39
|
const docHandle = createDocumentHandle({
|
|
40
40
|
documentId: 'doc1',
|
|
41
41
|
documentType: 'book',
|
|
42
|
-
resource: {projectId: 'test-project', dataset: 'test-dataset'},
|
|
43
42
|
})
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
resource: {projectId: 'test
|
|
43
|
+
|
|
44
|
+
const normalizedDoc = {
|
|
45
|
+
...docHandle,
|
|
46
|
+
resource: {projectId: 'test', dataset: 'test'},
|
|
48
47
|
}
|
|
49
48
|
|
|
50
49
|
// Define a single generic TestDocument type
|
|
@@ -55,6 +54,16 @@ interface Book extends SanityDocument {
|
|
|
55
54
|
title?: string
|
|
56
55
|
}
|
|
57
56
|
|
|
57
|
+
// Scope the TestDocument type to the project/datasets used in tests
|
|
58
|
+
type AllTestSchemaTypes = Book
|
|
59
|
+
|
|
60
|
+
// Augment the 'groq' module
|
|
61
|
+
declare module 'groq' {
|
|
62
|
+
interface SanitySchemas {
|
|
63
|
+
'default:default': AllTestSchemaTypes
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
58
67
|
describe('useEditDocument hook', () => {
|
|
59
68
|
beforeEach(() => {
|
|
60
69
|
vi.clearAllMocks()
|
|
@@ -73,8 +82,8 @@ describe('useEditDocument hook', () => {
|
|
|
73
82
|
|
|
74
83
|
const {result} = renderHook(() => useEditDocument<string>({...docHandle, path: 'foo'}))
|
|
75
84
|
const promise = result.current('newValue')
|
|
76
|
-
expect(editDocument).toHaveBeenCalledWith(
|
|
77
|
-
expect(apply).toHaveBeenCalledWith(editDocument(
|
|
85
|
+
expect(editDocument).toHaveBeenCalledWith(normalizedDoc, {set: {foo: 'newValue'}})
|
|
86
|
+
expect(apply).toHaveBeenCalledWith(editDocument(normalizedDoc, {set: {foo: 'newValue'}}))
|
|
78
87
|
const actionsResult = await promise
|
|
79
88
|
expect(actionsResult).toEqual({transactionId: 'tx1'})
|
|
80
89
|
})
|
|
@@ -94,7 +103,7 @@ describe('useEditDocument hook', () => {
|
|
|
94
103
|
|
|
95
104
|
const {result} = renderHook(() => useEditDocument(docHandle))
|
|
96
105
|
const promise = result.current({...doc, foo: 'baz', extra: 'old', _id: 'doc1'})
|
|
97
|
-
expect(apply).toHaveBeenCalledWith([editDocument(
|
|
106
|
+
expect(apply).toHaveBeenCalledWith([editDocument(normalizedDoc, {set: {foo: 'baz'}})])
|
|
98
107
|
const actionsResult = await promise
|
|
99
108
|
expect(actionsResult).toEqual({transactionId: 'tx2'})
|
|
100
109
|
})
|
|
@@ -112,10 +121,8 @@ describe('useEditDocument hook', () => {
|
|
|
112
121
|
|
|
113
122
|
const {result} = renderHook(() => useEditDocument<string>({...docHandle, path: 'foo'}))
|
|
114
123
|
const promise = result.current((prev: unknown) => `${prev}Updated`) // 'bar' becomes 'barUpdated'
|
|
115
|
-
expect(editDocument).toHaveBeenCalledWith(
|
|
116
|
-
expect(apply).toHaveBeenCalledWith(
|
|
117
|
-
editDocument(normalizedDocHandle, {set: {foo: 'barUpdated'}}),
|
|
118
|
-
)
|
|
124
|
+
expect(editDocument).toHaveBeenCalledWith(normalizedDoc, {set: {foo: 'barUpdated'}})
|
|
125
|
+
expect(apply).toHaveBeenCalledWith(editDocument(normalizedDoc, {set: {foo: 'barUpdated'}}))
|
|
119
126
|
const actionsResult = await promise
|
|
120
127
|
expect(actionsResult).toEqual({transactionId: 'tx3'})
|
|
121
128
|
})
|
|
@@ -133,8 +140,8 @@ describe('useEditDocument hook', () => {
|
|
|
133
140
|
vi.mocked(useApplyDocumentActions).mockReturnValue(apply)
|
|
134
141
|
|
|
135
142
|
const {result} = renderHook(() => useEditDocument(docHandle))
|
|
136
|
-
const promise = result.current((prevDoc:
|
|
137
|
-
expect(apply).toHaveBeenCalledWith([editDocument(
|
|
143
|
+
const promise = result.current((prevDoc: Book) => ({...prevDoc, foo: 'baz'}))
|
|
144
|
+
expect(apply).toHaveBeenCalledWith([editDocument(normalizedDoc, {set: {foo: 'baz'}})])
|
|
138
145
|
const actionsResult = await promise
|
|
139
146
|
expect(actionsResult).toEqual({transactionId: 'tx4'})
|
|
140
147
|
})
|
|
@@ -1,44 +1,86 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type ActionsResult,
|
|
3
|
+
type DocumentOptions,
|
|
4
|
+
editDocument,
|
|
5
|
+
getDocumentState,
|
|
6
|
+
type JsonMatch,
|
|
7
|
+
resolveDocument,
|
|
8
|
+
} from '@sanity/sdk'
|
|
9
|
+
import {type SanityDocument} from 'groq'
|
|
2
10
|
import {useCallback} from 'react'
|
|
3
11
|
|
|
4
|
-
import {type DocumentHandle} from '../../config/handles'
|
|
5
12
|
import {useSanityInstance} from '../context/useSanityInstance'
|
|
6
13
|
import {useNormalizedResourceOptions} from '../helpers/useNormalizedResourceOptions'
|
|
14
|
+
import {trackHookUsage} from '../helpers/useTrackHookUsage'
|
|
7
15
|
import {useApplyDocumentActions} from './useApplyDocumentActions'
|
|
8
16
|
|
|
9
17
|
const ignoredKeys = ['_id', '_type', '_createdAt', '_updatedAt', '_rev']
|
|
10
18
|
|
|
11
19
|
type Updater<TValue> = TValue | ((currentValue: TValue) => TValue)
|
|
12
20
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
21
|
+
// Overload 1: No path, relies on Typegen
|
|
22
|
+
/**
|
|
23
|
+
* @public
|
|
24
|
+
* Edit an entire document, relying on Typegen for the type.
|
|
25
|
+
*
|
|
26
|
+
* @param options - Document options including `documentId`, `documentType`, and optionally `projectId`/`dataset`.
|
|
27
|
+
* @returns A stable function to update the document state. Accepts either the new document state or an updater function `(currentValue) => nextValue`.
|
|
28
|
+
* Returns a promise resolving to the {@link ActionsResult}.
|
|
29
|
+
*/
|
|
30
|
+
export function useEditDocument<
|
|
31
|
+
TDocumentType extends string = string,
|
|
32
|
+
TDataset extends string = string,
|
|
33
|
+
TProjectId extends string = string,
|
|
34
|
+
>(
|
|
35
|
+
options: DocumentOptions<undefined, TDocumentType, TDataset, TProjectId>,
|
|
36
|
+
): (
|
|
37
|
+
nextValue: Updater<SanityDocument<TDocumentType, `${TProjectId}.${TDataset}`>>,
|
|
38
|
+
) => Promise<ActionsResult<SanityDocument<TDocumentType, `${TProjectId}.${TDataset}`>>>
|
|
39
|
+
|
|
40
|
+
// Overload 2: Path provided, relies on Typegen
|
|
41
|
+
/**
|
|
42
|
+
* @public
|
|
43
|
+
* Edit a specific path within a document, relying on Typegen for the type.
|
|
44
|
+
*
|
|
45
|
+
* @param options - Document options including `documentId`, `documentType`, `path`, and optionally `projectId`/`dataset`.
|
|
46
|
+
* @returns A stable function to update the value at the specified path. Accepts either the new value or an updater function `(currentValue) => nextValue`.
|
|
47
|
+
* Returns a promise resolving to the {@link ActionsResult}.
|
|
48
|
+
*/
|
|
49
|
+
export function useEditDocument<
|
|
50
|
+
TPath extends string = string,
|
|
51
|
+
TDocumentType extends string = string,
|
|
52
|
+
TDataset extends string = string,
|
|
53
|
+
TProjectId extends string = string,
|
|
54
|
+
>(
|
|
55
|
+
options: DocumentOptions<TPath, TDocumentType, TDataset, TProjectId>,
|
|
56
|
+
): (
|
|
57
|
+
nextValue: Updater<JsonMatch<SanityDocument<TDocumentType, `${TProjectId}.${TDataset}`>, TPath>>,
|
|
58
|
+
) => Promise<ActionsResult<SanityDocument<TDocumentType, `${TProjectId}.${TDataset}`>>>
|
|
17
59
|
|
|
18
|
-
// Overload
|
|
60
|
+
// Overload 3: Explicit type, no path
|
|
19
61
|
/**
|
|
20
62
|
* @public
|
|
21
63
|
* Edit an entire document with an explicit type `TData`.
|
|
22
64
|
*
|
|
23
|
-
* @param options - Document options including `documentId` and optionally `
|
|
65
|
+
* @param options - Document options including `documentId` and optionally `projectId`/`dataset`.
|
|
24
66
|
* @returns A stable function to update the document state. Accepts either the new document state (`TData`) or an updater function `(currentValue: TData) => nextValue: TData`.
|
|
25
67
|
* Returns a promise resolving to the {@link ActionsResult}.
|
|
26
68
|
*/
|
|
27
69
|
export function useEditDocument<TData>(
|
|
28
|
-
options:
|
|
70
|
+
options: DocumentOptions<undefined>,
|
|
29
71
|
): (nextValue: Updater<TData>) => Promise<ActionsResult>
|
|
30
72
|
|
|
31
|
-
// Overload
|
|
73
|
+
// Overload 4: Explicit type, path provided
|
|
32
74
|
/**
|
|
33
75
|
* @public
|
|
34
76
|
* Edit a specific path within a document with an explicit type `TData`.
|
|
35
77
|
*
|
|
36
|
-
* @param options - Document options including `documentId`, `path`, and optionally `
|
|
78
|
+
* @param options - Document options including `documentId`, `path`, and optionally `projectId`/`dataset`.
|
|
37
79
|
* @returns A stable function to update the value at the specified path. Accepts either the new value (`TData`) or an updater function `(currentValue: TData) => nextValue: TData`.
|
|
38
80
|
* Returns a promise resolving to the {@link ActionsResult}.
|
|
39
81
|
*/
|
|
40
82
|
export function useEditDocument<TData>(
|
|
41
|
-
options:
|
|
83
|
+
options: DocumentOptions<string>,
|
|
42
84
|
): (nextValue: Updater<TData>) => Promise<ActionsResult>
|
|
43
85
|
|
|
44
86
|
/**
|
|
@@ -54,9 +96,11 @@ export function useEditDocument<TData>(
|
|
|
54
96
|
* - Integrating with the active {@link SanityInstance} context.
|
|
55
97
|
* - Utilizing `useApplyDocumentActions` internally for optimistic updates and transaction handling.
|
|
56
98
|
*
|
|
57
|
-
* It offers overloads for flexibility:
|
|
58
|
-
* 1. **
|
|
59
|
-
* 2. **
|
|
99
|
+
* It offers several overloads for flexibility:
|
|
100
|
+
* 1. **Typegen (Full Document):** Edit the entire document, inferring types from your schema.
|
|
101
|
+
* 2. **Typegen (Specific Path):** Edit a specific field, inferring types.
|
|
102
|
+
* 3. **Explicit Type (Full Document):** Edit the entire document with a manually specified type.
|
|
103
|
+
* 4. **Explicit Type (Specific Path):** Edit a specific field with a manually specified type.
|
|
60
104
|
*
|
|
61
105
|
* **LiveEdit Documents:**
|
|
62
106
|
* For documents using {@link DocumentHandle.liveEdit | liveEdit mode} (set via `liveEdit: true` in the document handle), edits are applied directly to the published document without creating a draft.
|
|
@@ -64,7 +108,87 @@ export function useEditDocument<TData>(
|
|
|
64
108
|
* This hook relies on the document state being loaded. If the document is not yet available
|
|
65
109
|
* (e.g., during initial load), the component using this hook will suspend.
|
|
66
110
|
*
|
|
67
|
-
* @example Basic Usage
|
|
111
|
+
* @example Basic Usage (Typegen, Full Document)
|
|
112
|
+
* ```tsx
|
|
113
|
+
* import {useCallback} from 'react';
|
|
114
|
+
* import {useEditDocument, useDocument, type DocumentHandle} from '@sanity/sdk-react'
|
|
115
|
+
*
|
|
116
|
+
* // Assume 'product' schema has a 'title' field (string)
|
|
117
|
+
* interface ProductEditorProps {
|
|
118
|
+
* productHandle: DocumentHandle<'product'> // Typegen infers 'product' type
|
|
119
|
+
* }
|
|
120
|
+
*
|
|
121
|
+
* function ProductEditor({ productHandle }: ProductEditorProps) {
|
|
122
|
+
* // Fetch the document to display its current state (optional)
|
|
123
|
+
* const {data: product} = useDocument(productHandle);
|
|
124
|
+
* // Get the edit function for the full document
|
|
125
|
+
* const editProduct = useEditDocument(productHandle);
|
|
126
|
+
*
|
|
127
|
+
* // Use useCallback for stable event handlers
|
|
128
|
+
* const handleTitleChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
|
|
129
|
+
* const newTitle = event.target.value;
|
|
130
|
+
* // Use the functional updater for safe partial updates
|
|
131
|
+
* editProduct(prev => ({
|
|
132
|
+
* ...prev,
|
|
133
|
+
* title: newTitle,
|
|
134
|
+
* })).
|
|
135
|
+
* }, [editProduct]);
|
|
136
|
+
*
|
|
137
|
+
* return (
|
|
138
|
+
* <div>
|
|
139
|
+
* <label>
|
|
140
|
+
* Product Title:
|
|
141
|
+
* <input
|
|
142
|
+
* type="text"
|
|
143
|
+
* value={product?.title ?? ''}
|
|
144
|
+
* onChange={handleTitleChange}
|
|
145
|
+
* />
|
|
146
|
+
* </label>
|
|
147
|
+
* </div>
|
|
148
|
+
* );
|
|
149
|
+
* }
|
|
150
|
+
* ```
|
|
151
|
+
*
|
|
152
|
+
* @example Editing a Specific Path (Typegen)
|
|
153
|
+
* ```tsx
|
|
154
|
+
* import React, { useCallback } from 'react';
|
|
155
|
+
* import {useEditDocument, useDocument, type DocumentHandle, type DocumentOptions} from '@sanity/sdk-react'
|
|
156
|
+
*
|
|
157
|
+
* // Assume 'product' schema has a 'price' field (number)
|
|
158
|
+
* interface ProductPriceEditorProps {
|
|
159
|
+
* productHandle: DocumentHandle<'product'>;
|
|
160
|
+
* }
|
|
161
|
+
*
|
|
162
|
+
* function ProductPriceEditor({ productHandle }: ProductPriceEditorProps) {
|
|
163
|
+
* // Construct DocumentOptions internally, combining the handle and a hardcoded path
|
|
164
|
+
* const priceOptions {
|
|
165
|
+
* ...productHandle,
|
|
166
|
+
* path: 'price', // Hardcode the path to edit
|
|
167
|
+
* };
|
|
168
|
+
*
|
|
169
|
+
* // Fetch the current price to display it
|
|
170
|
+
* const {data: currentPrice} = useDocument(priceOptions);
|
|
171
|
+
* // Get the edit function for the specific path 'price'
|
|
172
|
+
* const editPrice = useEditDocument(priceOptions);
|
|
173
|
+
*
|
|
174
|
+
* const handleSetFixedPrice = useCallback(() => {
|
|
175
|
+
* // Update the price directly to a hardcoded value
|
|
176
|
+
* editPrice(99.99)
|
|
177
|
+
* }, [editPrice]);
|
|
178
|
+
*
|
|
179
|
+
* return (
|
|
180
|
+
* <div>
|
|
181
|
+
* <p>Current Price: {currentPrice}</p>
|
|
182
|
+
* <button onClick={handleSetFixedPrice}>
|
|
183
|
+
* Set Price to $99.99
|
|
184
|
+
* </button>
|
|
185
|
+
* </div>
|
|
186
|
+
* );
|
|
187
|
+
* }
|
|
188
|
+
*
|
|
189
|
+
* ```
|
|
190
|
+
*
|
|
191
|
+
* @example Usage with Explicit Types (Full Document)
|
|
68
192
|
* ```tsx
|
|
69
193
|
* import React, { useCallback } from 'react';
|
|
70
194
|
* import {useEditDocument, useDocument, type DocumentHandle, type SanityDocument} from '@sanity/sdk-react'
|
|
@@ -136,12 +260,34 @@ export function useEditDocument<TData>(
|
|
|
136
260
|
* }
|
|
137
261
|
*
|
|
138
262
|
* ```
|
|
263
|
+
*
|
|
264
|
+
* @example Edit a document in a release
|
|
265
|
+
* ```tsx
|
|
266
|
+
* import {useEditDocument} from '@sanity/sdk-react'
|
|
267
|
+
*
|
|
268
|
+
* function EditArticleInRelease({documentId}: {documentId: string}) {
|
|
269
|
+
* // Use the document's plain ID — not `versions.<releaseName>.<id>`.
|
|
270
|
+
* // The document must already exist in the release (added via `createDocument` first).
|
|
271
|
+
* const editArticle = useEditDocument({
|
|
272
|
+
* documentId,
|
|
273
|
+
* documentType: 'article',
|
|
274
|
+
* perspective: {releaseName: 'summer-drop'},
|
|
275
|
+
* })
|
|
276
|
+
*
|
|
277
|
+
* return (
|
|
278
|
+
* <button onClick={() => editArticle(prev => ({...prev, title: 'Updated for release'}))}>
|
|
279
|
+
* Edit in Release
|
|
280
|
+
* </button>
|
|
281
|
+
* )
|
|
282
|
+
* }
|
|
283
|
+
* ```
|
|
139
284
|
*/
|
|
140
285
|
export function useEditDocument({
|
|
141
286
|
path,
|
|
142
287
|
...doc
|
|
143
|
-
}:
|
|
288
|
+
}: DocumentOptions<string | undefined>): (updater: Updater<unknown>) => Promise<ActionsResult> {
|
|
144
289
|
const instance = useSanityInstance()
|
|
290
|
+
trackHookUsage(instance, 'useEditDocument')
|
|
145
291
|
const normalizedDoc = useNormalizedResourceOptions(doc)
|
|
146
292
|
|
|
147
293
|
const apply = useApplyDocumentActions()
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {act, renderHook} from '@testing-library/react'
|
|
2
2
|
import {evaluateSync, parse, toJS} from 'groq-js'
|
|
3
3
|
import {describe, vi} from 'vitest'
|
|
4
4
|
|
|
5
|
-
import {act, renderHook} from '../../../test/test-utils'
|
|
6
5
|
import {ResourceProvider} from '../../context/ResourceProvider'
|
|
7
|
-
import {ResourcesContext} from '../../context/ResourcesContext'
|
|
8
6
|
import {useQuery} from '../query/useQuery'
|
|
9
7
|
import {useDocuments} from './useDocuments'
|
|
10
8
|
|
|
@@ -79,13 +77,25 @@ describe('useDocuments', () => {
|
|
|
79
77
|
|
|
80
78
|
it('should respect custom page size', () => {
|
|
81
79
|
const customBatchSize = 2
|
|
82
|
-
const {result} = renderHook(() => useDocuments({batchSize: customBatchSize})
|
|
80
|
+
const {result} = renderHook(() => useDocuments({batchSize: customBatchSize}), {
|
|
81
|
+
wrapper: ({children}) => (
|
|
82
|
+
<ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
|
|
83
|
+
{children}
|
|
84
|
+
</ResourceProvider>
|
|
85
|
+
),
|
|
86
|
+
})
|
|
83
87
|
|
|
84
88
|
expect(result.current.data.length).toBe(customBatchSize)
|
|
85
89
|
})
|
|
86
90
|
|
|
87
91
|
it('should filter by document type', () => {
|
|
88
|
-
const {result} = renderHook(() => useDocuments({filter: '_type == "movie"'})
|
|
92
|
+
const {result} = renderHook(() => useDocuments({filter: '_type == "movie"'}), {
|
|
93
|
+
wrapper: ({children}) => (
|
|
94
|
+
<ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
|
|
95
|
+
{children}
|
|
96
|
+
</ResourceProvider>
|
|
97
|
+
),
|
|
98
|
+
})
|
|
89
99
|
|
|
90
100
|
expect(result.current.data.every((doc) => doc.documentType === 'movie')).toBe(true)
|
|
91
101
|
expect(result.current.count).toBe(5) // 5 movies in the dataset
|
|
@@ -93,18 +103,32 @@ describe('useDocuments', () => {
|
|
|
93
103
|
|
|
94
104
|
// groq-js doesn't support search filters yet
|
|
95
105
|
it.skip('should apply search filter', () => {
|
|
96
|
-
const {result} = renderHook(() => useDocuments({search: 'inter'})
|
|
106
|
+
const {result} = renderHook(() => useDocuments({search: 'inter'}), {
|
|
107
|
+
wrapper: ({children}) => (
|
|
108
|
+
<ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
|
|
109
|
+
{children}
|
|
110
|
+
</ResourceProvider>
|
|
111
|
+
),
|
|
112
|
+
})
|
|
97
113
|
|
|
98
114
|
// Should match "Interstellar"
|
|
99
115
|
expect(result.current.data.some((doc) => doc.documentId === 'movie3')).toBe(true)
|
|
100
116
|
})
|
|
101
117
|
|
|
102
118
|
it('should apply ordering', () => {
|
|
103
|
-
const {result} = renderHook(
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
119
|
+
const {result} = renderHook(
|
|
120
|
+
() =>
|
|
121
|
+
useDocuments({
|
|
122
|
+
filter: '_type == "movie"',
|
|
123
|
+
orderings: [{field: 'releaseYear', direction: 'desc'}],
|
|
124
|
+
}),
|
|
125
|
+
{
|
|
126
|
+
wrapper: ({children}) => (
|
|
127
|
+
<ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
|
|
128
|
+
{children}
|
|
129
|
+
</ResourceProvider>
|
|
130
|
+
),
|
|
131
|
+
},
|
|
108
132
|
)
|
|
109
133
|
|
|
110
134
|
// First item should be the most recent movie (Interstellar, 2014)
|
|
@@ -113,7 +137,13 @@ describe('useDocuments', () => {
|
|
|
113
137
|
|
|
114
138
|
it('should load more data when loadMore is called', () => {
|
|
115
139
|
const batchSize = 2
|
|
116
|
-
const {result} = renderHook(() => useDocuments({batchSize: batchSize})
|
|
140
|
+
const {result} = renderHook(() => useDocuments({batchSize: batchSize}), {
|
|
141
|
+
wrapper: ({children}) => (
|
|
142
|
+
<ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
|
|
143
|
+
{children}
|
|
144
|
+
</ResourceProvider>
|
|
145
|
+
),
|
|
146
|
+
})
|
|
117
147
|
|
|
118
148
|
expect(result.current.data.length).toBe(batchSize)
|
|
119
149
|
|
|
@@ -125,7 +155,13 @@ describe('useDocuments', () => {
|
|
|
125
155
|
})
|
|
126
156
|
|
|
127
157
|
it('should indicate when there is more data to load', () => {
|
|
128
|
-
const {result} = renderHook(() => useDocuments({batchSize: 3})
|
|
158
|
+
const {result} = renderHook(() => useDocuments({batchSize: 3}), {
|
|
159
|
+
wrapper: ({children}) => (
|
|
160
|
+
<ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
|
|
161
|
+
{children}
|
|
162
|
+
</ResourceProvider>
|
|
163
|
+
),
|
|
164
|
+
})
|
|
129
165
|
expect(result.current.hasMore).toBe(true)
|
|
130
166
|
// Load all remaining data
|
|
131
167
|
act(() => {
|
|
@@ -138,6 +174,11 @@ describe('useDocuments', () => {
|
|
|
138
174
|
it('should reset limit when filter changes', () => {
|
|
139
175
|
const {result, rerender} = renderHook((props) => useDocuments(props), {
|
|
140
176
|
initialProps: {batchSize: 2, filter: ''},
|
|
177
|
+
wrapper: ({children}) => (
|
|
178
|
+
<ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
|
|
179
|
+
{children}
|
|
180
|
+
</ResourceProvider>
|
|
181
|
+
),
|
|
141
182
|
})
|
|
142
183
|
// Initially, data length equals pageSize (2)
|
|
143
184
|
expect(result.current.data.length).toBe(2)
|
|
@@ -153,44 +194,23 @@ describe('useDocuments', () => {
|
|
|
153
194
|
expect(result.current.data.length).toBe(2)
|
|
154
195
|
})
|
|
155
196
|
|
|
156
|
-
it('should add
|
|
157
|
-
const {result} = renderHook(() => useDocuments({})
|
|
158
|
-
|
|
159
|
-
// Check that the first document handle has the projectId and dataset
|
|
160
|
-
expect((result.current.data[0].resource as DatasetResource).projectId).toBe('test')
|
|
161
|
-
expect((result.current.data[0].resource as DatasetResource).dataset).toBe('test')
|
|
162
|
-
|
|
163
|
-
// Verify all document handles have these properties
|
|
164
|
-
expect(
|
|
165
|
-
result.current.data.every(
|
|
166
|
-
(doc) =>
|
|
167
|
-
(doc.resource as DatasetResource).projectId === 'test' &&
|
|
168
|
-
(doc.resource as DatasetResource).dataset === 'test',
|
|
169
|
-
),
|
|
170
|
-
).toBe(true)
|
|
171
|
-
})
|
|
172
|
-
|
|
173
|
-
it('should resolve resourceName to the named dataset resource', () => {
|
|
174
|
-
const resources = {
|
|
175
|
-
default: {projectId: 'test-project', dataset: 'test-dataset'},
|
|
176
|
-
secondary: {projectId: 'secondary-project', dataset: 'secondary-dataset'},
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
const {result} = renderHook(() => useDocuments({resourceName: 'secondary'}), {
|
|
197
|
+
it('should add projectId and dataset to document handles', () => {
|
|
198
|
+
const {result} = renderHook(() => useDocuments({}), {
|
|
180
199
|
wrapper: ({children}) => (
|
|
181
|
-
<ResourceProvider
|
|
182
|
-
|
|
200
|
+
<ResourceProvider projectId="test-project" dataset="test-dataset" fallback={null}>
|
|
201
|
+
{children}
|
|
183
202
|
</ResourceProvider>
|
|
184
203
|
),
|
|
185
204
|
})
|
|
186
205
|
|
|
187
|
-
|
|
188
|
-
expect(
|
|
206
|
+
// Check that the first document handle has the projectId and dataset
|
|
207
|
+
expect(result.current.data[0].projectId).toBe('test-project')
|
|
208
|
+
expect(result.current.data[0].dataset).toBe('test-dataset')
|
|
209
|
+
|
|
210
|
+
// Verify all document handles have these properties
|
|
189
211
|
expect(
|
|
190
212
|
result.current.data.every(
|
|
191
|
-
(doc) =>
|
|
192
|
-
(doc.resource as DatasetResource).projectId === 'secondary-project' &&
|
|
193
|
-
(doc.resource as DatasetResource).dataset === 'secondary-dataset',
|
|
213
|
+
(doc) => doc.projectId === 'test-project' && doc.dataset === 'test-dataset',
|
|
194
214
|
),
|
|
195
215
|
).toBe(true)
|
|
196
216
|
})
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {type DocumentHandle, isDatasetResource, type QueryOptions} from '@sanity/sdk'
|
|
2
|
+
import {createGroqSearchFilter, pickProperties} from '@sanity/sdk/_internal'
|
|
2
3
|
import {type SortOrderingItem} from '@sanity/types'
|
|
3
|
-
import {
|
|
4
|
-
import {useCallback, useEffect, useMemo, useState} from 'react'
|
|
4
|
+
import {useCallback, useMemo, useState} from 'react'
|
|
5
5
|
|
|
6
|
-
import {type
|
|
6
|
+
import {type ResourceHandle} from '../../config/handles'
|
|
7
7
|
import {useNormalizedResourceOptions} from '../helpers/useNormalizedResourceOptions'
|
|
8
|
+
import {useTrackHookUsage} from '../helpers/useTrackHookUsage'
|
|
8
9
|
import {useQuery} from '../query/useQuery'
|
|
9
10
|
|
|
10
11
|
const DEFAULT_BATCH_SIZE = 25
|
|
@@ -20,9 +21,7 @@ export interface DocumentsOptions<
|
|
|
20
21
|
TDataset extends string = string,
|
|
21
22
|
TProjectId extends string = string,
|
|
22
23
|
>
|
|
23
|
-
extends
|
|
24
|
-
ResourceHandle<TProjectId, TDataset>,
|
|
25
|
-
Pick<QueryOptions<TDocumentType, TDataset, TProjectId>, 'params'> {
|
|
24
|
+
extends ResourceHandle<TDataset, TProjectId>, Pick<QueryOptions, 'perspective' | 'params'> {
|
|
26
25
|
/**
|
|
27
26
|
* Filter documents by their `_type`. Can be a single type or an array of types.
|
|
28
27
|
*/
|
|
@@ -90,16 +89,18 @@ export interface DocumentsResponse<
|
|
|
90
89
|
* @returns An object containing the list of document handles, the loading state, the total count of retrieved document handles, and a function to load more
|
|
91
90
|
*
|
|
92
91
|
* @remarks
|
|
93
|
-
* - The returned document handles include
|
|
92
|
+
* - The returned document handles include projectId and dataset information from the current Sanity instance
|
|
94
93
|
* - This makes them ready to use with document operations and other document hooks
|
|
95
|
-
* - The hook automatically uses the correct Sanity instance based on the
|
|
94
|
+
* - The hook automatically uses the correct Sanity instance based on the projectId and dataset in the options
|
|
96
95
|
*
|
|
97
96
|
* @example Basic infinite list with loading more
|
|
98
97
|
* ```tsx
|
|
99
98
|
* import {
|
|
100
99
|
* useDocuments,
|
|
100
|
+
* createDatasetHandle,
|
|
101
|
+
* type DatasetHandle,
|
|
101
102
|
* type DocumentHandle,
|
|
102
|
-
* type
|
|
103
|
+
* type SortOrderingItem
|
|
103
104
|
* } from '@sanity/sdk-react'
|
|
104
105
|
* import {Suspense} from 'react'
|
|
105
106
|
*
|
|
@@ -115,14 +116,14 @@ export interface DocumentsResponse<
|
|
|
115
116
|
*
|
|
116
117
|
* // Define props for the list component
|
|
117
118
|
* interface DocumentListProps {
|
|
118
|
-
*
|
|
119
|
+
* dataset: DatasetHandle
|
|
119
120
|
* documentType: string
|
|
120
121
|
* search?: string
|
|
121
122
|
* }
|
|
122
123
|
*
|
|
123
|
-
* function DocumentList({
|
|
124
|
+
* function DocumentList({dataset, documentType, search}: DocumentListProps) {
|
|
124
125
|
* const { data, hasMore, isPending, loadMore, count } = useDocuments({
|
|
125
|
-
*
|
|
126
|
+
* ...dataset,
|
|
126
127
|
* documentType,
|
|
127
128
|
* search,
|
|
128
129
|
* batchSize: 10,
|
|
@@ -136,7 +137,7 @@ export interface DocumentsResponse<
|
|
|
136
137
|
* {data.map((docHandle) => (
|
|
137
138
|
* <li key={docHandle.documentId}>
|
|
138
139
|
* <Suspense fallback="Loading…">
|
|
139
|
-
* <MyDocumentComponent
|
|
140
|
+
* <MyDocumentComponent docHandle={docHandle} />
|
|
140
141
|
* </Suspense>
|
|
141
142
|
* </li>
|
|
142
143
|
* ))}
|
|
@@ -151,7 +152,8 @@ export interface DocumentsResponse<
|
|
|
151
152
|
* }
|
|
152
153
|
*
|
|
153
154
|
* // Usage:
|
|
154
|
-
* //
|
|
155
|
+
* // const myDatasetHandle = createDatasetHandle({ projectId: 'p1', dataset: 'production' })
|
|
156
|
+
* // <DocumentList dataset={myDatasetHandle} documentType="post" search="Sanity" />
|
|
155
157
|
* ```
|
|
156
158
|
*
|
|
157
159
|
* @example Using `filter` and `params` options for narrowing a collection
|
|
@@ -202,8 +204,8 @@ export function useDocuments<
|
|
|
202
204
|
TDataset,
|
|
203
205
|
TProjectId
|
|
204
206
|
> {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
+
useTrackHookUsage('useDocuments')
|
|
208
|
+
const options = useNormalizedResourceOptions(rawOptions)
|
|
207
209
|
const [limit, setLimit] = useState(batchSize)
|
|
208
210
|
const documentTypes = useMemo(
|
|
209
211
|
() =>
|
|
@@ -224,9 +226,11 @@ export function useDocuments<
|
|
|
224
226
|
types: documentTypes,
|
|
225
227
|
...options,
|
|
226
228
|
})
|
|
227
|
-
|
|
229
|
+
const [prevKey, setPrevKey] = useState(key)
|
|
230
|
+
if (prevKey !== key) {
|
|
231
|
+
setPrevKey(key)
|
|
228
232
|
setLimit(batchSize)
|
|
229
|
-
}
|
|
233
|
+
}
|
|
230
234
|
|
|
231
235
|
const filterClause = useMemo(() => {
|
|
232
236
|
const conditions: string[] = []
|
|
@@ -276,7 +280,14 @@ export function useDocuments<
|
|
|
276
280
|
params: {
|
|
277
281
|
...params,
|
|
278
282
|
// these are passed back to the user as part of each document handle
|
|
279
|
-
__handle:
|
|
283
|
+
__handle: {
|
|
284
|
+
// keep projectId/dataset for backward compat until v4; resource is added
|
|
285
|
+
// intentionally so that hook consumers can resolve the correct resource
|
|
286
|
+
...(options.resource && isDatasetResource(options.resource)
|
|
287
|
+
? pickProperties(options.resource, ['projectId', 'dataset'])
|
|
288
|
+
: {}),
|
|
289
|
+
...pickProperties(options, ['perspective', 'resource']),
|
|
290
|
+
},
|
|
280
291
|
__types: documentTypes,
|
|
281
292
|
},
|
|
282
293
|
})
|