diff --git a/src/node/StreamWindow.js b/src/node/StreamWindow.js
index afb6c25..b7bf919 100644
--- a/src/node/StreamWindow.js
+++ b/src/node/StreamWindow.js
@@ -216,16 +216,25 @@ export default class StreamWindow extends EventEmitter {
}
}
- reloadView(viewIdx) {
- const view = this.views.find(
+ findViewByIdx(viewIdx, predicate) {
+ return this.views.find(
(v) =>
v.state.context.pos && v.state.context.pos.spaces.includes(viewIdx),
)
+ }
+
+ reloadView(viewIdx) {
+ const view = this.findViewByIdx(viewIdx)
if (view) {
view.send('RELOAD')
}
}
+ openDevTools(viewIdx, inWebContents) {
+ const view = this.findViewByIdx(viewIdx)
+ view.send({ type: 'DEVTOOLS', inWebContents })
+ }
+
send(...args) {
this.overlayView.webContents.send(...args)
}
diff --git a/src/node/index.js b/src/node/index.js
index c5bb3c8..5f84006 100644
--- a/src/node/index.js
+++ b/src/node/index.js
@@ -90,8 +90,16 @@ async function main() {
broadcastState(clientState)
} else if (msg.type === 'reload-view') {
streamWindow.reloadView(msg.viewIdx)
- } else if (msg.type === 'browse') {
- ensureValidURL(msg.url)
+ } else if (msg.type === 'browse' || msg.type === 'dev-tools') {
+ if (
+ msg.type === 'dev-tools' &&
+ browseWindow &&
+ !browseWindow.isDestroyed()
+ ) {
+ // DevTools needs a fresh webContents to work. Close any existing window.
+ browseWindow.destroy()
+ browseWindow = null
+ }
if (!browseWindow || browseWindow.isDestroyed()) {
browseWindow = new BrowserWindow({
webPreferences: {
@@ -102,7 +110,12 @@ async function main() {
},
})
}
- browseWindow.loadURL(msg.url)
+ if (msg.type === 'browse') {
+ ensureValidURL(msg.url)
+ browseWindow.loadURL(msg.url)
+ } else if (msg.type === 'dev-tools') {
+ streamWindow.openDevTools(msg.viewIdx, browseWindow.webContents)
+ }
}
}
diff --git a/src/node/viewStateMachine.js b/src/node/viewStateMachine.js
index 58d0e27..f6370de 100644
--- a/src/node/viewStateMachine.js
+++ b/src/node/viewStateMachine.js
@@ -81,6 +81,9 @@ const viewStateMachine = Machine(
},
MUTE: '.muted',
UNMUTE: '.listening',
+ DEVTOOLS: {
+ actions: 'openDevTools',
+ },
},
states: {
muted: {
@@ -109,6 +112,12 @@ const viewStateMachine = Machine(
unmuteAudio: (context, event) => {
context.view.webContents.audioMuted = false
},
+ openDevTools: (context, event) => {
+ const { view } = context
+ const { inWebContents } = event
+ view.webContents.setDevToolsWebContents(inWebContents)
+ view.webContents.openDevTools({ mode: 'detach' })
+ },
},
guards: {
contentUnchanged: (context, event) => {
diff --git a/src/web/control.js b/src/web/control.js
index cee451c..7269eed 100644
--- a/src/web/control.js
+++ b/src/web/control.js
@@ -10,6 +10,7 @@ import { GRID_COUNT } from '../constants'
import SoundIcon from '../static/volume-up-solid.svg'
import ReloadIcon from '../static/redo-alt-solid.svg'
import LifeRingIcon from '../static/life-ring-regular.svg'
+import WindowIcon from '../static/window-maximize-regular.svg'
function App({ wsEndpoint }) {
const wsRef = useRef()
@@ -119,6 +120,15 @@ function App({ wsEndpoint }) {
)
}, [])
+ const handleDevTools = useCallback((idx) => {
+ wsRef.current.send(
+ JSON.stringify({
+ type: 'dev-tools',
+ viewIdx: idx,
+ }),
+ )
+ }, [])
+
const handleClickId = useCallback((streamId) => {
const availableIdx = range(GRID_COUNT * GRID_COUNT).find(
(i) => !stateIdxMap.has(i),
@@ -171,6 +181,7 @@ function App({ wsEndpoint }) {
onSetListening={handleSetListening}
onReloadView={handleReloadView}
onBrowse={handleBrowse}
+ onDevTools={handleDevTools}
/>
)
})}
@@ -247,6 +258,7 @@ function GridInput({
onSetListening,
onReloadView,
onBrowse,
+ onDevTools,
}) {
const [editingValue, setEditingValue] = useState()
const handleFocus = useCallback((ev) => {
@@ -272,6 +284,10 @@ function GridInput({
onReloadView,
])
const handleBrowseClick = useCallback(() => onBrowse(url), [url, onBrowse])
+ const handleDevToolsClick = useCallback(() => onDevTools(idx), [
+ idx,
+ onDevTools,
+ ])
const handleClick = useCallback((ev) => {
ev.target.select()
})
@@ -283,6 +299,9 @@ function GridInput({
+
+
+