a6bd33bcff
Workspace sessions (docs/plans/desktop-parity, phases 1-5 and 7): - sessions.lane_id: a workspace lists only the sessions its panes held, stamped by bindRunSession (first writer wins, nested `claude -p` excluded); GET /api/sessions?lane=&archived= - session row state dot, double-click rename, archive (sessions.archived_at, hides only); the activity bar's duplicate Sessions tab removed - Fork beside Resume (--fork-session, Claude only), Ctrl/Cmd+click a live session opens it in a second pane, a diff line's comment is pasted into the workspace's last-focused pane (lib/panePaste.ts) dashboard_runs stability: - a pane's previous run is archived as <pane>@<started_at> instead of being overwritten by INSERT OR REPLACE - a run is flagged abandoned only once its tmux session is gone, at boot and on the run-heal beat (panes outlive a server restart) UI: - sidebar: no footer, language or theme block; small collapse button in the brand corner; version + update check in the connection details modal, a status-bar dot while a release is out; language in Settings -> General - one Switch component for every switch, the themed Checkbox for every checkbox (no native checkboxes) Also: AI Tools catalog trimmed to 10 built-ins (custom-file prompt modes tested through fixtures), and the workspace plans under docs/plans/ (the multi-user server plan lives in the AgentHub-Server repo).
151 lines
8.7 KiB
Markdown
151 lines
8.7 KiB
Markdown
# Phase 2 — Settings as a full-page grouped navigation
|
|
|
|
_One PR, after phase 1._
|
|
|
|
## Goal
|
|
|
|
Replace the horizontal `PageTabs` bar on `/settings` with a left navigation
|
|
grouped under small uppercase headings, one section per route, a search box
|
|
that filters sections, and consistent row primitives — the structure in
|
|
`reference/orca-settings1.png` / `orca-settings-agents.png` /
|
|
`orca-settings-scrolled.png`, in AgentHub's own tokens.
|
|
|
|
## Non-goals
|
|
|
|
- No new settings. Every control that exists today is kept, moved, and
|
|
reachable from search. (One exception: the worktree-visibility toggles from
|
|
phase 1 get their first proper home here.)
|
|
- No theme change. No new dependency.
|
|
- No change to any server setting route.
|
|
|
|
## 1. Routes
|
|
|
|
`App.tsx`: `settings` → `settings/:section?`. `SettingsHub.tsx` reads
|
|
`:section`; unknown or missing ⇒ redirect to `settings/general`. The old
|
|
`?tool=<id>` query is honoured for one release: `?tool=claude-code` ⇒
|
|
`/settings/agents/claude-code`, `?tool=ai-router` ⇒ `/settings/ai-router`, and
|
|
`#ai-tools` ⇒ `/settings/agents` with the catalog modal open. Every in-app link
|
|
that builds a settings URL (`AddLaneModal`'s AI Tools link, the Claude
|
|
tab's cross-links, `Sidebar` nav) is updated to the path form.
|
|
|
|
Section ids are stable strings (they are URLs and i18n keys):
|
|
|
|
| Group (i18n `settingsNav.group.*`) | Section id | Content = today's component |
|
|
| --- | --- | --- |
|
|
| **General** | `general` | `Settings.tsx` sections: `lanesSection` (renamed "Workspaces": housekeeping) + `data` (import, remote sources, clear data) + `about` |
|
|
| | `appearance` | `AppearanceSettings` |
|
|
| | `notifications` | `Settings.tsx` `notifications` + `alertsHub` (`AlertsNotifications`, `WebhookSettings`) |
|
|
| **Agents** | `agents` | `AiToolsSettings` inline (the modal's content as a page; `AiToolsModal` stays for the Add-workspace link) |
|
|
| | `agents/claude-code` | `CcConfig` (its own sub-tabs stay inside the page) |
|
|
| | `agents/codex` | `CodexConfig` |
|
|
| | `agents/<catalog id>` | `AiToolConfig toolId` — one entry per installed, enabled tool without a `launcher` (same rule as today's `catalogTabs`) |
|
|
| **Routing** | `ai-router` | `AiRouterConfig` |
|
|
| | `pricing` | `PricingSettings` with a vendor filter for *all* vendors (today it is embedded per tool; keep those embeds too — this page is the all-vendors view) |
|
|
| **Git** | `git-credentials` | `GitCredentialsConfig` |
|
|
| | `worktrees` | **new** `WorktreeVisibilitySettings`: "Show untracked worktrees" switch; per-source rows `.claude/worktrees/*` (Show/Hide), AgentHub-managed (`LANES_ROOT`) (Show/Hide); writes the phase-1 localStorage key |
|
|
| **Projects** | `projects/<encoded root>` | **new** `ProjectSettings`: read-only project card (root, main branch, worktree count), its workspaces (link to each), the per-project override of the worktree sources above (`hideSources` keyed by root), and "Forget all workspaces of this project" (loops `POST …/remove`, confirm modal listing them) |
|
|
|
|
A tool section is hidden while that tool is disabled (same `aiTools.byId(...).enabled` check as today).
|
|
|
|
## 2. Layout
|
|
|
|
```
|
|
┌ sidebar (app) ┬──────────────────────────────────────────────────────────┐
|
|
│ │ ← Back to Workspace │
|
|
│ │ [🔍 Search settings Ctrl+F] │
|
|
│ │ │
|
|
│ │ GENERAL │ General │
|
|
│ │ ⚙ General │ Workspace housekeeping, data, about. │
|
|
│ │ ◐ Appearance │ ───────────────────────────────────── │
|
|
│ │ 🔔 Notifications│ ┌ card ─────────────────────────────┐ │
|
|
│ │ AGENTS │ │ Housekeeping │ │
|
|
│ │ ▣ AI tools │ │ Run housekeeping [Dry run][Run]│ │
|
|
│ │ ✳ Claude Code │ ├───────────────────────────────────┤ │
|
|
│ │ ◎ Codex │ │ Data │ │
|
|
│ │ ▲ Antigravity │ │ Import history … │ │
|
|
│ │ ROUTING … │ └───────────────────────────────────┘ │
|
|
│ │ PROJECTS │ │
|
|
│ │ ◈ agenthub │ │
|
|
└───────────────┴──────────────────┴─────────────────────────────────────────┘
|
|
```
|
|
|
|
- The settings nav is a second column **inside** the page (`w-56`, sticky,
|
|
own scroll), not the app sidebar. The app sidebar stays as it is.
|
|
- "← Back to Workspace" is a plain link to `/workspace` (keeps `?ws` from
|
|
localStorage).
|
|
- Content column: `max-w-3xl`, section title `text-2xl font-semibold`, one-line
|
|
description `text-sm text-fg-muted`, hairline, then **one card per subsection**
|
|
(`.card` as today). Do not nest cards.
|
|
- Mobile (`< md`): the nav becomes a `<select>` above the content.
|
|
|
|
## 3. Primitives (`client/src/components/settings/SettingsRow.tsx`)
|
|
|
|
```tsx
|
|
<SettingsSection title description> // h3 + muted description inside a card
|
|
<SettingsRow label description control alignTop?> // 2 columns: label+desc | control (shrink-0)
|
|
<SettingsSwitchRow label description checked onChange disabled? />
|
|
<SettingsSegmented options value onChange /> // role="radiogroup", existing button styles
|
|
```
|
|
|
|
Every control already in `Settings.tsx`, `AppearanceSettings.tsx`,
|
|
`ClaudeAgentHubSettings.tsx`, `CodexHooksSettings.tsx`,
|
|
`AntigravityHooksSettings.tsx`, `AiToolConfig.tsx` is re-wrapped in these
|
|
rows. `CcConfig.tsx` (172 KB) and `CodexConfig.tsx` keep their internal layout
|
|
in this phase — only their outer frame changes. Rows: `py-3` with a
|
|
description, `py-2` without; divider `border-b border-border/60` between
|
|
rows, none after the last.
|
|
|
|
## 4. Search
|
|
|
|
`client/src/lib/settingsSearch.ts`:
|
|
|
|
```ts
|
|
interface SettingsEntry { section: string; title: string; description?: string; keywords?: string[] }
|
|
rankSettings(query, entries): { section: string; score: number }[]
|
|
```
|
|
|
|
Scoring (lowercase; exact > prefix > substring): section title 900/850/800,
|
|
entry title 700/650/600, description 500/450/400, keywords 300/250/200. Each
|
|
section registers its entries in a static `SETTINGS_INDEX` array (one per
|
|
`SettingsRow` label at minimum; i18n-resolved at render). While the query is
|
|
non-empty the nav shows only matching sections (groups with no match hidden),
|
|
the first match is focused, Enter opens it; Esc clears. `Ctrl+F` / `Cmd+F`
|
|
focuses the box when the settings page has focus (do not steal it from a
|
|
terminal — `/settings` has none, so a plain keydown listener on the page root
|
|
is enough).
|
|
|
|
## 5. i18n
|
|
|
|
`settings.json`: `settingsNav.group.{general,agents,routing,git,projects}`,
|
|
`settingsNav.section.*` (title + description per id), `search.placeholder`,
|
|
`search.noMatch`, `back`, `worktrees.*`, `project.*`. Remove `tools.*` keys
|
|
that no longer render (keep `tools.label` if `AiToolsModal` still uses it).
|
|
|
|
## 6. Tests
|
|
|
|
- `SettingsHub.test.tsx`: route → section, legacy `?tool=` redirect, hidden
|
|
tool section when disabled, mobile select.
|
|
- `settingsSearch.test.ts`: ranking order, empty query, no match.
|
|
- `WorktreeVisibilitySettings.test.tsx`: writes the phase-1 key, per-project
|
|
override.
|
|
- Existing panel tests unchanged except their mount path.
|
|
- Snapshots: Settings screens regenerate once.
|
|
|
|
## 7. Docs
|
|
|
|
`docs/LANES.md` (worktree visibility, per-project settings), `README.md`
|
|
(settings tour), `client/README.md` (route list, primitives), `CLAUDE.md`
|
|
marker: "Settings is `/settings/:section` with a grouped nav; a tool's own
|
|
settings live under `agents/<id>`; the whole-page search index is
|
|
`SETTINGS_INDEX`".
|
|
|
|
## Acceptance
|
|
|
|
- Every control reachable before is reachable after (walk `Settings.tsx`'s
|
|
section list and each tool tab, tick them off in the PR body).
|
|
- `/settings?tool=codex` lands on `/settings/agents/codex`.
|
|
- Typing "pricing" in search shows Routing → Pricing and the Claude/Codex
|
|
pages (both embed the table); Enter opens the first.
|
|
- Keyboard: Tab order follows the visual order; `Ctrl+F` focuses search.
|
|
- Suites + headers + snapshots green; before/after screenshots.
|