Rudder learns whether this server should have an engine even when its event stream is buffered; the legend bar keeps its rounded ends
The dev backend answers /status with the same offline status as /events, and Rudder reads it on mount and whenever the event stream drops, so a proxy that buffers the stream no longer leaves it saying "Runs on your computer" on a server that should run the engine. The local-microphone notice no longer shows off this computer. The legend progress bar paints its grey band as a rounded strip and rounds the first and last segment, which the 24px touch targets had squared off.
This commit is contained in:
parent
8e267b0ce5
commit
55573df1d2
3 changed files with 23 additions and 4 deletions
|
|
@ -88,12 +88,18 @@ export function backendDevPlugin(root) {
|
|||
for (const b of DEV_BACKENDS) {
|
||||
server.middlewares.use(b.route, (req, res, next) => {
|
||||
if (isAlive(b.name)) return next()
|
||||
const status = { engine: 'offline', expected: !!(b.expected && b.expected()), error: 'The desktop engine is not running.' }
|
||||
if ((req.url || '').startsWith('/events')) {
|
||||
res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', Connection: 'keep-alive' })
|
||||
const expected = !!(b.expected && b.expected())
|
||||
res.write(`data: ${JSON.stringify({ type: 'status', status: { engine: 'offline', expected, error: 'The desktop engine is not running.' } })}\n\n`)
|
||||
res.write(`data: ${JSON.stringify({ type: 'status', status })}\n\n`)
|
||||
return // held open, so the EventSource does not reconnect in a loop
|
||||
}
|
||||
// /status answers the same, for a page whose event stream cannot get through (a proxy that buffers).
|
||||
if ((req.url || '').startsWith('/status')) {
|
||||
res.writeHead(200, { 'Content-Type': 'application/json' })
|
||||
res.end(JSON.stringify(status))
|
||||
return
|
||||
}
|
||||
res.writeHead(200, { 'Content-Type': 'application/json' })
|
||||
res.end('[]')
|
||||
})
|
||||
|
|
|
|||
|
|
@ -71,7 +71,13 @@ useShadowStyles(`
|
|||
tall so each segment button is a 24px target, but it paints only a 10px band: the track's background is
|
||||
a centred 10px strip and each segment clips its colour to its content box inside 7px of padding. The
|
||||
-7px margins keep the legend's layout exactly 10px tall, as before. */
|
||||
.lpb-track{position:relative;flex:1 1 auto;min-width:60px;display:flex;height:24px;margin:-7px 0;overflow:hidden;background:linear-gradient(rgba(110,118,129,0.25),rgba(110,118,129,0.25)) center/100% 10px no-repeat;}
|
||||
.lpb-track{position:relative;flex:1 1 auto;min-width:60px;display:flex;height:24px;margin:-7px 0;overflow:hidden;}
|
||||
/* The grey band, rounded, under the segments; the first and last segment round the bar's two ends (an
|
||||
elliptical radius 5px/12px leaves a 5px curve on the 10px painted band inside the 7px padding). */
|
||||
.lpb-track::before{content:'';position:absolute;left:0;right:0;top:7px;height:10px;border-radius:5px;background:rgba(110,118,129,0.25);}
|
||||
.lpb-seg{position:relative;}
|
||||
.lpb-span:first-child .lpb-seg:first-child{border-top-left-radius:5px 12px;border-bottom-left-radius:5px 12px;}
|
||||
.lpb-seg-rest,.lpb-span:last-child .lpb-seg:last-child{border-top-right-radius:5px 12px;border-bottom-right-radius:5px 12px;}
|
||||
.lpb-span{display:flex;height:100%;min-width:0;flex:0 0 auto;}
|
||||
.lpb-seg{appearance:none;-webkit-appearance:none;border:none;margin:0;padding:7px 0;box-sizing:border-box;background-clip:content-box !important;height:100%;display:block;flex:0 0 auto;cursor:pointer;outline:none;-webkit-tap-highlight-color:transparent;transition:filter 0.12s,box-shadow 0.12s;}
|
||||
.lpb-seg-rest{flex:1 1 auto;}
|
||||
|
|
|
|||
|
|
@ -308,6 +308,7 @@ function connect() {
|
|||
engine.value = 'offline'
|
||||
if (audioMode.value !== 'browser') recording.value = false
|
||||
logc('events disconnected; retrying in 3s')
|
||||
fetchStatus()
|
||||
try { es.close() } catch {}
|
||||
retry = setTimeout(connect, 3000)
|
||||
}
|
||||
|
|
@ -544,7 +545,13 @@ function onKey(ev) {
|
|||
if (ev.ctrlKey && ev.shiftKey && ev.code === 'Space') { ev.preventDefault(); toggle() }
|
||||
}
|
||||
|
||||
// The status also by plain request: a proxy that buffers the event stream (rega's harness did) must not
|
||||
// leave the page guessing whether this server is meant to have an engine.
|
||||
async function fetchStatus() {
|
||||
try { const r = await fetch(apiBase.value + '/status'); if (r.ok) applyStatus(await r.json()) } catch {}
|
||||
}
|
||||
onMounted(() => {
|
||||
fetchStatus()
|
||||
connect()
|
||||
refreshDevices()
|
||||
window.addEventListener('keydown', onKey)
|
||||
|
|
@ -675,7 +682,7 @@ const statusText = computed(() => ({
|
|||
</p>
|
||||
<p v-if="chosen && chosen.muted" class="notice" data-kind="warn">“{{ chosen.label }}” is muted in your system sound settings — Rudder won't hear anything until it's unmuted.</p>
|
||||
<p v-if="deviceError && audioMode !== 'browser'" class="notice" data-kind="error">{{ deviceError }}</p>
|
||||
<p v-else-if="!devices.length && engine !== 'offline' && audioMode !== 'browser'" class="notice" data-kind="warn">No microphone found. Connect a headset or turn on your computer's microphone in Sound settings.</p>
|
||||
<p v-else-if="!devices.length && engine !== 'offline' && audioMode !== 'browser' && onOwnComputer" class="notice" data-kind="warn">No microphone found. Connect a headset or turn on your computer's microphone in Sound settings.</p>
|
||||
<p v-if="offCards.length" class="hint">Also available but switched off in Sound settings: {{ offCards.join(', ') }}. Turn it on there to use it here.</p>
|
||||
|
||||
<p v-if="notice" class="notice" :data-kind="noticeKind">{{ notice }}</p>
|
||||
|
|
|
|||
Loading…
Reference in a new issue