This commit is contained in:
Chris Wanstrath 2026-01-27 21:52:30 -08:00
parent 5aca98fc58
commit d76d5ed50d
4 changed files with 27 additions and 6 deletions

View File

@ -305,10 +305,19 @@ const AppDetail = ({ app }: { app: App }) => (
<Section>
<SectionTitle>Logs</SectionTitle>
<LogsContainer>
{app.logs?.length ? (
app.logs.map((line, i) => (
<LogLine key={i}>
<LogTime>{new Date(line.time).toLocaleTimeString()}</LogTime>
<span>{line.text}</span>
</LogLine>
))
) : (
<LogLine>
<LogTime>--:--:--</LogTime>
<span style={{ color: '#666' }}>No logs yet</span>
</LogLine>
)}
</LogsContainer>
</Section>

View File

@ -1,11 +1,12 @@
import type { Subprocess } from 'bun'
import { existsSync, readdirSync, readFileSync, watch } from 'fs'
import { join } from 'path'
import type { App as SharedApp, AppState } from '../shared/types'
import type { App as SharedApp, AppState, LogLine } from '../shared/types'
export type { AppState } from '../shared/types'
const APPS_DIR = join(process.env.DATA_DIR ?? '.', 'apps')
const MAX_LOGS = 100
export type App = SharedApp & {
proc?: Subprocess
@ -96,6 +97,7 @@ const runApp = async (dir: string, port: number) => {
// Set state to starting
app.state = 'starting'
app.port = port
app.logs = []
update()
const cwd = join(APPS_DIR, dir)
@ -130,6 +132,9 @@ const runApp = async (dir: string, port: number) => {
const text = decoder.decode(value).trimEnd()
if (text) {
log(dir, text)
const line: LogLine = { time: Date.now(), text }
app.logs = [...(app.logs ?? []).slice(-(MAX_LOGS - 1)), line]
update()
}
}
}

View File

@ -15,11 +15,12 @@ app.get('/api/apps/stream', c => {
start(controller) {
const send = () => {
// Strip proc field from apps before sending
const apps: SharedApp[] = allApps().map(({ name, state, port, started }) => ({
const apps: SharedApp[] = allApps().map(({ name, state, port, started, logs }) => ({
name,
state,
port,
started,
logs,
}))
const data = JSON.stringify(apps)
controller.enqueue(encoder.encode(`data: ${data}\n\n`))

View File

@ -1,8 +1,14 @@
export type AppState = 'invalid' | 'stopped' | 'starting' | 'running' | 'stopping'
export type LogLine = {
time: number
text: string
}
export type App = {
name: string
state: AppState
port?: number
started?: number
logs?: LogLine[]
}