From 873ca80091541931af2931978c3734324381ceac Mon Sep 17 00:00:00 2001 From: meetsu <96637888+klNuno@users.noreply.github.com> Date: Wed, 16 Sep 2026 00:33:58 +0200 Subject: [PATCH 1/5] feat(ui): simplify navigation and chat controls --- docs/development.md | 6 + docs/model-switching.md | 7 + packages/ui/src/App.svelte | 6 +- packages/ui/src/app.css | 2 +- packages/ui/src/app.test.ts | 2 +- packages/ui/src/components/ChatView.svelte | 228 +----------------- packages/ui/src/components/Composer.svelte | 25 +- packages/ui/src/components/Composer.test.ts | 2 +- .../ui/src/components/MachineStatus.svelte | 15 +- packages/ui/src/components/Menu.svelte | 12 +- packages/ui/src/components/MessageList.svelte | 52 +++- .../ui/src/components/MessageOutline.svelte | 67 +++++ packages/ui/src/components/ModelPicker.svelte | 5 +- packages/ui/src/components/Sidebar.svelte | 8 +- .../ui/src/components/ThreadHeader.svelte | 197 +++++++++++++++ packages/ui/src/components/TitleBar.svelte | 69 +++--- packages/ui/src/lib/menu.ts | 2 + packages/ui/src/lib/model-defaults.test.ts | 36 +++ packages/ui/src/lib/model-defaults.ts | 2 + packages/ui/src/lib/store.svelte.ts | 27 ++- packages/ui/src/lib/strings.ts | 7 +- packages/ui/src/lib/workspace.svelte.ts | 7 + packages/ui/src/lib/workspace.test.ts | 14 +- packages/ui/test-setup.ts | 11 + tests/e2e/header.test.ts | 98 ++++++++ tests/e2e/shell.test.ts | 71 +++--- 26 files changed, 665 insertions(+), 313 deletions(-) create mode 100644 packages/ui/src/components/MessageOutline.svelte create mode 100644 packages/ui/src/components/ThreadHeader.svelte create mode 100644 tests/e2e/header.test.ts diff --git a/docs/development.md b/docs/development.md index 1e7ead2..51db3a2 100644 --- a/docs/development.md +++ b/docs/development.md @@ -237,6 +237,12 @@ from exact events to polling; without the second the focus guard never starts. ## Captures +`tests/e2e/header.test.ts` checks the shared header, sidebar folding and saved +state, project groups, machine menu ordering, and prompt navigation through a +paged, virtualized conversation. It captures desktop, phone and light-theme +layouts on the fake client. The shell suite checks that the thread controls sit +inside the same title bar and that dragging excludes editable controls. + The fake client is excluded from production bundles. Tests that need it must use the Vite development server. `tests/e2e/settings.test.ts` starts and closes one within the test process; the other end-to-end paths use a real temporary diff --git a/docs/model-switching.md b/docs/model-switching.md index 62750e6..69d7239 100644 --- a/docs/model-switching.md +++ b/docs/model-switching.md @@ -85,6 +85,13 @@ continuation of an image-bearing history explicitly. ## Storage and concurrent changes +The composer resolves an old `default` or `auto` model alias to the configured +provider preset for the next prompt when one is configured. A named model stays selected. Before sending +on an old thread, the UI verifies the preset against the account's model catalog +and saves it with the thread's selection revision. An unavailable preset or a +concurrent selection change refuses the send; it never silently runs the alias. +The picker also ignores saved presets containing these aliases. + Schema 9 adds `threads.session_generation`, `threads.selection_version` and `turns.execution`. Existing native session IDs survive migration. Execution snapshots record the target at acceptance, and both scheduler and driver use it. diff --git a/packages/ui/src/App.svelte b/packages/ui/src/App.svelte index ee874f3..bb610b7 100644 --- a/packages/ui/src/App.svelte +++ b/packages/ui/src/App.svelte @@ -235,9 +235,7 @@
- {#if inShell} - - {/if} +
{#if !store.booted} @@ -483,7 +481,7 @@ .scrim { display: block; position: fixed; - inset: 0; + inset: var(--titlebar) 0 0; z-index: 20; border: none; border-radius: 0; diff --git a/packages/ui/src/app.css b/packages/ui/src/app.css index 0a5cc93..2b0bfe5 100644 --- a/packages/ui/src/app.css +++ b/packages/ui/src/app.css @@ -68,7 +68,7 @@ --text-md: 16px; --text-lg: 20px; - --titlebar: 36px; + --titlebar: 44px; --sidebar: 280px; --panel: 360px; --content: 820px; diff --git a/packages/ui/src/app.test.ts b/packages/ui/src/app.test.ts index b7ebe91..46577c1 100644 --- a/packages/ui/src/app.test.ts +++ b/packages/ui/src/app.test.ts @@ -215,7 +215,7 @@ test('a draft names its project in the heading and the dropdown moves it to anot expect(heading.textContent).toContain('with approval requests in'); expect(heading.textContent).toContain('notes'); // The heading says the project, so the header chip no longer repeats it. - expect(query('[data-testid=chat] header').textContent).not.toContain('notes'); + expect(query('[data-testid=thread-header]').textContent).not.toContain('notes'); query('[data-testid=draft-project]').click(); await waitFor(() => document.querySelector('[data-testid=draft-project-menu]') !== null); diff --git a/packages/ui/src/components/ChatView.svelte b/packages/ui/src/components/ChatView.svelte index 5bcc2fc..d07cc53 100644 --- a/packages/ui/src/components/ChatView.svelte +++ b/packages/ui/src/components/ChatView.svelte @@ -1,83 +1,16 @@ + +{#if prompts.length > 1 || hasOlder} + +{/if} + + diff --git a/packages/ui/src/components/ModelPicker.svelte b/packages/ui/src/components/ModelPicker.svelte index 1aecc51..834328b 100644 --- a/packages/ui/src/components/ModelPicker.svelte +++ b/packages/ui/src/components/ModelPicker.svelte @@ -1,6 +1,6 @@ + +
+ {#if thread} + + {#if renaming} + void commitRename()} + placeholder={strings.thread.renamePlaceholder} + data-testid="thread-rename-input" + use:focusOnMount + /> + {:else} + + {/if} + {:else} + + {strings.sidebar.draft} + {/if} + + + + + {#if project && thread} + {project.name} + {/if} + {#if thread?.branch} + + + {thread.branch} + + {/if} + {#if thread}{/if} + + {#if thread && store.owner} + + {/if} +
+ + diff --git a/packages/ui/src/components/TitleBar.svelte b/packages/ui/src/components/TitleBar.svelte index 1256638..00a8495 100644 --- a/packages/ui/src/components/TitleBar.svelte +++ b/packages/ui/src/components/TitleBar.svelte @@ -1,11 +1,22 @@ {#if prompts.length > 1 || hasOlder} -