Skip to content

Commit

Permalink
✨ [RUMF-1396] add a Disconnect alert
Browse files Browse the repository at this point in the history
With Manifest V3, connection between the devtools panel and the
background service worker can be lost when the service worker is
refreshed. I experienced it very often while working on the extension
(every time I changed the background script). To help UX/DX, this commit
adds an alert to allow refreshing easily the devtools panel.
  • Loading branch information
BenoitZugmeyer committed Nov 18, 2022
1 parent c1e8ef4 commit 308b331
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 19 deletions.
2 changes: 1 addition & 1 deletion developer-extension/src/background/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ import { createListenAction, createSendAction } from '../common/actions'
import type { BackgroundActions, PopupActions } from '../common/types'

export const listenAction = createListenAction<BackgroundActions>()
export const sendAction = createSendAction<PopupActions>()
export const sendAction = createSendAction<PopupActions>().sendAction
39 changes: 27 additions & 12 deletions developer-extension/src/common/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ type Message<Actions extends { [key: string]: any }> = ValueOf<{
}
}>

export function createListenAction<Actions>() {
export function createListenAction<Actions extends { [key: string]: any }>() {
function listenAction<K extends keyof Actions>(
action: K,
callback: (payload: Actions[K], tabId: number | undefined) => void
Expand All @@ -27,18 +27,33 @@ export function createListenAction<Actions>() {
}

export function createSendAction<Actions>() {
let onDisconnect: (() => void) | undefined

function sendAction<K extends keyof Actions>(action: K, payload: Actions[K]) {
return chrome.runtime.sendMessage({ action, payload }, () => {
const error = chrome.runtime.lastError
if (
error &&
error.message !== 'Could not establish connection. Receiving end does not exist.' &&
error.message !== 'The message port closed before a response was received.'
) {
console.error(`sendAction error: ${String(error.message)}`)
}
})
try {
chrome.runtime.sendMessage({ action, payload }).catch(handleError)
} catch (error) {
handleError(error)
}
}

function handleError(error: any) {
const message = typeof error === 'object' && error !== null ? String(error.message) : '(no message)'

if (onDisconnect && message === 'Extension context invalidated.') {
onDisconnect()
} else if (
message !== 'Could not establish connection. Receiving end does not exist.' &&
message !== 'The message port closed before a response was received.'
) {
console.error(`sendAction error: ${message}`)
}
}

return sendAction
return {
sendAction,
setOnDisconnect: (newOnDisconnect: () => void) => {
onDisconnect = newOnDisconnect
},
}
}
3 changes: 2 additions & 1 deletion developer-extension/src/panel/actions.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { createListenAction, createSendAction } from '../common/actions'
import type { BackgroundActions, PopupActions } from '../common/types'

export const sendAction = createSendAction<BackgroundActions>()
const { sendAction, setOnDisconnect } = createSendAction<BackgroundActions>()
export { sendAction, setOnDisconnect }
export const listenAction = createListenAction<PopupActions>()
31 changes: 26 additions & 5 deletions developer-extension/src/panel/app.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { MantineProvider } from '@mantine/core'
import { Alert, Button, Center, Group, MantineProvider } from '@mantine/core'
import { useColorScheme } from '@mantine/hooks'
import React, { Suspense } from 'react'
import React, { Suspense, useState } from 'react'
import { setOnDisconnect } from './actions'

import { Panel } from './panel'

export function App() {
const colorScheme = useColorScheme()
const [isDisconnected, setIsDisconnected] = useState(false)

setOnDisconnect(() => setIsDisconnected(true))

return (
<MantineProvider
Expand All @@ -14,9 +18,26 @@ export function App() {
}}
withGlobalStyles
>
<Suspense fallback={<></>}>
<Panel />
</Suspense>
<Suspense fallback={<></>}>{isDisconnected ? <DisconnectAlert /> : <Panel />}</Suspense>
</MantineProvider>
)
}

function DisconnectAlert() {
return (
<Center
sx={{
height: '100vh',
}}
>
<Alert title="Extension disconnected!" color="red">
The extension has been disconnected. This can happen after an update.
<Group position="right">
<Button onClick={() => location.reload()} color="red">
Reload extension
</Button>
</Group>
</Alert>
</Center>
)
}

0 comments on commit 308b331

Please sign in to comment.