@sanity/sdk-react 0.0.1 → 0.0.3

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.
Files changed (31) hide show
  1. package/README.md +3 -3
  2. package/dist/index.d.ts +364 -287
  3. package/dist/index.js +125 -149
  4. package/dist/index.js.map +1 -1
  5. package/package.json +5 -5
  6. package/src/_exports/sdk-react.ts +10 -10
  7. package/src/hooks/comlink/useWindowConnection.test.tsx +145 -0
  8. package/src/hooks/comlink/useWindowConnection.ts +32 -30
  9. package/src/hooks/{comlink → dashboard}/useManageFavorite.test.ts +84 -134
  10. package/src/hooks/{comlink → dashboard}/useManageFavorite.ts +4 -39
  11. package/src/hooks/dashboard/useNavigateToStudioDocument.test.ts +2 -73
  12. package/src/hooks/dashboard/useNavigateToStudioDocument.ts +20 -27
  13. package/src/hooks/dashboard/useRecordDocumentHistoryEvent.test.ts +69 -0
  14. package/src/hooks/{comlink → dashboard}/useRecordDocumentHistoryEvent.ts +17 -10
  15. package/src/hooks/dashboard/useStudioWorkspacesByProjectIdDataset.test.tsx +14 -85
  16. package/src/hooks/dashboard/useStudioWorkspacesByProjectIdDataset.ts +33 -8
  17. package/src/hooks/document/useApplyDocumentActions.ts +4 -4
  18. package/src/hooks/document/useDocument.test.ts +8 -10
  19. package/src/hooks/document/useDocument.ts +50 -33
  20. package/src/hooks/document/useDocumentEvent.ts +2 -2
  21. package/src/hooks/document/useDocumentSyncStatus.ts +1 -1
  22. package/src/hooks/document/useEditDocument.ts +15 -15
  23. package/src/hooks/documents/useDocuments.ts +5 -5
  24. package/src/hooks/paginatedDocuments/usePaginatedDocuments.ts +5 -5
  25. package/src/hooks/preview/{usePreview.test.tsx → useDocumentPreview.test.tsx} +5 -5
  26. package/src/hooks/preview/{usePreview.tsx → useDocumentPreview.tsx} +11 -8
  27. package/src/hooks/projection/{useProjection.test.tsx → useDocumentProjection.test.tsx} +5 -5
  28. package/src/hooks/projection/{useProjection.ts → useDocumentProjection.ts} +22 -17
  29. package/src/hooks/query/useQuery.ts +5 -5
  30. package/src/hooks/comlink/useRecordDocumentHistoryEvent.test.ts +0 -85
  31. package/src/hooks/comlink/useWindowConnection.test.ts +0 -135
@@ -1,4 +1,3 @@
1
- import {type Status} from '@sanity/comlink'
2
1
  import {
3
2
  type CanvasResource,
4
3
  type Events,
@@ -14,16 +13,15 @@ import {
14
13
  getFavoritesState,
15
14
  resolveFavoritesState,
16
15
  } from '@sanity/sdk'
17
- import {useCallback, useMemo, useState, useSyncExternalStore} from 'react'
16
+ import {useCallback, useMemo, useSyncExternalStore} from 'react'
18
17
 
18
+ import {useWindowConnection} from '../comlink/useWindowConnection'
19
19
  import {useSanityInstance} from '../context/useSanityInstance'
20
- import {useWindowConnection} from './useWindowConnection'
21
20
 
22
21
  interface ManageFavorite extends FavoriteStatusResponse {
23
22
  favorite: () => Promise<void>
24
23
  unfavorite: () => Promise<void>
25
24
  isFavorited: boolean
26
- isConnected: boolean
27
25
  }
28
26
 
29
27
  interface UseManageFavoriteProps extends DocumentHandle {
@@ -92,11 +90,9 @@ export function useManageFavorite({
92
90
  resourceType,
93
91
  schemaName,
94
92
  }: UseManageFavoriteProps): ManageFavorite {
95
- const [status, setStatus] = useState<Status>('idle')
96
93
  const {fetch} = useWindowConnection<Events.FavoriteMessage, FrameMessage>({
97
94
  name: SDK_NODE_NAME,
98
95
  connectTo: SDK_CHANNEL_NAME,
99
- onStatus: setStatus,
100
96
  })
101
97
  const instance = useSanityInstance()
102
98
  const {config} = instance
@@ -136,7 +132,7 @@ export function useManageFavorite({
136
132
 
137
133
  const handleFavoriteAction = useCallback(
138
134
  async (action: 'added' | 'removed') => {
139
- if (status !== 'connected' || !fetch || !documentId || !documentType || !resourceType) return
135
+ if (!fetch || !documentId || !documentType || !resourceType) return
140
136
 
141
137
  try {
142
138
  const payload = {
@@ -165,46 +161,15 @@ export function useManageFavorite({
165
161
  throw err
166
162
  }
167
163
  },
168
- [
169
- fetch,
170
- documentId,
171
- documentType,
172
- resourceId,
173
- resourceType,
174
- schemaName,
175
- instance,
176
- context,
177
- status,
178
- ],
164
+ [fetch, documentId, documentType, resourceId, resourceType, schemaName, instance, context],
179
165
  )
180
166
 
181
167
  const favorite = useCallback(() => handleFavoriteAction('added'), [handleFavoriteAction])
182
168
  const unfavorite = useCallback(() => handleFavoriteAction('removed'), [handleFavoriteAction])
183
169
 
184
- // if state is undefined, we should suspend
185
- if (!state) {
186
- try {
187
- const promise = resolveFavoritesState(instance, context)
188
- throw promise
189
- } catch (err) {
190
- // If we get a timeout error, return a fallback state instead of suspending
191
- if (err instanceof Error && err.message === 'Favorites service connection timeout') {
192
- return {
193
- favorite: async () => {},
194
- unfavorite: async () => {},
195
- isFavorited: false,
196
- isConnected: false,
197
- }
198
- }
199
- // For other errors, continue with suspension
200
- throw err
201
- }
202
- }
203
-
204
170
  return {
205
171
  favorite,
206
172
  unfavorite,
207
173
  isFavorited,
208
- isConnected: status === 'connected',
209
174
  }
210
175
  }
@@ -1,6 +1,5 @@
1
- import {type Status} from '@sanity/comlink'
2
1
  import {type DocumentHandle} from '@sanity/sdk'
3
- import {act, renderHook} from '@testing-library/react'
2
+ import {renderHook} from '@testing-library/react'
4
3
  import {beforeEach, describe, expect, it, vi} from 'vitest'
5
4
 
6
5
  import {useNavigateToStudioDocument} from './useNavigateToStudioDocument'
@@ -9,13 +8,10 @@ import {useNavigateToStudioDocument} from './useNavigateToStudioDocument'
9
8
  const mockSendMessage = vi.fn()
10
9
  const mockFetch = vi.fn()
11
10
  let mockWorkspacesByProjectIdAndDataset = {}
12
- let mockWorkspacesIsConnected = true
13
- let mockStatusCallback: ((status: Status) => void) | null = null
14
11
 
15
12
  vi.mock('../comlink/useWindowConnection', () => {
16
13
  return {
17
- useWindowConnection: ({onStatus}: {onStatus?: (status: Status) => void}) => {
18
- mockStatusCallback = onStatus || null
14
+ useWindowConnection: () => {
19
15
  return {
20
16
  sendMessage: mockSendMessage,
21
17
  fetch: mockFetch,
@@ -29,7 +25,6 @@ vi.mock('./useStudioWorkspacesByProjectIdDataset', () => {
29
25
  useStudioWorkspacesByProjectIdDataset: () => ({
30
26
  workspacesByProjectIdAndDataset: mockWorkspacesByProjectIdAndDataset,
31
27
  error: null,
32
- isConnected: mockWorkspacesIsConnected,
33
28
  }),
34
29
  }
35
30
  })
@@ -57,35 +52,19 @@ describe('useNavigateToStudioDocument', () => {
57
52
  mockWorkspacesByProjectIdAndDataset = {
58
53
  'project1:dataset1': [mockWorkspace],
59
54
  }
60
- mockWorkspacesIsConnected = true
61
- mockStatusCallback = null
62
55
  })
63
56
 
64
57
  it('returns a function and connection status', () => {
65
58
  const {result} = renderHook(() => useNavigateToStudioDocument(mockDocumentHandle))
66
59
 
67
- // Initially not connected
68
- expect(result.current.isConnected).toBe(false)
69
-
70
- // Simulate connection
71
- act(() => {
72
- mockStatusCallback?.('connected')
73
- })
74
-
75
60
  expect(result.current).toEqual({
76
61
  navigateToStudioDocument: expect.any(Function),
77
- isConnected: true,
78
62
  })
79
63
  })
80
64
 
81
65
  it('sends correct navigation message when called', () => {
82
66
  const {result} = renderHook(() => useNavigateToStudioDocument(mockDocumentHandle))
83
67
 
84
- // Simulate connection
85
- act(() => {
86
- mockStatusCallback?.('connected')
87
- })
88
-
89
68
  result.current.navigateToStudioDocument()
90
69
 
91
70
  expect(mockSendMessage).toHaveBeenCalledWith('dashboard/v1/bridge/navigate-to-resource', {
@@ -95,35 +74,10 @@ describe('useNavigateToStudioDocument', () => {
95
74
  })
96
75
  })
97
76
 
98
- it('does not send message when not connected', () => {
99
- mockWorkspacesByProjectIdAndDataset = {}
100
- mockWorkspacesIsConnected = false
101
-
102
- const {result} = renderHook(() => useNavigateToStudioDocument(mockDocumentHandle))
103
-
104
- // Simulate connection
105
- act(() => {
106
- mockStatusCallback?.('connected')
107
- })
108
-
109
- result.current.navigateToStudioDocument()
110
-
111
- expect(mockSendMessage).not.toHaveBeenCalled()
112
- })
113
-
114
77
  it('does not send message when no workspace is found', () => {
115
78
  mockWorkspacesByProjectIdAndDataset = {}
116
- mockWorkspacesIsConnected = true
117
-
118
79
  const {result} = renderHook(() => useNavigateToStudioDocument(mockDocumentHandle))
119
-
120
- // Simulate connection
121
- act(() => {
122
- mockStatusCallback?.('connected')
123
- })
124
-
125
80
  result.current.navigateToStudioDocument()
126
-
127
81
  expect(mockSendMessage).not.toHaveBeenCalled()
128
82
  })
129
83
 
@@ -137,11 +91,6 @@ describe('useNavigateToStudioDocument', () => {
137
91
 
138
92
  const {result} = renderHook(() => useNavigateToStudioDocument(mockDocumentHandle))
139
93
 
140
- // Simulate connection
141
- act(() => {
142
- mockStatusCallback?.('connected')
143
- })
144
-
145
94
  result.current.navigateToStudioDocument()
146
95
 
147
96
  expect(consoleSpy).toHaveBeenCalledWith(
@@ -169,11 +118,6 @@ describe('useNavigateToStudioDocument', () => {
169
118
 
170
119
  const {result} = renderHook(() => useNavigateToStudioDocument(incompleteDocumentHandle))
171
120
 
172
- // Simulate connection
173
- act(() => {
174
- mockStatusCallback?.('connected')
175
- })
176
-
177
121
  result.current.navigateToStudioDocument()
178
122
 
179
123
  expect(consoleSpy).toHaveBeenCalledWith(
@@ -194,11 +138,6 @@ describe('useNavigateToStudioDocument', () => {
194
138
 
195
139
  const {result} = renderHook(() => useNavigateToStudioDocument(mockDocumentHandle, preferredUrl))
196
140
 
197
- // Simulate connection
198
- act(() => {
199
- mockStatusCallback?.('connected')
200
- })
201
-
202
141
  result.current.navigateToStudioDocument()
203
142
 
204
143
  // Should choose workspace2 because it matches the preferred URL
@@ -227,11 +166,6 @@ describe('useNavigateToStudioDocument', () => {
227
166
 
228
167
  const {result} = renderHook(() => useNavigateToStudioDocument(mockDocumentHandle, preferredUrl))
229
168
 
230
- // Simulate connection
231
- act(() => {
232
- mockStatusCallback?.('connected')
233
- })
234
-
235
169
  result.current.navigateToStudioDocument()
236
170
 
237
171
  // Should choose the NO_PROJECT_ID:NO_DATASET workspace because it matches the preferred URL
@@ -259,11 +193,6 @@ describe('useNavigateToStudioDocument', () => {
259
193
 
260
194
  const {result} = renderHook(() => useNavigateToStudioDocument(mockDocumentHandle, preferredUrl))
261
195
 
262
- // Simulate connection
263
- act(() => {
264
- mockStatusCallback?.('connected')
265
- })
266
-
267
196
  result.current.navigateToStudioDocument()
268
197
 
269
198
  expect(consoleSpy).toHaveBeenCalledWith(
@@ -1,7 +1,6 @@
1
- import {type Status} from '@sanity/comlink'
2
1
  import {type Bridge, SDK_CHANNEL_NAME, SDK_NODE_NAME} from '@sanity/message-protocol'
3
2
  import {type DocumentHandle} from '@sanity/sdk'
4
- import {useCallback, useState} from 'react'
3
+ import {useCallback} from 'react'
5
4
 
6
5
  import {useWindowConnection} from '../comlink/useWindowConnection'
7
6
  import {
@@ -15,7 +14,6 @@ import {
15
14
  */
16
15
  export interface NavigateToStudioResult {
17
16
  navigateToStudioDocument: () => void
18
- isConnected: boolean
19
17
  }
20
18
 
21
19
  /**
@@ -38,16 +36,28 @@ export interface NavigateToStudioResult {
38
36
  * - `isConnected` - Boolean indicating if connection to Dashboard is established
39
37
  *
40
38
  * @example
41
- * ```ts
39
+ * ```tsx
42
40
  * import {useNavigateToStudioDocument, type DocumentHandle} from '@sanity/sdk-react'
41
+ * import {Button} from '@sanity/ui'
42
+ * import {Suspense} from 'react'
43
43
  *
44
- * function MyComponent({documentHandle}: {documentHandle: DocumentHandle}) {
44
+ * function NavigateButton({documentHandle}: {documentHandle: DocumentHandle}) {
45
45
  * const {navigateToStudioDocument, isConnected} = useNavigateToStudioDocument(documentHandle)
46
+ * return (
47
+ * <Button
48
+ * disabled={!isConnected}
49
+ * onClick={navigateToStudioDocument}
50
+ * text="Navigate to Studio Document"
51
+ * />
52
+ * )
53
+ * }
46
54
  *
55
+ * // Wrap the component with Suspense since the hook may suspend
56
+ * function MyDocumentAction({documentHandle}: {documentHandle: DocumentHandle}) {
47
57
  * return (
48
- * <button onClick={navigateToStudioDocument} disabled={!isConnected}>
49
- * Navigate to Studio Document
50
- * </button>
58
+ * <Suspense fallback={<Button text="Loading..." disabled />}>
59
+ * <NavigateButton documentHandle={documentHandle} />
60
+ * </Suspense>
51
61
  * )
52
62
  * }
53
63
  * ```
@@ -56,24 +66,15 @@ export function useNavigateToStudioDocument(
56
66
  documentHandle: DocumentHandle,
57
67
  preferredStudioUrl?: string,
58
68
  ): NavigateToStudioResult {
59
- const {workspacesByProjectIdAndDataset, isConnected: workspacesConnected} =
60
- useStudioWorkspacesByProjectIdDataset()
61
- const [status, setStatus] = useState<Status>('idle')
69
+ const {workspacesByProjectIdAndDataset} = useStudioWorkspacesByProjectIdDataset()
62
70
  const {sendMessage} = useWindowConnection<Bridge.Navigation.NavigateToResourceMessage, never>({
63
71
  name: SDK_NODE_NAME,
64
72
  connectTo: SDK_CHANNEL_NAME,
65
- onStatus: setStatus,
66
73
  })
67
74
 
68
75
  const navigateToStudioDocument = useCallback(() => {
69
76
  const {projectId, dataset} = documentHandle
70
77
 
71
- if (!workspacesConnected || status !== 'connected') {
72
- // eslint-disable-next-line no-console
73
- console.warn('Not connected to Dashboard')
74
- return
75
- }
76
-
77
78
  if (!projectId || !dataset) {
78
79
  // eslint-disable-next-line no-console
79
80
  console.warn('Project ID and dataset are required to navigate to a studio document')
@@ -123,17 +124,9 @@ export function useNavigateToStudioDocument(
123
124
  }
124
125
 
125
126
  sendMessage(message.type, message.data)
126
- }, [
127
- documentHandle,
128
- workspacesConnected,
129
- status,
130
- workspacesByProjectIdAndDataset,
131
- sendMessage,
132
- preferredStudioUrl,
133
- ])
127
+ }, [documentHandle, workspacesByProjectIdAndDataset, sendMessage, preferredStudioUrl])
134
128
 
135
129
  return {
136
130
  navigateToStudioDocument,
137
- isConnected: workspacesConnected && status === 'connected',
138
131
  }
139
132
  }
@@ -0,0 +1,69 @@
1
+ import {beforeEach, describe, expect, it, vi} from 'vitest'
2
+
3
+ import {renderHook} from '../../../test/test-utils'
4
+ import {useWindowConnection} from '../comlink/useWindowConnection'
5
+ import {useRecordDocumentHistoryEvent} from './useRecordDocumentHistoryEvent'
6
+
7
+ vi.mock('../comlink/useWindowConnection', () => ({
8
+ useWindowConnection: vi.fn(),
9
+ }))
10
+
11
+ describe('useRecordDocumentHistoryEvent', () => {
12
+ let mockSendMessage = vi.fn()
13
+ const mockDocumentHandle = {
14
+ documentId: 'mock-id',
15
+ documentType: 'mock-type',
16
+ resourceType: 'studio' as const,
17
+ resourceId: 'mock-resource-id',
18
+ }
19
+
20
+ beforeEach(() => {
21
+ mockSendMessage = vi.fn()
22
+ vi.mocked(useWindowConnection).mockImplementation(() => {
23
+ return {
24
+ sendMessage: mockSendMessage,
25
+ fetch: vi.fn(),
26
+ }
27
+ })
28
+ })
29
+
30
+ it('should send correct message when recording events', () => {
31
+ const {result} = renderHook(() => useRecordDocumentHistoryEvent(mockDocumentHandle))
32
+
33
+ result.current.recordEvent('viewed')
34
+ expect(mockSendMessage).toHaveBeenCalledWith('dashboard/v1/events/history', {
35
+ eventType: 'viewed',
36
+ document: {
37
+ id: 'mock-id',
38
+ type: 'mock-type',
39
+ resource: {
40
+ id: 'mock-resource-id',
41
+ type: 'studio',
42
+ },
43
+ },
44
+ })
45
+ })
46
+
47
+ it('should handle errors when sending messages', () => {
48
+ mockSendMessage.mockImplementation(() => {
49
+ throw new Error('Failed to send message')
50
+ })
51
+
52
+ const {result} = renderHook(() => useRecordDocumentHistoryEvent(mockDocumentHandle))
53
+
54
+ expect(() => result.current.recordEvent('viewed')).toThrow('Failed to send message')
55
+ })
56
+
57
+ it('should throw error when resourceId is missing for non-studio resources', () => {
58
+ const mockMediaDocumentHandle = {
59
+ documentId: 'mock-id',
60
+ documentType: 'mock-type',
61
+ resourceType: 'media-library' as const,
62
+ resourceId: undefined,
63
+ }
64
+
65
+ expect(() => renderHook(() => useRecordDocumentHistoryEvent(mockMediaDocumentHandle))).toThrow(
66
+ 'resourceId is required for media-library and canvas resources',
67
+ )
68
+ })
69
+ })
@@ -1,4 +1,3 @@
1
- import {type Status} from '@sanity/comlink'
2
1
  import {
3
2
  type CanvasResource,
4
3
  type Events,
@@ -8,13 +7,12 @@ import {
8
7
  type StudioResource,
9
8
  } from '@sanity/message-protocol'
10
9
  import {type DocumentHandle, type FrameMessage} from '@sanity/sdk'
11
- import {useCallback, useState} from 'react'
10
+ import {useCallback} from 'react'
12
11
 
13
- import {useWindowConnection} from './useWindowConnection'
12
+ import {useWindowConnection} from '../comlink/useWindowConnection'
14
13
 
15
14
  interface DocumentInteractionHistory {
16
15
  recordEvent: (eventType: 'viewed' | 'edited' | 'created' | 'deleted') => void
17
- isConnected: boolean
18
16
  }
19
17
 
20
18
  /**
@@ -42,7 +40,11 @@ interface UseRecordDocumentHistoryEventProps extends DocumentHandle {
42
40
  *
43
41
  * @example
44
42
  * ```tsx
45
- * function MyDocumentAction(props: DocumentActionProps) {
43
+ * import {useRecordDocumentHistoryEvent} from '@sanity/sdk-react'
44
+ * import {Button} from '@sanity/ui'
45
+ * import {Suspense} from 'react'
46
+ *
47
+ * function RecordEventButton(props: DocumentActionProps) {
46
48
  * const {documentId, documentType, resourceType, resourceId} = props
47
49
  * const {recordEvent, isConnected} = useRecordDocumentHistoryEvent({
48
50
  * documentId,
@@ -50,15 +52,23 @@ interface UseRecordDocumentHistoryEventProps extends DocumentHandle {
50
52
  * resourceType,
51
53
  * resourceId,
52
54
  * })
53
- *
54
55
  * return (
55
56
  * <Button
56
57
  * disabled={!isConnected}
57
58
  * onClick={() => recordEvent('viewed')}
58
- * text={'Viewed'}
59
+ * text="Viewed"
59
60
  * />
60
61
  * )
61
62
  * }
63
+ *
64
+ * // Wrap the component with Suspense since the hook may suspend
65
+ * function MyDocumentAction(props: DocumentActionProps) {
66
+ * return (
67
+ * <Suspense fallback={<Button text="Loading..." disabled />}>
68
+ * <RecordEventButton {...props} />
69
+ * </Suspense>
70
+ * )
71
+ * }
62
72
  * ```
63
73
  */
64
74
  export function useRecordDocumentHistoryEvent({
@@ -68,11 +78,9 @@ export function useRecordDocumentHistoryEvent({
68
78
  resourceId,
69
79
  schemaName,
70
80
  }: UseRecordDocumentHistoryEventProps): DocumentInteractionHistory {
71
- const [status, setStatus] = useState<Status>('idle')
72
81
  const {sendMessage} = useWindowConnection<Events.HistoryMessage, FrameMessage>({
73
82
  name: SDK_NODE_NAME,
74
83
  connectTo: SDK_CHANNEL_NAME,
75
- onStatus: setStatus,
76
84
  })
77
85
 
78
86
  if (resourceType !== 'studio' && !resourceId) {
@@ -110,6 +118,5 @@ export function useRecordDocumentHistoryEvent({
110
118
 
111
119
  return {
112
120
  recordEvent,
113
- isConnected: status === 'connected',
114
121
  }
115
122
  }
@@ -1,8 +1,7 @@
1
- import {type Message, type Status} from '@sanity/comlink'
2
1
  import {renderHook, waitFor} from '@testing-library/react'
3
2
  import {describe, expect, it, vi} from 'vitest'
4
3
 
5
- import {useWindowConnection, type WindowConnection} from '../comlink/useWindowConnection'
4
+ import {useWindowConnection} from '../comlink/useWindowConnection'
6
5
  import {useStudioWorkspacesByProjectIdDataset} from './useStudioWorkspacesByProjectIdDataset'
7
6
 
8
7
  vi.mock('../comlink/useWindowConnection', () => ({
@@ -54,49 +53,15 @@ describe('useStudioWorkspacesByResourceId', () => {
54
53
  vi.clearAllMocks()
55
54
  })
56
55
 
57
- it('should return empty workspaces and connected=false when not connected', async () => {
58
- // Create a mock that captures the onStatus callback
59
- let capturedOnStatus: ((status: Status) => void) | undefined
60
-
61
- vi.mocked(useWindowConnection).mockImplementation(({onStatus}) => {
62
- capturedOnStatus = onStatus
63
-
64
- return {
65
- fetch: undefined,
66
- sendMessage: vi.fn(),
67
- } as unknown as WindowConnection<Message>
68
- })
69
-
70
- const {result} = renderHook(() => useStudioWorkspacesByProjectIdDataset())
71
-
72
- // Call onStatus with 'idle' to simulate not connected
73
- if (capturedOnStatus) capturedOnStatus('idle')
74
-
75
- expect(result.current).toEqual({
76
- workspacesByProjectIdAndDataset: {},
77
- error: null,
78
- isConnected: false,
79
- })
80
- })
81
-
82
56
  it('should process workspaces into lookup by projectId:dataset', async () => {
83
57
  const mockFetch = vi.fn().mockResolvedValue(mockWorkspaceData)
84
- let capturedOnStatus: ((status: Status) => void) | undefined
85
-
86
- vi.mocked(useWindowConnection).mockImplementation(({onStatus}) => {
87
- capturedOnStatus = onStatus
88
-
89
- return {
90
- fetch: mockFetch,
91
- sendMessage: vi.fn(),
92
- } as unknown as WindowConnection<Message>
58
+ vi.mocked(useWindowConnection).mockReturnValue({
59
+ fetch: mockFetch,
60
+ sendMessage: vi.fn(),
93
61
  })
94
62
 
95
63
  const {result} = renderHook(() => useStudioWorkspacesByProjectIdDataset())
96
64
 
97
- // Call onStatus with 'connected' to simulate connected state
98
- if (capturedOnStatus) capturedOnStatus('connected')
99
-
100
65
  await waitFor(() => {
101
66
  expect(result.current.workspacesByProjectIdAndDataset).toEqual({
102
67
  'project1:dataset1': [
@@ -138,38 +103,23 @@ describe('useStudioWorkspacesByResourceId', () => {
138
103
  ],
139
104
  })
140
105
  expect(result.current.error).toBeNull()
141
- expect(result.current.isConnected).toBe(true)
142
106
  })
143
107
 
144
- expect(mockFetch).toHaveBeenCalledWith(
145
- 'dashboard/v1/bridge/context',
146
- undefined,
147
- expect.any(Object),
148
- )
108
+ expect(mockFetch).toHaveBeenCalledWith('dashboard/v1/context', undefined, expect.any(Object))
149
109
  })
150
110
 
151
111
  it('should handle fetch errors', async () => {
152
112
  const mockFetch = vi.fn().mockRejectedValue(new Error('Failed to fetch'))
153
- let capturedOnStatus: ((status: Status) => void) | undefined
154
-
155
- vi.mocked(useWindowConnection).mockImplementation(({onStatus}) => {
156
- capturedOnStatus = onStatus
157
-
158
- return {
159
- fetch: mockFetch,
160
- sendMessage: vi.fn(),
161
- } as unknown as WindowConnection<Message>
113
+ vi.mocked(useWindowConnection).mockReturnValue({
114
+ fetch: mockFetch,
115
+ sendMessage: vi.fn(),
162
116
  })
163
117
 
164
118
  const {result} = renderHook(() => useStudioWorkspacesByProjectIdDataset())
165
119
 
166
- // Call onStatus with 'connected' to simulate connected state
167
- if (capturedOnStatus) capturedOnStatus('connected')
168
-
169
120
  await waitFor(() => {
170
121
  expect(result.current.workspacesByProjectIdAndDataset).toEqual({})
171
122
  expect(result.current.error).toBe('Failed to fetch workspaces')
172
- expect(result.current.isConnected).toBe(true)
173
123
  })
174
124
  })
175
125
 
@@ -177,26 +127,16 @@ describe('useStudioWorkspacesByResourceId', () => {
177
127
  const abortError = new Error('Aborted')
178
128
  abortError.name = 'AbortError'
179
129
  const mockFetch = vi.fn().mockRejectedValue(abortError)
180
- let capturedOnStatus: ((status: Status) => void) | undefined
181
-
182
- vi.mocked(useWindowConnection).mockImplementation(({onStatus}) => {
183
- capturedOnStatus = onStatus
184
-
185
- return {
186
- fetch: mockFetch,
187
- sendMessage: vi.fn(),
188
- } as unknown as WindowConnection<Message>
130
+ vi.mocked(useWindowConnection).mockReturnValue({
131
+ fetch: mockFetch,
132
+ sendMessage: vi.fn(),
189
133
  })
190
134
 
191
135
  const {result} = renderHook(() => useStudioWorkspacesByProjectIdDataset())
192
136
 
193
- // Call onStatus with 'connected' to simulate connected state
194
- if (capturedOnStatus) capturedOnStatus('connected')
195
-
196
137
  await waitFor(() => {
197
138
  expect(result.current.workspacesByProjectIdAndDataset).toEqual({})
198
139
  expect(result.current.error).toBeNull()
199
- expect(result.current.isConnected).toBe(true)
200
140
  })
201
141
  })
202
142
 
@@ -248,24 +188,14 @@ describe('useStudioWorkspacesByResourceId', () => {
248
188
  ],
249
189
  },
250
190
  }
251
-
252
191
  const mockFetch = vi.fn().mockResolvedValue(mockDataWithMixedResources)
253
- let capturedOnStatus: ((status: Status) => void) | undefined
254
-
255
- vi.mocked(useWindowConnection).mockImplementation(({onStatus}) => {
256
- capturedOnStatus = onStatus
257
-
258
- return {
259
- fetch: mockFetch,
260
- sendMessage: vi.fn(),
261
- } as unknown as WindowConnection<Message>
192
+ vi.mocked(useWindowConnection).mockReturnValue({
193
+ fetch: mockFetch,
194
+ sendMessage: vi.fn(),
262
195
  })
263
196
 
264
197
  const {result} = renderHook(() => useStudioWorkspacesByProjectIdDataset())
265
198
 
266
- // Call onStatus with 'connected' to simulate connected state
267
- if (capturedOnStatus) capturedOnStatus('connected')
268
-
269
199
  await waitFor(() => {
270
200
  // Should only include the studio resource with valid projectId and dataset
271
201
  expect(result.current.workspacesByProjectIdAndDataset['project1:dataset1']).toHaveLength(1)
@@ -285,7 +215,6 @@ describe('useStudioWorkspacesByResourceId', () => {
285
215
  ).toEqual(['studio-no-project', 'studio-no-dataset'])
286
216
 
287
217
  expect(result.current.error).toBeNull()
288
- expect(result.current.isConnected).toBe(true)
289
218
  })
290
219
  })
291
220
  })