@sanity/sdk-react 2.8.0 → 3.0.0-rc.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/README.md +125 -63
- package/dist/index.d.ts +381 -571
- package/dist/index.js +435 -366
- package/dist/index.js.map +1 -1
- package/package.json +7 -9
- package/src/_exports/index.ts +4 -0
- package/src/_exports/sdk-react.ts +16 -0
- package/src/components/SDKProvider.test.tsx +23 -58
- package/src/components/SDKProvider.tsx +38 -30
- package/src/components/SanityApp.test.tsx +12 -68
- package/src/components/SanityApp.tsx +88 -65
- package/src/components/auth/AuthBoundary.test.tsx +8 -26
- package/src/components/auth/LoginError.tsx +5 -5
- package/src/config/handles.ts +53 -0
- package/src/context/ComlinkTokenRefresh.test.tsx +27 -10
- package/src/context/DefaultResourceContext.ts +10 -0
- package/src/context/PerspectiveContext.ts +12 -0
- package/src/context/ResourceProvider.test.tsx +99 -19
- package/src/context/ResourceProvider.tsx +103 -37
- package/src/context/ResourcesContext.tsx +7 -0
- package/src/context/SDKStudioContext.test.tsx +33 -28
- package/src/context/SDKStudioContext.ts +6 -0
- package/src/context/renderSanityApp.test.tsx +49 -151
- package/src/context/renderSanityApp.tsx +8 -12
- package/src/hooks/agent/agentActions.test.tsx +1 -1
- package/src/hooks/agent/agentActions.ts +56 -19
- package/src/hooks/auth/useDashboardOrganizationId.test.tsx +8 -2
- package/src/hooks/auth/useVerifyOrgProjects.test.tsx +32 -8
- package/src/hooks/client/useClient.test.tsx +4 -1
- package/src/hooks/client/useClient.ts +0 -1
- package/src/hooks/context/useDefaultResource.test.tsx +25 -0
- package/src/hooks/context/useDefaultResource.ts +30 -0
- package/src/hooks/context/useSanityInstance.test.tsx +2 -140
- package/src/hooks/context/useSanityInstance.ts +9 -53
- package/src/hooks/dashboard/useDispatchIntent.test.ts +24 -15
- package/src/hooks/dashboard/useDispatchIntent.ts +7 -7
- package/src/hooks/dashboard/useManageFavorite.test.tsx +34 -94
- package/src/hooks/dashboard/useManageFavorite.ts +16 -10
- package/src/hooks/dashboard/useNavigateToStudioDocument.test.ts +7 -5
- package/src/hooks/dashboard/useNavigateToStudioDocument.ts +6 -2
- package/src/hooks/dashboard/useRecordDocumentHistoryEvent.test.ts +2 -0
- package/src/hooks/dashboard/useRecordDocumentHistoryEvent.ts +2 -1
- package/src/hooks/dashboard/utils/useResourceIdFromDocumentHandle.test.ts +17 -38
- package/src/hooks/dashboard/utils/useResourceIdFromDocumentHandle.ts +12 -19
- package/src/hooks/datasets/useDatasets.test.ts +8 -22
- package/src/hooks/datasets/useDatasets.ts +8 -16
- package/src/hooks/document/useApplyDocumentActions.test.ts +98 -52
- package/src/hooks/document/useApplyDocumentActions.ts +35 -37
- package/src/hooks/document/useDocument.test.tsx +8 -37
- package/src/hooks/document/useDocument.ts +78 -129
- package/src/hooks/document/useDocumentEvent.test.tsx +7 -19
- package/src/hooks/document/useDocumentEvent.ts +21 -19
- package/src/hooks/document/useDocumentPermissions.test.tsx +75 -84
- package/src/hooks/document/useDocumentPermissions.ts +41 -28
- package/src/hooks/document/useDocumentSyncStatus.test.ts +13 -3
- package/src/hooks/document/useDocumentSyncStatus.ts +19 -14
- package/src/hooks/document/useEditDocument.test.tsx +28 -70
- package/src/hooks/document/useEditDocument.ts +29 -149
- package/src/hooks/documents/useDocuments.test.tsx +44 -64
- package/src/hooks/documents/useDocuments.ts +19 -25
- package/src/hooks/helpers/createCallbackHook.test.tsx +19 -13
- package/src/hooks/helpers/createStateSourceHook.test.tsx +10 -10
- package/src/hooks/helpers/createStateSourceHook.tsx +2 -4
- package/src/hooks/helpers/useNormalizedResourceOptions.test.ts +65 -0
- package/src/hooks/helpers/useNormalizedResourceOptions.ts +127 -0
- package/src/hooks/paginatedDocuments/usePaginatedDocuments.test.tsx +27 -34
- package/src/hooks/paginatedDocuments/usePaginatedDocuments.ts +19 -20
- package/src/hooks/presence/usePresence.test.tsx +71 -9
- package/src/hooks/presence/usePresence.ts +28 -3
- package/src/hooks/preview/useDocumentPreview.test.tsx +85 -193
- package/src/hooks/preview/useDocumentPreview.tsx +42 -62
- package/src/hooks/projection/useDocumentProjection.test.tsx +9 -37
- package/src/hooks/projection/useDocumentProjection.ts +9 -82
- package/src/hooks/projects/useProject.test.ts +1 -2
- package/src/hooks/projects/useProject.ts +7 -8
- package/src/hooks/query/useQuery.test.tsx +5 -6
- package/src/hooks/query/useQuery.ts +12 -91
- package/src/hooks/releases/useActiveReleases.test.tsx +2 -2
- package/src/hooks/releases/useActiveReleases.ts +25 -13
- package/src/hooks/releases/usePerspective.test.tsx +9 -17
- package/src/hooks/releases/usePerspective.ts +29 -18
- package/src/hooks/users/useUser.test.tsx +9 -3
- package/src/hooks/users/useUser.ts +1 -1
- package/src/hooks/users/useUsers.test.tsx +5 -2
- package/src/hooks/users/useUsers.ts +1 -1
- package/src/context/SourcesContext.tsx +0 -7
- package/src/hooks/helpers/useNormalizedSourceOptions.ts +0 -85
|
@@ -6,7 +6,10 @@ import {useClient} from './useClient'
|
|
|
6
6
|
|
|
7
7
|
describe('useClient', () => {
|
|
8
8
|
const wrapper = ({children}: {children: React.ReactNode}) => (
|
|
9
|
-
<ResourceProvider
|
|
9
|
+
<ResourceProvider
|
|
10
|
+
resource={{projectId: 'test-project', dataset: 'test-dataset'}}
|
|
11
|
+
fallback={null}
|
|
12
|
+
>
|
|
10
13
|
{children}
|
|
11
14
|
</ResourceProvider>
|
|
12
15
|
)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {renderHook} from '@testing-library/react'
|
|
2
|
+
import {describe, expect, it} from 'vitest'
|
|
3
|
+
|
|
4
|
+
import {ResourceContext} from '../../context/DefaultResourceContext'
|
|
5
|
+
import {useResource} from './useDefaultResource'
|
|
6
|
+
|
|
7
|
+
describe('useResource', () => {
|
|
8
|
+
it('returns the resource from context', () => {
|
|
9
|
+
const resource = {projectId: 'my-project', dataset: 'my-dataset'}
|
|
10
|
+
|
|
11
|
+
const {result} = renderHook(() => useResource(), {
|
|
12
|
+
wrapper: ({children}) => (
|
|
13
|
+
<ResourceContext.Provider value={resource}>{children}</ResourceContext.Provider>
|
|
14
|
+
),
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
expect(result.current).toBe(resource)
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it('returns undefined when no resource is in context', () => {
|
|
21
|
+
const {result} = renderHook(() => useResource())
|
|
22
|
+
|
|
23
|
+
expect(result.current).toBeUndefined()
|
|
24
|
+
})
|
|
25
|
+
})
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import {type DocumentResource} from '@sanity/sdk'
|
|
2
|
+
import {useContext} from 'react'
|
|
3
|
+
|
|
4
|
+
import {ResourceContext} from '../../context/DefaultResourceContext'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Returns the current {@link DocumentResource} from context.
|
|
8
|
+
*
|
|
9
|
+
* @public
|
|
10
|
+
*
|
|
11
|
+
* @category Platform
|
|
12
|
+
* @returns The resource set by the nearest `ResourceProvider`, or `undefined`
|
|
13
|
+
*
|
|
14
|
+
* @remarks
|
|
15
|
+
* With the flat instance model, nested `ResourceProvider`s override the
|
|
16
|
+
* active resource via React context rather than creating child instances.
|
|
17
|
+
* Use this hook when you need the current project/dataset/resource for a
|
|
18
|
+
* subtree instead of reading from `useSanityInstance().config`.
|
|
19
|
+
*
|
|
20
|
+
* @example Get the current resource
|
|
21
|
+
* ```tsx
|
|
22
|
+
* const resource = useResource()
|
|
23
|
+
* if (resource && 'projectId' in resource) {
|
|
24
|
+
* console.log(resource.projectId, resource.dataset)
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export function useResource(): DocumentResource | undefined {
|
|
29
|
+
return useContext(ResourceContext)
|
|
30
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {createSanityInstance, type
|
|
1
|
+
import {createSanityInstance, type SanityInstance} from '@sanity/sdk'
|
|
2
2
|
import {renderHook} from '@testing-library/react'
|
|
3
3
|
import {type ReactNode} from 'react'
|
|
4
4
|
import {describe, expect, it} from 'vitest'
|
|
@@ -16,158 +16,20 @@ describe('useSanityInstance', () => {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
it('should return the Sanity instance from context', () => {
|
|
19
|
-
|
|
20
|
-
const instance = createSanityInstance({projectId: 'test-project', dataset: 'test-dataset'})
|
|
19
|
+
const instance = createSanityInstance()
|
|
21
20
|
|
|
22
|
-
// Render the hook with the wrapper that provides the context
|
|
23
21
|
const {result} = renderHook(() => useSanityInstance(), {
|
|
24
22
|
wrapper: createWrapper(instance),
|
|
25
23
|
})
|
|
26
24
|
|
|
27
|
-
// Check that the correct instance is returned
|
|
28
25
|
expect(result.current).toBe(instance)
|
|
29
26
|
})
|
|
30
27
|
|
|
31
28
|
it('should throw an error if no instance is found in context', () => {
|
|
32
|
-
// Expect the hook to throw when no instance is in context
|
|
33
29
|
expect(() => {
|
|
34
30
|
renderHook(() => useSanityInstance(), {
|
|
35
31
|
wrapper: createWrapper(null),
|
|
36
32
|
})
|
|
37
33
|
}).toThrow('SanityInstance context not found')
|
|
38
34
|
})
|
|
39
|
-
|
|
40
|
-
it('should include the requested config in error message when no instance found', () => {
|
|
41
|
-
const requestedConfig = {projectId: 'test', dataset: 'test'}
|
|
42
|
-
|
|
43
|
-
// Expect the hook to throw and include the requested config in the error
|
|
44
|
-
expect(() => {
|
|
45
|
-
renderHook(() => useSanityInstance(requestedConfig), {
|
|
46
|
-
wrapper: createWrapper(null),
|
|
47
|
-
})
|
|
48
|
-
}).toThrow(JSON.stringify(requestedConfig, null, 2))
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
it('should find a matching instance with provided config', () => {
|
|
52
|
-
// Create a parent instance
|
|
53
|
-
const parentInstance = createSanityInstance({
|
|
54
|
-
projectId: 'parent-project',
|
|
55
|
-
dataset: 'parent-dataset',
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
// Create a child instance
|
|
59
|
-
const childInstance = parentInstance.createChild({dataset: 'child-dataset'})
|
|
60
|
-
|
|
61
|
-
// Render the hook with the child instance and request the parent config
|
|
62
|
-
const {result} = renderHook(
|
|
63
|
-
() => useSanityInstance({projectId: 'parent-project', dataset: 'parent-dataset'}),
|
|
64
|
-
{wrapper: createWrapper(childInstance)},
|
|
65
|
-
)
|
|
66
|
-
|
|
67
|
-
// Should match and return the parent instance
|
|
68
|
-
expect(result.current).toBe(parentInstance)
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
it('should throw an error if no matching instance is found for config', () => {
|
|
72
|
-
// Create an instance
|
|
73
|
-
const instance = createSanityInstance({projectId: 'test-project', dataset: 'test-dataset'})
|
|
74
|
-
|
|
75
|
-
// Request a config that doesn't match
|
|
76
|
-
const requestedConfig: SanityConfig = {
|
|
77
|
-
projectId: 'non-existent',
|
|
78
|
-
dataset: 'not-found',
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Expect the hook to throw for a non-matching config
|
|
82
|
-
expect(() => {
|
|
83
|
-
renderHook(() => useSanityInstance(requestedConfig), {
|
|
84
|
-
wrapper: createWrapper(instance),
|
|
85
|
-
})
|
|
86
|
-
}).toThrow('Could not find a matching Sanity instance')
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
it('should include the requested config in error message when no matching instance', () => {
|
|
90
|
-
const instance = createSanityInstance({projectId: 'test-project', dataset: 'test-dataset'})
|
|
91
|
-
const requestedConfig = {projectId: 'different', dataset: 'different'}
|
|
92
|
-
|
|
93
|
-
// Expect the error to include the requested config details
|
|
94
|
-
expect(() => {
|
|
95
|
-
renderHook(() => useSanityInstance(requestedConfig), {
|
|
96
|
-
wrapper: createWrapper(instance),
|
|
97
|
-
})
|
|
98
|
-
}).toThrow(JSON.stringify(requestedConfig, null, 2))
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
it('should return the current instance when no config is provided', () => {
|
|
102
|
-
// Create a hierarchy of instances
|
|
103
|
-
const grandparent = createSanityInstance({projectId: 'gp', dataset: 'gp-ds'})
|
|
104
|
-
const parent = grandparent.createChild({projectId: 'p'})
|
|
105
|
-
const child = parent.createChild({dataset: 'child-ds'})
|
|
106
|
-
|
|
107
|
-
// Render the hook with the child instance and no config
|
|
108
|
-
const {result} = renderHook(() => useSanityInstance(), {
|
|
109
|
-
wrapper: createWrapper(child),
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
// Should return the child instance
|
|
113
|
-
expect(result.current).toBe(child)
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
it('should match child instance when it satisfies the config', () => {
|
|
117
|
-
// Create a parent instance
|
|
118
|
-
const parent = createSanityInstance({projectId: 'parent', dataset: 'parent-ds'})
|
|
119
|
-
|
|
120
|
-
// Create a child instance that inherits projectId
|
|
121
|
-
const child = parent.createChild({dataset: 'child-ds'})
|
|
122
|
-
|
|
123
|
-
// Render the hook with the child instance and request by the child's dataset
|
|
124
|
-
const {result} = renderHook(() => useSanityInstance({dataset: 'child-ds'}), {
|
|
125
|
-
wrapper: createWrapper(child),
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
// Should match and return the child instance
|
|
129
|
-
expect(result.current).toBe(child)
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
it('should match partial config correctly', () => {
|
|
133
|
-
// Create an instance with multiple config values
|
|
134
|
-
const instance = createSanityInstance({
|
|
135
|
-
projectId: 'test-proj',
|
|
136
|
-
dataset: 'test-ds',
|
|
137
|
-
})
|
|
138
|
-
|
|
139
|
-
// Should match when requesting just one property
|
|
140
|
-
const {result} = renderHook(() => useSanityInstance({dataset: 'test-ds'}), {
|
|
141
|
-
wrapper: createWrapper(instance),
|
|
142
|
-
})
|
|
143
|
-
|
|
144
|
-
expect(result.current).toBe(instance)
|
|
145
|
-
})
|
|
146
|
-
|
|
147
|
-
it("should match deeper in hierarchy when current instance doesn't match", () => {
|
|
148
|
-
// Create a three-level hierarchy
|
|
149
|
-
const root = createSanityInstance({projectId: 'root', dataset: 'root-ds'})
|
|
150
|
-
const middle = root.createChild({projectId: 'middle'})
|
|
151
|
-
const leaf = middle.createChild({dataset: 'leaf-ds'})
|
|
152
|
-
|
|
153
|
-
// Request config matching the root from the leaf
|
|
154
|
-
const {result} = renderHook(() => useSanityInstance({projectId: 'root', dataset: 'root-ds'}), {
|
|
155
|
-
wrapper: createWrapper(leaf),
|
|
156
|
-
})
|
|
157
|
-
|
|
158
|
-
// Should find and return the root instance
|
|
159
|
-
expect(result.current).toBe(root)
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
it('should match undefined values in config', () => {
|
|
163
|
-
// Create instance with only projectId
|
|
164
|
-
const rootInstance = createSanityInstance({projectId: 'test'})
|
|
165
|
-
|
|
166
|
-
// Match specifically looking for undefined dataset
|
|
167
|
-
const {result} = renderHook(() => useSanityInstance({dataset: undefined}), {
|
|
168
|
-
wrapper: createWrapper(rootInstance),
|
|
169
|
-
})
|
|
170
|
-
|
|
171
|
-
expect(result.current).toBe(rootInstance)
|
|
172
|
-
})
|
|
173
35
|
})
|
|
@@ -1,80 +1,36 @@
|
|
|
1
|
-
import {type
|
|
1
|
+
import {type SanityInstance} from '@sanity/sdk'
|
|
2
2
|
import {useContext} from 'react'
|
|
3
3
|
|
|
4
4
|
import {SanityInstanceContext} from '../../context/SanityInstanceContext'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* Retrieves the current Sanity instance
|
|
7
|
+
* Retrieves the current Sanity instance from React context.
|
|
8
8
|
*
|
|
9
9
|
* @public
|
|
10
10
|
*
|
|
11
11
|
* @category Platform
|
|
12
|
-
* @
|
|
13
|
-
* @returns The current or matching Sanity instance
|
|
12
|
+
* @returns The current instance
|
|
14
13
|
*
|
|
15
14
|
* @remarks
|
|
16
|
-
* This hook accesses the nearest Sanity instance from
|
|
17
|
-
*
|
|
18
|
-
* that matches the specified configuration using shallow comparison of properties.
|
|
19
|
-
*
|
|
20
|
-
* The hook must be used within a component wrapped by a `ResourceProvider` or `SanityApp`.
|
|
21
|
-
*
|
|
22
|
-
* Use this hook when you need to:
|
|
23
|
-
* - Access the current SanityInstance from context
|
|
24
|
-
* - Find a specific instance with matching project/dataset configuration
|
|
25
|
-
* - Access a parent instance with specific configuration values
|
|
15
|
+
* This hook accesses the nearest Sanity instance from React context,
|
|
16
|
+
* provided by a `ResourceProvider` or `SanityApp`.
|
|
26
17
|
*
|
|
27
18
|
* @example Get the current instance
|
|
28
19
|
* ```tsx
|
|
29
|
-
* // Get the current instance from context
|
|
30
20
|
* const instance = useSanityInstance()
|
|
31
|
-
* console.log(instance.config
|
|
32
|
-
* ```
|
|
33
|
-
*
|
|
34
|
-
* @example Find an instance with specific configuration
|
|
35
|
-
* ```tsx
|
|
36
|
-
* // Find an instance matching the given project and dataset
|
|
37
|
-
* const instance = useSanityInstance({
|
|
38
|
-
* projectId: 'abc123',
|
|
39
|
-
* dataset: 'production'
|
|
40
|
-
* })
|
|
41
|
-
*
|
|
42
|
-
* // Use instance for API calls
|
|
43
|
-
* const fetchDocument = (docId) => {
|
|
44
|
-
* // Instance is guaranteed to have the matching config
|
|
45
|
-
* return client.fetch(`*[_id == $id][0]`, { id: docId })
|
|
46
|
-
* }
|
|
47
|
-
* ```
|
|
48
|
-
*
|
|
49
|
-
* @example Match partial configuration
|
|
50
|
-
* ```tsx
|
|
51
|
-
* // Find an instance with specific auth configuration
|
|
52
|
-
* const instance = useSanityInstance({
|
|
53
|
-
* auth: { requireLogin: true }
|
|
54
|
-
* })
|
|
21
|
+
* console.log(instance.config)
|
|
55
22
|
* ```
|
|
56
23
|
*
|
|
57
24
|
* @throws Error if no SanityInstance is found in context
|
|
58
|
-
* @throws Error if no matching instance is found for the provided config
|
|
59
25
|
*/
|
|
60
|
-
export const useSanityInstance = (
|
|
26
|
+
export const useSanityInstance = (): SanityInstance => {
|
|
61
27
|
const instance = useContext(SanityInstanceContext)
|
|
62
28
|
|
|
63
29
|
if (!instance) {
|
|
64
30
|
throw new Error(
|
|
65
|
-
|
|
66
|
-
)
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (!config) return instance
|
|
70
|
-
|
|
71
|
-
const match = instance.match(config)
|
|
72
|
-
if (!match) {
|
|
73
|
-
throw new Error(
|
|
74
|
-
`Could not find a matching Sanity instance for the requested configuration: ${JSON.stringify(config, null, 2)}.
|
|
75
|
-
Please ensure there is a ResourceProvider component with a matching configuration in the component hierarchy.`,
|
|
31
|
+
'SanityInstance context not found. Please ensure that your component is wrapped in a ResourceProvider or a SanityApp component.',
|
|
76
32
|
)
|
|
77
33
|
}
|
|
78
34
|
|
|
79
|
-
return
|
|
35
|
+
return instance
|
|
80
36
|
}
|
|
@@ -16,8 +16,7 @@ describe('useDispatchIntent', () => {
|
|
|
16
16
|
const mockDocumentHandle: DocumentHandle = {
|
|
17
17
|
documentId: 'test-document-id',
|
|
18
18
|
documentType: 'test-document-type',
|
|
19
|
-
projectId: 'test-project-id',
|
|
20
|
-
dataset: 'test-dataset',
|
|
19
|
+
resource: {projectId: 'test-project-id', dataset: 'test-dataset'},
|
|
21
20
|
}
|
|
22
21
|
|
|
23
22
|
beforeEach(() => {
|
|
@@ -37,11 +36,13 @@ describe('useDispatchIntent', () => {
|
|
|
37
36
|
})
|
|
38
37
|
|
|
39
38
|
it('should throw error when neither action nor intentId is provided', () => {
|
|
39
|
+
const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
|
|
40
40
|
const {result} = renderHook(() => useDispatchIntent({documentHandle: mockDocumentHandle}))
|
|
41
41
|
|
|
42
42
|
expect(() => result.current.dispatchIntent()).toThrow(
|
|
43
43
|
'useDispatchIntent: Either `action` or `intentId` must be provided.',
|
|
44
44
|
)
|
|
45
|
+
consoleErrorSpy.mockRestore()
|
|
45
46
|
})
|
|
46
47
|
|
|
47
48
|
it('should handle errors gracefully', () => {
|
|
@@ -90,8 +91,7 @@ describe('useDispatchIntent', () => {
|
|
|
90
91
|
const newDocumentHandle: DocumentHandle = {
|
|
91
92
|
documentId: 'new-document-id',
|
|
92
93
|
documentType: 'new-document-type',
|
|
93
|
-
projectId: 'new-project-id',
|
|
94
|
-
dataset: 'new-dataset',
|
|
94
|
+
resource: {projectId: 'new-project-id', dataset: 'new-dataset'},
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
rerender({action: 'edit' as const, documentHandle: newDocumentHandle})
|
|
@@ -165,11 +165,11 @@ describe('useDispatchIntent', () => {
|
|
|
165
165
|
})
|
|
166
166
|
})
|
|
167
167
|
|
|
168
|
-
it('should send intent message with media library
|
|
168
|
+
it('should send intent message with media library resource', () => {
|
|
169
169
|
const mockMediaLibraryHandle = {
|
|
170
170
|
documentId: 'test-asset-id',
|
|
171
171
|
documentType: 'sanity.asset',
|
|
172
|
-
|
|
172
|
+
resourceName: 'media-library',
|
|
173
173
|
} as const
|
|
174
174
|
|
|
175
175
|
const {result} = renderHook(() =>
|
|
@@ -194,11 +194,11 @@ describe('useDispatchIntent', () => {
|
|
|
194
194
|
})
|
|
195
195
|
})
|
|
196
196
|
|
|
197
|
-
it('should send intent message with canvas
|
|
197
|
+
it('should send intent message with canvas resource', () => {
|
|
198
198
|
const mockCanvasHandle = {
|
|
199
199
|
documentId: 'test-canvas-document-id',
|
|
200
200
|
documentType: 'sanity.canvas.document',
|
|
201
|
-
|
|
201
|
+
resourceName: 'canvas',
|
|
202
202
|
} as const
|
|
203
203
|
|
|
204
204
|
const {result} = renderHook(() =>
|
|
@@ -223,9 +223,9 @@ describe('useDispatchIntent', () => {
|
|
|
223
223
|
})
|
|
224
224
|
})
|
|
225
225
|
|
|
226
|
-
describe('
|
|
227
|
-
it('should
|
|
228
|
-
const
|
|
226
|
+
describe('default resource fallback', () => {
|
|
227
|
+
it('should use default resource from context when handle has no explicit targeting', () => {
|
|
228
|
+
const minimalHandle = {
|
|
229
229
|
documentId: 'test-document-id',
|
|
230
230
|
documentType: 'test-document-type',
|
|
231
231
|
}
|
|
@@ -233,13 +233,22 @@ describe('useDispatchIntent', () => {
|
|
|
233
233
|
const {result} = renderHook(() =>
|
|
234
234
|
useDispatchIntent({
|
|
235
235
|
action: 'edit',
|
|
236
|
-
documentHandle:
|
|
236
|
+
documentHandle: minimalHandle as unknown as DocumentHandle,
|
|
237
237
|
}),
|
|
238
238
|
)
|
|
239
239
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
)
|
|
240
|
+
result.current.dispatchIntent()
|
|
241
|
+
|
|
242
|
+
expect(mockSendMessage).toHaveBeenCalledWith('dashboard/v1/events/intents/dispatch-intent', {
|
|
243
|
+
action: 'edit',
|
|
244
|
+
document: {
|
|
245
|
+
id: 'test-document-id',
|
|
246
|
+
type: 'test-document-type',
|
|
247
|
+
},
|
|
248
|
+
resource: {
|
|
249
|
+
id: 'test.test',
|
|
250
|
+
},
|
|
251
|
+
})
|
|
243
252
|
})
|
|
244
253
|
})
|
|
245
254
|
})
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {SDK_CHANNEL_NAME, SDK_NODE_NAME} from '@sanity/message-protocol'
|
|
2
|
-
import {type
|
|
2
|
+
import {type FrameMessage} from '@sanity/sdk'
|
|
3
3
|
import {useCallback} from 'react'
|
|
4
4
|
|
|
5
|
+
import {type DocumentHandle} from '../../config/handles'
|
|
5
6
|
import {useWindowConnection} from '../comlink/useWindowConnection'
|
|
6
|
-
import {type WithSourceNameSupport} from '../helpers/useNormalizedSourceOptions'
|
|
7
7
|
import {useResourceIdFromDocumentHandle} from './utils/useResourceIdFromDocumentHandle'
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -42,7 +42,7 @@ interface DispatchIntent {
|
|
|
42
42
|
interface UseDispatchIntentParams {
|
|
43
43
|
action?: 'edit'
|
|
44
44
|
intentId?: string
|
|
45
|
-
documentHandle:
|
|
45
|
+
documentHandle: DocumentHandle
|
|
46
46
|
parameters?: Record<string, unknown>
|
|
47
47
|
}
|
|
48
48
|
|
|
@@ -56,8 +56,8 @@ interface UseDispatchIntentParams {
|
|
|
56
56
|
* - `action` - Action to perform (currently only 'edit' is supported). Will prompt a picker if multiple handlers are available.
|
|
57
57
|
* - `intentId` - Specific ID of the intent to dispatch. Either `action` or `intentId` is required.
|
|
58
58
|
* - `documentHandle` - The document handle containing document ID, type, and either:
|
|
59
|
-
* - `projectId` and `dataset` for traditional dataset
|
|
60
|
-
* - `
|
|
59
|
+
* - `projectId` and `dataset` for traditional dataset resources, like `{documentId: '123', documentType: 'book', projectId: 'abc123', dataset: 'production'}`
|
|
60
|
+
* - `resource` for media library, canvas, or dataset resources, like `{documentId: '123', documentType: 'sanity.asset', resource: mediaLibraryResource('ml123')}` or `{documentId: '123', documentType: 'sanity.canvas.document', resource: canvasResource('canvas123')}`
|
|
61
61
|
* - `paremeters` - Optional parameters to include in the dispatch; will be passed to the resolved intent handler
|
|
62
62
|
* @returns An object containing:
|
|
63
63
|
* - `dispatchIntent` - Function to dispatch the intent message
|
|
@@ -119,10 +119,10 @@ export function useDispatchIntent(params: UseDispatchIntentParams): DispatchInte
|
|
|
119
119
|
)
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
// Validate that we have a resource ID (which is computed from
|
|
122
|
+
// Validate that we have a resource ID (which is computed from resource/resourceName or projectId+dataset)
|
|
123
123
|
if (!resource.id) {
|
|
124
124
|
throw new Error(
|
|
125
|
-
'useDispatchIntent: Unable to determine resource. Either `
|
|
125
|
+
'useDispatchIntent: Unable to determine resource. Either `resource`, `resourceName`, or both `projectId` and `dataset` must be provided in documentHandle.',
|
|
126
126
|
)
|
|
127
127
|
}
|
|
128
128
|
|