feat(app): status rings on panels + sidebar aggregate badge from state events
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { useRef } from "react";
|
||||
import { TerminalView } from "./TerminalView";
|
||||
import type { LayoutNode } from "./layoutTypes";
|
||||
import { StatusRing } from "./StatusRing";
|
||||
import type { LayoutNode, SurfaceState } from "./layoutTypes";
|
||||
import { setRatios, restartSurface } from "./socketBridge";
|
||||
|
||||
interface Props {
|
||||
@@ -8,16 +9,17 @@ interface Props {
|
||||
layout: LayoutNode | null;
|
||||
/** surface_id -> running flag, from the latest status/events. */
|
||||
running: Record<string, boolean>;
|
||||
states: Record<string, SurfaceState>;
|
||||
}
|
||||
|
||||
export function LayoutEngine({ workspaceId, layout, running }: Props) {
|
||||
export function LayoutEngine({ workspaceId, layout, running, states }: Props) {
|
||||
if (!layout) {
|
||||
return <div style={{ color: "#666", padding: 24 }}>Empty workspace — apply a preset to add panels.</div>;
|
||||
}
|
||||
return <Node workspaceId={workspaceId} node={layout} path={[]} running={running} />;
|
||||
return <Node workspaceId={workspaceId} node={layout} path={[]} running={running} states={states} />;
|
||||
}
|
||||
|
||||
function Node({ workspaceId, node, path, running }: { workspaceId: string; node: LayoutNode; path: number[]; running: Record<string, boolean> }) {
|
||||
function Node({ workspaceId, node, path, running, states }: { workspaceId: string; node: LayoutNode; path: number[]; running: Record<string, boolean>; states: Record<string, SurfaceState> }) {
|
||||
if ("leaf" in node) {
|
||||
const id = node.leaf.surface_id;
|
||||
if (running[id] === false) {
|
||||
@@ -28,7 +30,17 @@ function Node({ workspaceId, node, path, running }: { workspaceId: string; node:
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return <TerminalView key={id} surfaceId={id} />;
|
||||
return (
|
||||
<div style={{ display: "flex", flexDirection: "column", width: "100%", height: "100%" }}>
|
||||
<div style={{ display: "flex", alignItems: "center", gap: 7, padding: "3px 8px", background: "#0A0D12", borderBottom: "1px solid #232A33" }}>
|
||||
<StatusRing state={states[id] ?? "idle"} running={true} />
|
||||
<span style={{ fontFamily: "monospace", fontSize: 11, color: "#8B97A6" }}>{id}</span>
|
||||
</div>
|
||||
<div style={{ flex: 1, minHeight: 0 }}>
|
||||
<TerminalView key={id} surfaceId={id} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const { orient, ratios, children } = node.split;
|
||||
@@ -43,7 +55,7 @@ function Node({ workspaceId, node, path, running }: { workspaceId: string; node:
|
||||
next[i + 1] = Math.max(0.05, (next[i + 1] ?? 1) - deltaFrac);
|
||||
void setRatios(workspaceId, path, next);
|
||||
}}>
|
||||
<Node workspaceId={workspaceId} node={child} path={[...path, i]} running={running} />
|
||||
<Node workspaceId={workspaceId} node={child} path={[...path, i]} running={running} states={states} />
|
||||
</Pane>
|
||||
))}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user