Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(visual-editing): execute fetches after node connect event #2308

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 27 additions & 19 deletions packages/comlink/src/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
assertEvent,
assign,
createActor,
emit,
enqueueActions,
fromCallback,
raise,
Expand All @@ -29,8 +30,10 @@ import type {
Message,
MessageEmitEvent,
ProtocolMessage,
ReceivedEmitEvent,
RequestData,
Status,
StatusEmitEvent,
WithoutResponse,
} from './types'

Expand Down Expand Up @@ -61,7 +64,7 @@ export type Connection<S extends Message = Message, R extends Message = Message>
type: T,
handler: (event: U['data']) => Promise<U['response']> | U['response'],
) => () => void
onStatus: (handler: (status: Status) => void) => () => void
onStatus: (handler: (status: Status) => void, filter?: Status) => () => void
post: <T extends S['type'], U extends Extract<S, {type: T}>>(
...params: (U['data'] extends undefined ? [T] : never) | [T, U['data']]
) => void
Expand Down Expand Up @@ -136,7 +139,8 @@ export const createConnectionMachine = <
| BufferAddedEmitEvent<V>
| BufferFlushedEmitEvent<V>
| MessageEmitEvent<R>
| (R extends R ? {type: R['type']; message: ProtocolMessage<R>} : never)
| ReceivedEmitEvent<R>
| StatusEmitEvent
events:
| {type: 'connect'}
| {type: 'disconnect'}
Expand Down Expand Up @@ -220,6 +224,12 @@ export const createConnectionMachine = <
return emit
})
}),
'emit status': emit((_, params: {status: Status}) => {
return {
type: '_status',
status: params.status,
} satisfies StatusEmitEvent
}),
'flush buffer': enqueueActions(({enqueue}) => {
enqueue.raise(({context}) => ({
type: 'request',
Expand Down Expand Up @@ -316,6 +326,7 @@ export const createConnectionMachine = <
initial: 'idle',
states: {
idle: {
entry: [{type: 'emit status', params: {status: 'idle'}}],
on: {
connect: {
target: 'handshaking',
Expand All @@ -328,6 +339,7 @@ export const createConnectionMachine = <
},
handshaking: {
id: 'handshaking',
entry: [{type: 'emit status', params: {status: 'handshaking'}}],
invoke: [
{
id: 'send syn',
Expand Down Expand Up @@ -375,7 +387,7 @@ export const createConnectionMachine = <
exit: 'send handshake ack',
},
connected: {
entry: 'flush buffer',
entry: ['flush buffer', {type: 'emit status', params: {status: 'connected'}}],
invoke: {
id: 'listen for messages',
src: 'listen',
Expand Down Expand Up @@ -433,7 +445,7 @@ export const createConnectionMachine = <
},
disconnected: {
id: 'disconnected',
entry: 'send disconnect',
entry: ['send disconnect', {type: 'emit status', params: {status: 'disconnected'}}],
on: {
request: {
actions: 'create request',
Expand Down Expand Up @@ -490,21 +502,17 @@ export const createConnection = <S extends Message, R extends Message>(
actor.send({type: 'disconnect'})
}

const onStatus = (handler: (status: Status) => void) => {
const currentSnapshot = actor.getSnapshot()
let currentStatus: Status =
typeof currentSnapshot.value === 'string'
? currentSnapshot.value
: Object.keys(currentSnapshot.value)[0]

const {unsubscribe} = actor.subscribe((state) => {
const status: Status =
typeof state.value === 'string' ? state.value : Object.keys(state.value)[0]
if (currentStatus !== status) {
currentStatus = status
handler(status)
}
})
const onStatus = (handler: (status: Status) => void, filter?: Status) => {
const {unsubscribe} = actor.on(
// @ts-expect-error @todo ReceivedEmitEvent causes this
'_status',
(event: StatusEmitEvent & {status: Status}) => {
if (filter && event.status !== filter) {
return
}
handler(event.status)
},
)
return unsubscribe
}

Expand Down
2 changes: 2 additions & 0 deletions packages/comlink/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,11 @@ export type {
MessageEmitEvent,
MessageType,
ProtocolMessage,
ReceivedEmitEvent,
RequestData,
ResponseMessage,
Status,
StatusEmitEvent,
StatusEvent,
WithoutResponse,
} from './types'
54 changes: 36 additions & 18 deletions packages/comlink/src/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ import type {
Message,
MessageEmitEvent,
ProtocolMessage,
ReceivedEmitEvent,
RequestData,
Status,
StatusEmitEvent,
WithoutResponse,
} from './types'

Expand Down Expand Up @@ -72,7 +74,10 @@ export type Node<S extends Message, R extends Message> = {
type: T,
handler: (event: U['data']) => U['response'],
) => () => void
onStatus: (handler: (status: Status) => void) => () => void
onStatus: (
handler: (status: Omit<Status, 'disconnected'>) => void,
filter?: Omit<Status, 'disconnected'>,
) => () => void
post: <T extends S['type'], U extends Extract<S, {type: T}>>(
...params: (U['data'] extends undefined ? [T] : never) | [T, U['data']]
) => void
Expand Down Expand Up @@ -128,7 +133,8 @@ export const createNodeMachine = <
| BufferFlushedEmitEvent<V>
| HeartbeatEmitEvent
| MessageEmitEvent<R>
| (R extends R ? {type: R['type']; message: ProtocolMessage<R>} : never)
| ReceivedEmitEvent<R>
| (StatusEmitEvent & {status: Omit<Status, 'disconnected'>})
events:
| {type: 'heartbeat.received'; message: MessageEvent<ProtocolMessage<HeartbeatMessage>>}
| {type: 'message.received'; message: MessageEvent<ProtocolMessage<R>>}
Expand Down Expand Up @@ -239,6 +245,12 @@ export const createNodeMachine = <
return emit
})
}),
'emit status': emit((_, params: {status: Exclude<Status, 'disconnected'>}) => {
return {
type: '_status',
status: params.status,
} satisfies StatusEmitEvent & {status: Omit<Status, 'disconnected'>}
}),
'flush buffer': enqueueActions(({enqueue}) => {
enqueue.raise(({context}) => ({
type: 'request',
Expand Down Expand Up @@ -360,6 +372,7 @@ export const createNodeMachine = <
initial: 'idle',
states: {
idle: {
entry: [{type: 'emit status', params: {status: 'idle'}}],
on: {
post: {
actions: 'buffer message',
Expand All @@ -368,7 +381,7 @@ export const createNodeMachine = <
},
handshaking: {
guard: 'hasSource',
entry: 'send handshake syn ack',
entry: ['send handshake syn ack', {type: 'emit status', params: {status: 'handshaking'}}],
invoke: [
{
id: 'listen for handshake ack',
Expand Down Expand Up @@ -422,7 +435,11 @@ export const createNodeMachine = <
},
},
connected: {
entry: ['flush handshake buffer', 'flush buffer'],
entry: [
'flush handshake buffer',
'flush buffer',
{type: 'emit status', params: {status: 'connected'}},
],
invoke: [
{
id: 'listen for messages',
Expand Down Expand Up @@ -494,7 +511,7 @@ export const createNode = <S extends Message, R extends Message>(
handler: (event: U['data']) => U['response'],
) => {
const {unsubscribe} = actor.on(
// @ts-expect-error @todo `type` typing
// @ts-expect-error @todo ReceivedEmitEvent causes this
type,
(event: {type: T; message: ProtocolMessage<U>}) => {
handler(event.message.data)
Expand All @@ -503,19 +520,20 @@ export const createNode = <S extends Message, R extends Message>(
return unsubscribe
}

const onStatus = (handler: (status: Status) => void) => {
const snapshot = actor.getSnapshot()
let currentStatus: Status =
typeof snapshot.value === 'string' ? snapshot.value : Object.keys(snapshot.value)[0]

const {unsubscribe} = actor.subscribe((state) => {
const status: Status =
typeof state.value === 'string' ? state.value : Object.keys(state.value)[0]
if (currentStatus !== status) {
currentStatus = status
handler(status)
}
})
const onStatus = (
handler: (status: Omit<Status, 'disconnected'>) => void,
filter?: Omit<Status, 'disconnected'>,
) => {
const {unsubscribe} = actor.on(
// @ts-expect-error @todo ReceivedEmitEvent causes this
'_status',
(event: StatusEmitEvent & {status: Omit<Status, 'disconnected'>}) => {
if (filter && event.status !== filter) {
return
}
handler(event.status)
},
)
return unsubscribe
}

Expand Down
15 changes: 14 additions & 1 deletion packages/comlink/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
/**
* @public
*/
export type Status = string // @todo strongly type these
export type Status = 'idle' | 'handshaking' | 'connected' | 'disconnected'

/**
* @public
Expand Down Expand Up @@ -102,13 +102,26 @@ export interface MessageEmitEvent<T extends Message> {
message: ProtocolMessage<T>
}

/**
* @public
*/
export interface StatusEmitEvent {
type: '_status'
status: Status
}

export type ReceivedEmitEvent<T extends Message> = T extends T
? {type: T['type']; message: ProtocolMessage<T>}
: never

/**
* @public
*/
export type InternalEmitEvent<S extends Message, R extends Message> =
| BufferAddedEmitEvent<S>
| BufferFlushedEmitEvent<R>
| MessageEmitEvent<R>
| StatusEmitEvent

/**
* @public
Expand Down
1 change: 1 addition & 0 deletions packages/presentation/src/PresentationTool.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ export default function PresentationTool(props: {
)
})

// @todo This won't work for multiple window contexts?
comlink.on('visual-editing/refreshing', (data) => {
if (data.source === 'manual') {
clearTimeout(refreshRef.current)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import type {Status} from '@sanity/comlink'
import {memo, startTransition, useEffect, useMemo, useState} from 'react'
import {type SanityDocument} from 'sanity'
import {getPublishedId, useEditState} from '../internals'
import type {VisualEditingConnection} from '../types'
import type {ConnectionStatus, VisualEditingConnection} from '../types'

export interface PostMessageRefreshMutationsProps {
id: string
type: string
comlink: VisualEditingConnection
previewKitConnection: Status
loadersConnection: Status
previewKitConnection: ConnectionStatus
loadersConnection: ConnectionStatus
}

function PostMessageRefreshMutations(props: PostMessageRefreshMutationsProps): React.ReactNode {
Expand Down
1 change: 1 addition & 0 deletions packages/presentation/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from './plugin'
export type {
CombinedSearchParams,
ConnectionStatus,
ContextFn,
DocumentLocation,
DocumentLocationResolver,
Expand Down
15 changes: 8 additions & 7 deletions packages/presentation/src/preview/Preview.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type {Status} from '@sanity/comlink'
import {
Button,
Card,
Expand Down Expand Up @@ -34,7 +33,12 @@ import {
type DispatchPresentationAction,
type PresentationState,
} from '../reducers/presentationReducer'
import type {HeaderOptions, PresentationPerspective, PresentationViewport} from '../types'
import type {
ConnectionStatus,
HeaderOptions,
PresentationPerspective,
PresentationViewport,
} from '../types'
import {usePresentationTool} from '../usePresentationTool'
import {IFrame} from './IFrame'
import {usePresentationPreviewHeader} from './PreviewHeader'
Expand All @@ -48,12 +52,12 @@ export interface PreviewProps extends Pick<PresentationState, 'iframe' | 'visual
dispatch: DispatchPresentationAction
header?: HeaderOptions
initialUrl: URL
loadersConnection: Status
loadersConnection: ConnectionStatus
navigatorEnabled: boolean
onPathChange: (nextPath: string) => void
onRefresh: (fallback: () => void) => void
openPopup: (url: string) => void
overlaysConnection: Status
overlaysConnection: ConnectionStatus
perspective: PresentationPerspective
previewUrl?: string
setPerspective: (perspective: 'previewDrafts' | 'published') => void
Expand Down Expand Up @@ -148,9 +152,6 @@ export const Preview = memo(
}, MAX_TIME_TO_OVERLAYS_CONNECTION)
return () => clearTimeout(timeout)
}
if (overlaysConnection === 'disconnected') {
setSomethingIsWrong(true)
}
return
}, [loading, overlaysConnection, refreshing, showOverlaysConnectionStatus])

Expand Down
2 changes: 2 additions & 0 deletions packages/presentation/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -301,3 +301,5 @@ export type VisualEditingConnection = ChannelInstance<
* @internal
*/
export type LoaderConnection = ChannelInstance<LoaderControllerMsg, LoaderNodeMsg>

export type ConnectionStatus = 'connected' | 'connecting' | 'reconnecting' | 'idle'
Loading
Loading