@sanity/sdk-react 2.5.0 → 2.6.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 +97 -20
- package/dist/index.d.ts +35 -14
- package/dist/index.js +84 -44
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
- package/src/_exports/sdk-react.ts +1 -0
- package/src/components/SDKProvider.tsx +8 -3
- package/src/components/SanityApp.tsx +2 -1
- package/src/context/SourcesContext.tsx +7 -0
- package/src/context/renderSanityApp.test.tsx +355 -0
- package/src/context/renderSanityApp.tsx +48 -0
- package/src/hooks/context/useSource.tsx +34 -0
- package/src/hooks/dashboard/useDispatchIntent.test.ts +24 -18
- package/src/hooks/dashboard/useDispatchIntent.ts +9 -10
- package/src/hooks/dashboard/utils/{getResourceIdFromDocumentHandle.test.ts → useResourceIdFromDocumentHandle.test.ts} +33 -59
- package/src/hooks/dashboard/utils/useResourceIdFromDocumentHandle.ts +46 -0
- package/src/hooks/document/useEditDocument.ts +3 -0
- package/src/hooks/documents/useDocuments.ts +3 -2
- package/src/hooks/paginatedDocuments/usePaginatedDocuments.ts +1 -0
- package/src/hooks/query/useQuery.ts +21 -8
- package/src/hooks/dashboard/types.ts +0 -12
- package/src/hooks/dashboard/utils/getResourceIdFromDocumentHandle.ts +0 -53
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import {SDK_CHANNEL_NAME, SDK_NODE_NAME} from '@sanity/message-protocol'
|
|
2
|
-
import {type FrameMessage} from '@sanity/sdk'
|
|
2
|
+
import {type DocumentHandle, type FrameMessage} from '@sanity/sdk'
|
|
3
3
|
import {useCallback} from 'react'
|
|
4
4
|
|
|
5
5
|
import {useWindowConnection} from '../comlink/useWindowConnection'
|
|
6
|
-
import {
|
|
7
|
-
import {getResourceIdFromDocumentHandle} from './utils/getResourceIdFromDocumentHandle'
|
|
6
|
+
import {useResourceIdFromDocumentHandle} from './utils/useResourceIdFromDocumentHandle'
|
|
8
7
|
|
|
9
8
|
/**
|
|
10
9
|
* Message type for sending intents to the dashboard
|
|
@@ -42,7 +41,7 @@ interface DispatchIntent {
|
|
|
42
41
|
interface UseDispatchIntentParams {
|
|
43
42
|
action?: 'edit'
|
|
44
43
|
intentId?: string
|
|
45
|
-
documentHandle:
|
|
44
|
+
documentHandle: DocumentHandle
|
|
46
45
|
parameters?: Record<string, unknown>
|
|
47
46
|
}
|
|
48
47
|
|
|
@@ -104,13 +103,15 @@ export function useDispatchIntent(params: UseDispatchIntentParams): DispatchInte
|
|
|
104
103
|
connectTo: SDK_CHANNEL_NAME,
|
|
105
104
|
})
|
|
106
105
|
|
|
106
|
+
const resource = useResourceIdFromDocumentHandle(documentHandle)
|
|
107
|
+
|
|
107
108
|
const dispatchIntent = useCallback(() => {
|
|
108
109
|
try {
|
|
109
110
|
if (!action && !intentId) {
|
|
110
111
|
throw new Error('useDispatchIntent: Either `action` or `intentId` must be provided.')
|
|
111
112
|
}
|
|
112
113
|
|
|
113
|
-
const {projectId, dataset,
|
|
114
|
+
const {projectId, dataset, sourceName} = documentHandle
|
|
114
115
|
|
|
115
116
|
if (action && intentId) {
|
|
116
117
|
// eslint-disable-next-line no-console -- warn if both action and intentId are provided
|
|
@@ -119,14 +120,12 @@ export function useDispatchIntent(params: UseDispatchIntentParams): DispatchInte
|
|
|
119
120
|
)
|
|
120
121
|
}
|
|
121
122
|
|
|
122
|
-
if (!
|
|
123
|
+
if (!sourceName && (!projectId || !dataset)) {
|
|
123
124
|
throw new Error(
|
|
124
|
-
'useDispatchIntent: Either `
|
|
125
|
+
'useDispatchIntent: Either `sourceName` or both `projectId` and `dataset` must be provided in documentHandle.',
|
|
125
126
|
)
|
|
126
127
|
}
|
|
127
128
|
|
|
128
|
-
const resource = getResourceIdFromDocumentHandle(documentHandle)
|
|
129
|
-
|
|
130
129
|
const message: IntentMessage = {
|
|
131
130
|
type: 'dashboard/v1/events/intents/dispatch-intent',
|
|
132
131
|
data: {
|
|
@@ -150,7 +149,7 @@ export function useDispatchIntent(params: UseDispatchIntentParams): DispatchInte
|
|
|
150
149
|
console.error('Failed to dispatch intent:', error)
|
|
151
150
|
throw error
|
|
152
151
|
}
|
|
153
|
-
}, [action, intentId, documentHandle, parameters, sendMessage])
|
|
152
|
+
}, [action, intentId, documentHandle, parameters, sendMessage, resource.id, resource.type])
|
|
154
153
|
|
|
155
154
|
return {
|
|
156
155
|
dispatchIntent,
|
|
@@ -1,28 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
canvasSource,
|
|
3
|
-
datasetSource,
|
|
4
|
-
type DocumentHandle,
|
|
5
|
-
type DocumentSource,
|
|
6
|
-
mediaLibrarySource,
|
|
7
|
-
} from '@sanity/sdk'
|
|
1
|
+
import {type DocumentHandle} from '@sanity/sdk'
|
|
8
2
|
import {describe, expect, it} from 'vitest'
|
|
9
3
|
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
4
|
+
import {renderHook} from '../../../../test/test-utils'
|
|
5
|
+
import {useResourceIdFromDocumentHandle} from './useResourceIdFromDocumentHandle'
|
|
12
6
|
|
|
13
7
|
describe('getResourceIdFromDocumentHandle', () => {
|
|
14
8
|
describe('with traditional DocumentHandle (projectId/dataset)', () => {
|
|
15
9
|
it('should return resource ID from projectId and dataset', () => {
|
|
16
|
-
const documentHandle
|
|
10
|
+
const documentHandle = {
|
|
17
11
|
documentId: 'test-document-id',
|
|
18
12
|
documentType: 'test-document-type',
|
|
19
13
|
projectId: 'test-project-id',
|
|
20
14
|
dataset: 'test-dataset',
|
|
21
15
|
}
|
|
22
16
|
|
|
23
|
-
const result =
|
|
17
|
+
const {result} = renderHook(() => useResourceIdFromDocumentHandle(documentHandle))
|
|
24
18
|
|
|
25
|
-
expect(result).toEqual({
|
|
19
|
+
expect(result.current).toEqual({
|
|
26
20
|
id: 'test-project-id.test-dataset',
|
|
27
21
|
type: undefined,
|
|
28
22
|
})
|
|
@@ -31,33 +25,33 @@ describe('getResourceIdFromDocumentHandle', () => {
|
|
|
31
25
|
|
|
32
26
|
describe('with DocumentHandleWithSource - media library', () => {
|
|
33
27
|
it('should return media library ID and resourceType when media library source is provided', () => {
|
|
34
|
-
const documentHandle:
|
|
28
|
+
const documentHandle: DocumentHandle = {
|
|
35
29
|
documentId: 'test-asset-id',
|
|
36
30
|
documentType: 'sanity.asset',
|
|
37
|
-
|
|
31
|
+
sourceName: 'media-library',
|
|
38
32
|
}
|
|
39
33
|
|
|
40
|
-
const result =
|
|
34
|
+
const {result} = renderHook(() => useResourceIdFromDocumentHandle(documentHandle))
|
|
41
35
|
|
|
42
|
-
expect(result).toEqual({
|
|
43
|
-
id: '
|
|
36
|
+
expect(result.current).toEqual({
|
|
37
|
+
id: 'media-library-id',
|
|
44
38
|
type: 'media-library',
|
|
45
39
|
})
|
|
46
40
|
})
|
|
47
41
|
|
|
48
42
|
it('should prioritize source over projectId/dataset when both are provided', () => {
|
|
49
|
-
const documentHandle
|
|
43
|
+
const documentHandle = {
|
|
50
44
|
documentId: 'test-asset-id',
|
|
51
45
|
documentType: 'sanity.asset',
|
|
52
46
|
projectId: 'test-project-id',
|
|
53
47
|
dataset: 'test-dataset',
|
|
54
|
-
|
|
48
|
+
sourceName: 'media-library',
|
|
55
49
|
}
|
|
56
50
|
|
|
57
|
-
const result =
|
|
51
|
+
const {result} = renderHook(() => useResourceIdFromDocumentHandle(documentHandle))
|
|
58
52
|
|
|
59
|
-
expect(result).toEqual({
|
|
60
|
-
id: '
|
|
53
|
+
expect(result.current).toEqual({
|
|
54
|
+
id: 'media-library-id',
|
|
61
55
|
type: 'media-library',
|
|
62
56
|
})
|
|
63
57
|
})
|
|
@@ -65,16 +59,16 @@ describe('getResourceIdFromDocumentHandle', () => {
|
|
|
65
59
|
|
|
66
60
|
describe('with DocumentHandleWithSource - canvas', () => {
|
|
67
61
|
it('should return canvas ID and resourceType when canvas source is provided', () => {
|
|
68
|
-
const documentHandle
|
|
62
|
+
const documentHandle = {
|
|
69
63
|
documentId: 'test-canvas-document-id',
|
|
70
64
|
documentType: 'sanity.canvas.document',
|
|
71
|
-
|
|
65
|
+
sourceName: 'canvas',
|
|
72
66
|
}
|
|
73
67
|
|
|
74
|
-
const result =
|
|
68
|
+
const {result} = renderHook(() => useResourceIdFromDocumentHandle(documentHandle))
|
|
75
69
|
|
|
76
|
-
expect(result).toEqual({
|
|
77
|
-
id: '
|
|
70
|
+
expect(result.current).toEqual({
|
|
71
|
+
id: 'canvas-id',
|
|
78
72
|
type: 'canvas',
|
|
79
73
|
})
|
|
80
74
|
})
|
|
@@ -82,32 +76,32 @@ describe('getResourceIdFromDocumentHandle', () => {
|
|
|
82
76
|
|
|
83
77
|
describe('with DocumentHandleWithSource - dataset source', () => {
|
|
84
78
|
it('should return dataset resource ID when dataset source is provided', () => {
|
|
85
|
-
const documentHandle
|
|
79
|
+
const documentHandle = {
|
|
86
80
|
documentId: 'test-document-id',
|
|
87
81
|
documentType: 'test-document-type',
|
|
88
|
-
|
|
82
|
+
sourceName: 'dataset',
|
|
89
83
|
}
|
|
90
84
|
|
|
91
|
-
const result =
|
|
85
|
+
const {result} = renderHook(() => useResourceIdFromDocumentHandle(documentHandle))
|
|
92
86
|
|
|
93
|
-
expect(result).toEqual({
|
|
87
|
+
expect(result.current).toEqual({
|
|
94
88
|
id: 'source-project-id.source-dataset',
|
|
95
89
|
type: undefined,
|
|
96
90
|
})
|
|
97
91
|
})
|
|
98
92
|
|
|
99
93
|
it('should use dataset source over projectId/dataset when both are provided', () => {
|
|
100
|
-
const documentHandle
|
|
94
|
+
const documentHandle = {
|
|
101
95
|
documentId: 'test-document-id',
|
|
102
96
|
documentType: 'test-document-type',
|
|
103
97
|
projectId: 'test-project-id',
|
|
104
98
|
dataset: 'test-dataset',
|
|
105
|
-
|
|
99
|
+
sourceName: 'dataset',
|
|
106
100
|
}
|
|
107
101
|
|
|
108
|
-
const result =
|
|
102
|
+
const {result} = renderHook(() => useResourceIdFromDocumentHandle(documentHandle))
|
|
109
103
|
|
|
110
|
-
expect(result).toEqual({
|
|
104
|
+
expect(result.current).toEqual({
|
|
111
105
|
id: 'source-project-id.source-dataset',
|
|
112
106
|
type: undefined,
|
|
113
107
|
})
|
|
@@ -116,37 +110,17 @@ describe('getResourceIdFromDocumentHandle', () => {
|
|
|
116
110
|
|
|
117
111
|
describe('edge cases', () => {
|
|
118
112
|
it('should handle DocumentHandleWithSource with undefined source', () => {
|
|
119
|
-
const documentHandle
|
|
120
|
-
documentId: 'test-document-id',
|
|
121
|
-
documentType: 'test-document-type',
|
|
122
|
-
projectId: 'test-project-id',
|
|
123
|
-
dataset: 'test-dataset',
|
|
124
|
-
source: undefined,
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const result = getResourceIdFromDocumentHandle(documentHandle)
|
|
128
|
-
|
|
129
|
-
expect(result).toEqual({
|
|
130
|
-
id: 'test-project-id.test-dataset',
|
|
131
|
-
type: undefined,
|
|
132
|
-
})
|
|
133
|
-
})
|
|
134
|
-
|
|
135
|
-
it('should fall back to projectId/dataset when source is not recognized', () => {
|
|
136
|
-
const documentHandle: DocumentHandleWithSource = {
|
|
113
|
+
const documentHandle = {
|
|
137
114
|
documentId: 'test-document-id',
|
|
138
115
|
documentType: 'test-document-type',
|
|
139
116
|
projectId: 'test-project-id',
|
|
140
117
|
dataset: 'test-dataset',
|
|
141
|
-
|
|
142
|
-
__sanity_internal_sourceId: 'unknown-format',
|
|
143
|
-
} as unknown as DocumentSource,
|
|
118
|
+
sourceName: undefined,
|
|
144
119
|
}
|
|
145
120
|
|
|
146
|
-
const result =
|
|
121
|
+
const {result} = renderHook(() => useResourceIdFromDocumentHandle(documentHandle))
|
|
147
122
|
|
|
148
|
-
|
|
149
|
-
expect(result).toEqual({
|
|
123
|
+
expect(result.current).toEqual({
|
|
150
124
|
id: 'test-project-id.test-dataset',
|
|
151
125
|
type: undefined,
|
|
152
126
|
})
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type DocumentHandle,
|
|
3
|
+
isCanvasSource,
|
|
4
|
+
isDatasetSource,
|
|
5
|
+
isMediaLibrarySource,
|
|
6
|
+
} from '@sanity/sdk'
|
|
7
|
+
|
|
8
|
+
import {useSource} from '../../context/useSource'
|
|
9
|
+
|
|
10
|
+
interface DashboardMessageResource {
|
|
11
|
+
id: string
|
|
12
|
+
type?: 'media-library' | 'canvas'
|
|
13
|
+
}
|
|
14
|
+
/** Currently only used for dispatching intents to the dashboard,
|
|
15
|
+
* but could easily be extended to other dashboard hooks
|
|
16
|
+
* @beta
|
|
17
|
+
*/
|
|
18
|
+
export function useResourceIdFromDocumentHandle(
|
|
19
|
+
documentHandle: DocumentHandle,
|
|
20
|
+
): DashboardMessageResource {
|
|
21
|
+
const source = useSource(documentHandle)
|
|
22
|
+
const {projectId, dataset} = documentHandle
|
|
23
|
+
let resourceId: string = ''
|
|
24
|
+
let resourceType: 'media-library' | 'canvas' | undefined
|
|
25
|
+
if (projectId && dataset) {
|
|
26
|
+
resourceId = `${projectId}.${dataset}`
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (source) {
|
|
30
|
+
if (isDatasetSource(source)) {
|
|
31
|
+
resourceId = `${source.projectId}.${source.dataset}`
|
|
32
|
+
resourceType = undefined
|
|
33
|
+
} else if (isMediaLibrarySource(source)) {
|
|
34
|
+
resourceId = source.mediaLibraryId
|
|
35
|
+
resourceType = 'media-library'
|
|
36
|
+
} else if (isCanvasSource(source)) {
|
|
37
|
+
resourceId = source.canvasId
|
|
38
|
+
resourceType = 'canvas'
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
id: resourceId,
|
|
44
|
+
type: resourceType,
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -100,6 +100,9 @@ export function useEditDocument<TData>(
|
|
|
100
100
|
* 3. **Explicit Type (Full Document):** Edit the entire document with a manually specified type.
|
|
101
101
|
* 4. **Explicit Type (Specific Path):** Edit a specific field with a manually specified type.
|
|
102
102
|
*
|
|
103
|
+
* **LiveEdit Documents:**
|
|
104
|
+
* 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.
|
|
105
|
+
*
|
|
103
106
|
* This hook relies on the document state being loaded. If the document is not yet available
|
|
104
107
|
* (e.g., during initial load), the component using this hook will suspend.
|
|
105
108
|
*
|
|
@@ -23,8 +23,8 @@ export interface DocumentsOptions<
|
|
|
23
23
|
TDocumentType extends string = string,
|
|
24
24
|
TDataset extends string = string,
|
|
25
25
|
TProjectId extends string = string,
|
|
26
|
-
>
|
|
27
|
-
|
|
26
|
+
>
|
|
27
|
+
extends DatasetHandle<TDataset, TProjectId>, Pick<QueryOptions, 'perspective' | 'params'> {
|
|
28
28
|
/**
|
|
29
29
|
* Filter documents by their `_type`. Can be a single type or an array of types.
|
|
30
30
|
*/
|
|
@@ -39,6 +39,7 @@ export interface DocumentsOptions<
|
|
|
39
39
|
batchSize?: number
|
|
40
40
|
/**
|
|
41
41
|
* Sorting configuration for the results
|
|
42
|
+
* @beta
|
|
42
43
|
*/
|
|
43
44
|
orderings?: SortOrderingItem[]
|
|
44
45
|
/**
|
|
@@ -9,6 +9,16 @@ import {type SanityQueryResult} from 'groq'
|
|
|
9
9
|
import {useEffect, useMemo, useRef, useState, useSyncExternalStore, useTransition} from 'react'
|
|
10
10
|
|
|
11
11
|
import {useSanityInstance} from '../context/useSanityInstance'
|
|
12
|
+
import {useSource} from '../context/useSource'
|
|
13
|
+
|
|
14
|
+
interface UseQueryOptions<
|
|
15
|
+
TQuery extends string = string,
|
|
16
|
+
TDataset extends string = string,
|
|
17
|
+
TProjectId extends string = string,
|
|
18
|
+
TSourceName extends string = string,
|
|
19
|
+
> extends QueryOptions<TQuery, TDataset, TProjectId> {
|
|
20
|
+
sourceName?: TSourceName
|
|
21
|
+
}
|
|
12
22
|
|
|
13
23
|
// Overload 1: Inferred Type (using Typegen)
|
|
14
24
|
/**
|
|
@@ -70,8 +80,9 @@ export function useQuery<
|
|
|
70
80
|
TQuery extends string = string,
|
|
71
81
|
TDataset extends string = string,
|
|
72
82
|
TProjectId extends string = string,
|
|
83
|
+
TSourceName extends string = string,
|
|
73
84
|
>(
|
|
74
|
-
options:
|
|
85
|
+
options: UseQueryOptions<TQuery, TDataset, TProjectId, TSourceName>,
|
|
75
86
|
): {
|
|
76
87
|
/** The query result, typed based on the GROQ query string */
|
|
77
88
|
data: SanityQueryResult<TQuery, `${TProjectId}.${TDataset}`>
|
|
@@ -137,6 +148,8 @@ export function useQuery(options: QueryOptions): {data: unknown; isPending: bool
|
|
|
137
148
|
// Implementation returns unknown, overloads define specifics
|
|
138
149
|
const instance = useSanityInstance(options)
|
|
139
150
|
|
|
151
|
+
const source = useSource(options)
|
|
152
|
+
|
|
140
153
|
// Use React's useTransition to avoid UI jank when queries change
|
|
141
154
|
const [isPending, startTransition] = useTransition()
|
|
142
155
|
|
|
@@ -144,8 +157,6 @@ export function useQuery(options: QueryOptions): {data: unknown; isPending: bool
|
|
|
144
157
|
const queryKey = getQueryKey(options)
|
|
145
158
|
// Use a deferred state to avoid immediate re-renders when the query changes
|
|
146
159
|
const [deferredQueryKey, setDeferredQueryKey] = useState(queryKey)
|
|
147
|
-
// Parse the deferred query key back into a query and options
|
|
148
|
-
const deferred = useMemo(() => parseQueryKey(deferredQueryKey), [deferredQueryKey])
|
|
149
160
|
|
|
150
161
|
// Create an AbortController to cancel in-flight requests when needed
|
|
151
162
|
const ref = useRef<AbortController>(new AbortController())
|
|
@@ -166,10 +177,11 @@ export function useQuery(options: QueryOptions): {data: unknown; isPending: bool
|
|
|
166
177
|
}, [deferredQueryKey, queryKey])
|
|
167
178
|
|
|
168
179
|
// Get the state source for this query from the query store
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
180
|
+
// Memoize the options object by depending on the stable string key instead of the parsed object
|
|
181
|
+
const {getCurrent, subscribe} = useMemo(() => {
|
|
182
|
+
const deferred = parseQueryKey(deferredQueryKey)
|
|
183
|
+
return getQueryState(instance, {...deferred, source})
|
|
184
|
+
}, [instance, deferredQueryKey, source])
|
|
173
185
|
|
|
174
186
|
// If data isn't available yet, suspend rendering
|
|
175
187
|
if (getCurrent() === undefined) {
|
|
@@ -182,8 +194,9 @@ export function useQuery(options: QueryOptions): {data: unknown; isPending: bool
|
|
|
182
194
|
// the captured signal remains unchanged for this suspended render.
|
|
183
195
|
// Thus, the promise thrown here uses a stable abort signal, ensuring correct behavior.
|
|
184
196
|
const currentSignal = ref.current.signal
|
|
197
|
+
const deferred = parseQueryKey(deferredQueryKey)
|
|
185
198
|
|
|
186
|
-
throw resolveQuery(instance, {...deferred, signal: currentSignal})
|
|
199
|
+
throw resolveQuery(instance, {...deferred, source, signal: currentSignal})
|
|
187
200
|
}
|
|
188
201
|
|
|
189
202
|
// Subscribe to updates and get the current data
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import {type DocumentHandle, type DocumentSource} from '@sanity/sdk'
|
|
2
|
-
/**
|
|
3
|
-
* Document handle that optionally includes a source (e.g., media library source)
|
|
4
|
-
* or projectId and dataset for traditional dataset sources
|
|
5
|
-
* (but now marked optional since it's valid to just use a source)
|
|
6
|
-
* @beta
|
|
7
|
-
*/
|
|
8
|
-
export interface DocumentHandleWithSource extends Omit<DocumentHandle, 'projectId' | 'dataset'> {
|
|
9
|
-
source?: DocumentSource
|
|
10
|
-
projectId?: string
|
|
11
|
-
dataset?: string
|
|
12
|
-
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import {type DocumentHandle, type DocumentSource} from '@sanity/sdk'
|
|
2
|
-
|
|
3
|
-
import {type DocumentHandleWithSource} from '../types'
|
|
4
|
-
|
|
5
|
-
// Internal constant for accessing source ID
|
|
6
|
-
const SOURCE_ID = '__sanity_internal_sourceId' as const
|
|
7
|
-
|
|
8
|
-
interface DashboardMessageResource {
|
|
9
|
-
id: string
|
|
10
|
-
type?: 'media-library' | 'canvas'
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const isDocumentHandleWithSource = (
|
|
14
|
-
documentHandle: DocumentHandle | DocumentHandleWithSource,
|
|
15
|
-
): documentHandle is DocumentHandleWithSource => {
|
|
16
|
-
return 'source' in documentHandle
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/** Currently only used for dispatching intents to the dashboard,
|
|
20
|
-
* but could easily be extended to other dashboard hooks
|
|
21
|
-
* @beta
|
|
22
|
-
*/
|
|
23
|
-
export function getResourceIdFromDocumentHandle(
|
|
24
|
-
documentHandle: DocumentHandle | DocumentHandleWithSource,
|
|
25
|
-
): DashboardMessageResource {
|
|
26
|
-
let source: DocumentSource | undefined
|
|
27
|
-
|
|
28
|
-
const {projectId, dataset} = documentHandle
|
|
29
|
-
if (isDocumentHandleWithSource(documentHandle)) {
|
|
30
|
-
source = documentHandle.source
|
|
31
|
-
}
|
|
32
|
-
let resourceId: string = projectId + '.' + dataset
|
|
33
|
-
let resourceType: 'media-library' | 'canvas' | undefined
|
|
34
|
-
|
|
35
|
-
if (source) {
|
|
36
|
-
const sourceId = (source as Record<string, unknown>)[SOURCE_ID]
|
|
37
|
-
if (Array.isArray(sourceId)) {
|
|
38
|
-
if (sourceId[0] === 'media-library' || sourceId[0] === 'canvas') {
|
|
39
|
-
resourceType = sourceId[0] as 'media-library' | 'canvas'
|
|
40
|
-
resourceId = sourceId[1] as string
|
|
41
|
-
}
|
|
42
|
-
} else if (sourceId && typeof sourceId === 'object' && 'projectId' in sourceId) {
|
|
43
|
-
const datasetSource = sourceId as {projectId: string; dataset: string}
|
|
44
|
-
// don't create type since it's ambiguous for project / dataset docs
|
|
45
|
-
resourceId = `${datasetSource.projectId}.${datasetSource.dataset}`
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return {
|
|
50
|
-
id: resourceId,
|
|
51
|
-
type: resourceType,
|
|
52
|
-
}
|
|
53
|
-
}
|