diff --git a/ui/src/ui/app.ts b/ui/src/ui/app.ts index fceed164b..c7d0effcb 100644 --- a/ui/src/ui/app.ts +++ b/ui/src/ui/app.ts @@ -70,7 +70,7 @@ const DEFAULT_CRON_FORM: CronFormState = { export class ClawdisApp extends LitElement { @state() settings: UiSettings = loadSettings(); @state() password = ""; - @state() tab: Tab = "overview"; + @state() tab: Tab = "chat"; @state() connected = false; @state() hello: GatewayHelloOk | null = null; @state() lastError: string | null = null; @@ -156,6 +156,7 @@ export class ClawdisApp extends LitElement { @state() debugCallError: string | null = null; client: GatewayBrowserClient | null = null; + private chatScrollFrame: number | null = null; createRenderRoot() { return this; @@ -166,6 +167,18 @@ export class ClawdisApp extends LitElement { this.connect(); } + protected updated(changed: Map) { + if ( + this.tab === "chat" && + (changed.has("chatMessages") || + changed.has("chatStream") || + changed.has("chatLoading") || + changed.has("tab")) + ) { + this.scheduleChatScroll(); + } + } + connect() { this.lastError = null; this.hello = null; @@ -199,6 +212,16 @@ export class ClawdisApp extends LitElement { this.client.start(); } + private scheduleChatScroll() { + if (this.chatScrollFrame) cancelAnimationFrame(this.chatScrollFrame); + this.chatScrollFrame = requestAnimationFrame(() => { + this.chatScrollFrame = null; + const container = this.querySelector(".messages") as HTMLElement | null; + if (!container) return; + container.scrollTop = container.scrollHeight; + }); + } + private onEvent(evt: GatewayEventFrame) { this.eventLog = [ { ts: Date.now(), event: evt.event, payload: evt.payload }, diff --git a/ui/src/ui/navigation.ts b/ui/src/ui/navigation.ts index 1905be48b..6e74791d6 100644 --- a/ui/src/ui/navigation.ts +++ b/ui/src/ui/navigation.ts @@ -1,10 +1,11 @@ export const TAB_GROUPS = [ + { label: "Chat", tabs: ["chat"] }, { label: "Control", tabs: ["overview", "connections", "instances", "sessions", "cron"], }, - { label: "Agent", tabs: ["chat", "skills", "nodes"] }, - { label: "Gateway", tabs: ["config", "debug"] }, + { label: "Agent", tabs: ["skills", "nodes"] }, + { label: "Settings", tabs: ["config", "debug"] }, ] as const; export type Tab = @@ -72,4 +73,3 @@ export function subtitleForTab(tab: Tab) { return ""; } } - diff --git a/ui/src/ui/views/chat.ts b/ui/src/ui/views/chat.ts index 1a14901cd..bbf386d9d 100644 --- a/ui/src/ui/views/chat.ts +++ b/ui/src/ui/views/chat.ts @@ -38,6 +38,7 @@ export function renderChat(props: ChatProps) {
+ ${props.loading ? html`
Loading chat…
` : nothing} ${props.messages.map((m) => renderMessage(m))} ${props.stream ? html`${renderMessage({ @@ -113,4 +114,3 @@ function extractText(message: unknown): string | null { if (typeof m.text === "string") return m.text; return null; } -