--all, --tools

This commit is contained in:
Chris Wanstrath 2026-01-30 18:13:29 -08:00
parent 5ea9d5f843
commit ed46638b50
4 changed files with 44 additions and 22 deletions

View File

@ -21,10 +21,10 @@ export async function configShow() {
const source = process.env.TOES_URL const source = process.env.TOES_URL
? 'TOES_URL' ? 'TOES_URL'
: process.env.TOES_HOST : process.env.TOES_HOST
? 'TOES_HOST' + (process.env.PORT ? ' + PORT' : '') ? 'TOES_HOST' + (process.env.PORT ? ' + PORT' : '')
: process.env.NODE_ENV === 'production' : process.env.NODE_ENV === 'production'
? 'default (production)' ? 'default (production)'
: 'default (development)' : 'default (development)'
console.log(`Source: ${color.gray(source)}`) console.log(`Source: ${color.gray(source)}`)
@ -53,7 +53,7 @@ export async function infoApp(arg?: string) {
} }
const icon = STATE_ICONS[app.state] ?? '◯' const icon = STATE_ICONS[app.state] ?? '◯'
console.log(`${icon} ${color.bold(app.name)}`) console.log(`${icon} ${color.bold(app.name)} ${app.tool && '[tool]'}`)
console.log(` State: ${app.state}`) console.log(` State: ${app.state}`)
if (app.port) { if (app.port) {
console.log(` Port: ${app.port}`) console.log(` Port: ${app.port}`)
@ -73,11 +73,22 @@ export async function infoApp(arg?: string) {
if (app.error) console.log(` Error: ${color.red(app.error)}`) if (app.error) console.log(` Error: ${color.red(app.error)}`)
} }
export async function listApps() { interface ListAppsOptions {
tools?: boolean
all?: boolean
}
export async function listApps(options: ListAppsOptions) {
const apps: App[] | undefined = await get('/api/apps') const apps: App[] | undefined = await get('/api/apps')
if (!apps) return if (!apps) return
for (const app of apps) { const filtered = apps.filter((app) => {
if (options.all) return true
if (options.tools) return app.tool
return !app.tool
})
for (const app of filtered) {
console.log(`${STATE_ICONS[app.state] ?? '◯'} ${app.name}`) console.log(`${STATE_ICONS[app.state] ?? '◯'} ${app.name}`)
} }
} }

View File

@ -1,5 +1,4 @@
import { program } from 'commander' import { program } from 'commander'
import { readFileSync } from 'fs'
import color from 'kleur' import color from 'kleur'
import { import {
@ -60,6 +59,8 @@ program
program program
.command('list') .command('list')
.description('List all apps') .description('List all apps')
.option('-t, --tools', 'show only tools')
.option('-a, --all', 'show all apps including tools')
.action(listApps) .action(listApps)
program program

View File

@ -10,7 +10,7 @@ const render = () => {
// Update tool iframes after DOM settles // Update tool iframes after DOM settles
requestAnimationFrame(() => { requestAnimationFrame(() => {
const tools = apps.filter(a => a.tool) const tools = apps.filter(a => a.tool)
updateToolIframes(selectedTab, tools) updateToolIframes(selectedTab, tools, selectedApp)
}) })
} }

View File

@ -24,9 +24,11 @@ export function initToolIframes() {
const match = iframe.src.match(/localhost:(\d+)/) const match = iframe.src.match(/localhost:(\d+)/)
if (match && match[1]) { if (match && match[1]) {
const port = parseInt(match[1], 10) const port = parseInt(match[1], 10)
const name = iframe.dataset.toolName const toolName = iframe.dataset.toolName
if (name) { const appName = iframe.dataset.appName
iframes.set(name, { iframe, port }) if (toolName) {
const cacheKey = appName ? `${toolName}:${appName}` : toolName
iframes.set(cacheKey, { iframe, port })
} }
} }
}) })
@ -42,7 +44,8 @@ export function initToolIframes() {
// Update which iframe is visible based on selected tab and tool state // Update which iframe is visible based on selected tab and tool state
export function updateToolIframes( export function updateToolIframes(
selectedTab: string, selectedTab: string,
tools: Array<{ name: string; port?: number; state: string }> tools: Array<{ name: string; port?: number; state: string }>,
selectedApp: string | null
) { ) {
const container = getContainer() const container = getContainer()
if (!container) return if (!container) return
@ -63,8 +66,11 @@ export function updateToolIframes(
const tool = selectedTool! const tool = selectedTool!
// Build cache key for tool + app combination
const cacheKey = selectedApp ? `${tool.name}:${selectedApp}` : tool.name
// Skip if nothing changed // Skip if nothing changed
if (currentTool === tool.name) { if (currentTool === cacheKey) {
// Just update position in case of scroll/resize // Just update position in case of scroll/resize
const tabContent = document.querySelector('[data-tool-target]') const tabContent = document.querySelector('[data-tool-target]')
if (tabContent) { if (tabContent) {
@ -97,34 +103,38 @@ export function updateToolIframes(
z-index: 100; z-index: 100;
` `
// Get or create the iframe for this tool // Get or create the iframe for this tool + app combination
let cached = iframes.get(tool.name) let cached = iframes.get(cacheKey)
if (!cached || cached.port !== tool.port) { if (!cached || cached.port !== tool.port) {
// Create new iframe (first time or port changed) // Create new iframe (first time or port changed)
const iframe = document.createElement('iframe') const iframe = document.createElement('iframe')
iframe.src = `http://localhost:${tool.port}` const url = selectedApp
? `http://localhost:${tool.port}?app=${encodeURIComponent(selectedApp)}`
: `http://localhost:${tool.port}`
iframe.src = url
iframe.dataset.toolName = tool.name // For hot reload recovery iframe.dataset.toolName = tool.name // For hot reload recovery
iframe.dataset.appName = selectedApp ?? '' // For hot reload recovery
iframe.style.cssText = ` iframe.style.cssText = `
width: 100%; width: 100%;
height: 100%; height: 100%;
border: none; border: none;
` `
cached = { iframe, port: tool.port! } cached = { iframe, port: tool.port! }
iframes.set(tool.name, cached) iframes.set(cacheKey, cached)
// Add to container // Add to container
container.appendChild(iframe) container.appendChild(iframe)
} }
// Show only the selected iframe, hide others // Show only the selected iframe, hide others
for (const [name, { iframe }] of iframes) { for (const [key, { iframe }] of iframes) {
const shouldShow = name === tool.name const shouldShow = key === cacheKey
if (shouldShow && iframe.parentElement !== container) { if (shouldShow && iframe.parentElement !== container) {
container.appendChild(iframe) container.appendChild(iframe)
} }
iframe.style.display = shouldShow ? 'block' : 'none' iframe.style.display = shouldShow ? 'block' : 'none'
} }
currentTool = tool.name currentTool = cacheKey
;(window as any).__currentTool = tool.name ;(window as any).__currentTool = cacheKey
} }