refactor(maestro): flatten web UI to a single host
Session tree nests by working directory only; the daemon chips in the header become a session tally, and the spawn form loses its host picker. API calls move from /api/daemons/:id/* to /api/dirs, /api/recent-dirs, /api/gitroot, and /api/info.
This commit is contained in:
+7
-19
@@ -1,15 +1,14 @@
|
||||
import { eventsWsUrl, listDaemons, listSessions } from "./api.js";
|
||||
import type { DaemonInfo, RegistryEvent, Session, Uuid } from "./types.js";
|
||||
import { eventsWsUrl, listSessions } from "./api.js";
|
||||
import type { CatalogEvent, Session, Uuid } from "./types.js";
|
||||
|
||||
export interface CatalogState {
|
||||
daemons: Map<string, DaemonInfo>;
|
||||
sessions: Map<Uuid, Session>;
|
||||
}
|
||||
|
||||
export type CatalogListener = (state: CatalogState) => void;
|
||||
|
||||
export class CatalogStore {
|
||||
private state: CatalogState = { daemons: new Map(), sessions: new Map() };
|
||||
private state: CatalogState = { sessions: new Map() };
|
||||
private listeners = new Set<CatalogListener>();
|
||||
private ws: WebSocket | null = null;
|
||||
private reconnectTimer: number | null = null;
|
||||
@@ -46,9 +45,9 @@ export class CatalogStore {
|
||||
this.ws = ws;
|
||||
|
||||
ws.onmessage = (ev) => {
|
||||
let event: RegistryEvent;
|
||||
let event: CatalogEvent;
|
||||
try {
|
||||
event = JSON.parse(ev.data) as RegistryEvent;
|
||||
event = JSON.parse(ev.data) as CatalogEvent;
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
@@ -83,23 +82,13 @@ export class CatalogStore {
|
||||
}, delay);
|
||||
}
|
||||
|
||||
private apply(event: RegistryEvent): void {
|
||||
private apply(event: CatalogEvent): void {
|
||||
switch (event.type) {
|
||||
case "Snapshot":
|
||||
this.state = {
|
||||
daemons: new Map(event.daemons.map((d) => [d.daemon_id, d])),
|
||||
sessions: new Map(event.sessions.map((s) => [s.id, s])),
|
||||
};
|
||||
break;
|
||||
case "DaemonAdded":
|
||||
this.state.daemons.set(event.daemon.daemon_id, event.daemon);
|
||||
break;
|
||||
case "DaemonRemoved":
|
||||
this.state.daemons.delete(event.daemon_id);
|
||||
for (const [id, sess] of this.state.sessions) {
|
||||
if (sess.daemon_id === event.daemon_id) this.state.sessions.delete(id);
|
||||
}
|
||||
break;
|
||||
case "SessionAdded":
|
||||
this.state.sessions.set(event.session.id, event.session);
|
||||
break;
|
||||
@@ -119,9 +108,8 @@ export class CatalogStore {
|
||||
|
||||
private async resync(): Promise<void> {
|
||||
try {
|
||||
const [daemons, sessions] = await Promise.all([listDaemons(), listSessions()]);
|
||||
const sessions = await listSessions();
|
||||
this.state = {
|
||||
daemons: new Map(daemons.map((d) => [d.daemon_id, d])),
|
||||
sessions: new Map(sessions.map((s) => [s.id, s])),
|
||||
};
|
||||
this.emit();
|
||||
|
||||
Reference in New Issue
Block a user