fix(desktop): streamline detail drawers

This commit is contained in:
apale7 2026-04-20 01:27:00 +08:00
parent a1eb4e244c
commit 5bd04b6a07
4 changed files with 933 additions and 511 deletions

View File

@ -0,0 +1,93 @@
# Desktop Log, Network, And List-First Forms
## Summary
Desktop shell already contains provider and alias management pages with inline split-view editing, plus dedicated log and network tabs. Current provider and alias pages always reserve detail-pane space and automatically select first list item. This makes browsing feel heavy and wastes space when user only wants to inspect list.
This task keeps current data flow and form logic, but changes page behavior to a list-first layout:
- provider page shows only list by default
- alias route page shows only list by default
- clicking a list item opens edit panel
- clicking new opens create form panel
- import and bind target flows stay modal-based
## Product Goal
Make provider and alias route management feel lighter and more focused by separating browsing from editing, while preserving existing CRUD behavior and minimizing architectural churn.
## Current State
### Already done
- `frontend/src/App.tsx` contains provider and alias list, search, filter, create, edit, delete, import, and bind-target flows.
- provider and alias forms already reuse local state and existing API calls.
- desktop shell already uses modal overlays for provider import, alias target binding, and confirm dialogs.
### Problems
- provider and alias tabs default to split-view with always-visible detail panel.
- first filtered item is auto-selected, so page never rests in pure list mode.
- empty detail area still occupies layout width before user chooses an action.
## Requirements
### Provider page
- Default state shows only provider list and list controls.
- No provider detail panel should be visible until user clicks a provider row or `New provider`.
- Clicking provider row opens edit panel for that provider.
- Clicking `New provider` opens create panel with empty form.
### Alias route page
- Default state shows only alias list and list controls.
- No alias detail panel should be visible until user clicks alias row or `New alias`.
- Clicking alias row opens edit panel for that alias.
- Clicking `New alias` opens create panel with empty form.
### Interaction and reuse
- Reuse existing provider and alias form logic as much as possible.
- Reuse current modal/backdrop interaction patterns already used in desktop shell.
- Keep import-provider modal and bind-target modal unchanged unless minor adjustments are required for consistency.
- Keep existing backend/API contracts unchanged.
## Design Decisions
### Detail presentation
Use conditional overlay detail panel instead of always-mounted split-view pane.
Why:
- smallest frontend-only change that matches requested behavior
- consistent with existing modal/backdrop interaction already present in app
- preserves current form structure, submit handlers, and confirmation flows
### Selection behavior
Do not auto-select first filtered provider or alias.
Why:
- page should remain in pure list mode until explicit user action
- prevents accidental context switching when search/filter changes
## Non-Goals
1. No backend changes for providers, aliases, logs, or network.
2. No redesign of import-provider or bind-target workflows.
3. No new global state layer or routing changes.
4. No visual redesign outside provider and alias page layout adjustments needed for list-first behavior.
## Acceptance Criteria
1. Provider tab initially renders list without visible edit pane.
2. Alias tab initially renders list without visible edit pane.
3. Clicking provider row opens provider edit panel.
4. Clicking alias row opens alias edit panel.
5. Clicking provider create button opens provider create panel.
6. Clicking alias create button opens alias create panel.
7. Search/filter changes do not auto-open a detail panel.
8. Existing save, delete, import, bind, and toggle actions still work.

View File

@ -0,0 +1,69 @@
{
"id": "desktop-log-network-views",
"name": "desktop-log-network-views",
"title": "Design and implement desktop log and network views",
"description": "",
"status": "completed",
"dev_type": "feature",
"scope": "desktop",
"package": null,
"priority": "P2",
"creator": "OpenCode",
"assignee": "OpenCode",
"createdAt": "2026-04-19",
"completedAt": "2026-04-20",
"branch": "master",
"base_branch": "master",
"worktree_path": null,
"current_phase": 6,
"next_action": [
{
"phase": 1,
"action": "brainstorm"
},
{
"phase": 2,
"action": "research"
},
{
"phase": 3,
"action": "implement"
},
{
"phase": 4,
"action": "check"
},
{
"phase": 5,
"action": "update-spec"
},
{
"phase": 6,
"action": "record-session"
}
],
"commit": null,
"pr_url": null,
"subtasks": [],
"children": [],
"parent": null,
"relatedFiles": [
".trellis/tasks/04-19-desktop-log-network-views/prd.md",
"frontend/src/App.tsx",
"frontend/src/styles.css"
],
"notes": "Completed desktop provider, alias, log, and network view refresh to use list-first layouts with on-demand detail drawers instead of default split panes. Added keyboard-accessible drawer close flows, automatic first-field focus, shell scroll locking while drawers are open, list-header status/close affordances, and independent log/network detail selection. Fixed a GUI theme regression by preventing routine data refresh after proxy start/stop from overwriting in-memory desktop preferences. Verified with `npm run build` in `frontend`.",
"meta": {
"tests": [
"npm run build"
],
"uiPatterns": [
"list-first detail drawers",
"shared drawer close interactions",
"drawer-only scrolling"
],
"regressions": [
"proxy start/stop no longer resets theme presentation"
]
}
}

File diff suppressed because it is too large Load Diff

View File

@ -243,6 +243,12 @@ h4 {
min-height: 100vh;
}
.app-shell.shell-locked,
.sidebar.shell-locked,
.workspace.shell-locked {
overflow: hidden;
}
.sidebar {
position: sticky;
top: 0;
@ -683,7 +689,7 @@ html[data-theme='dark'] button.ghost-danger:hover {
.providers-layout,
.aliases-layout {
grid-template-columns: minmax(360px, 0.92fr) minmax(0, 1.08fr);
grid-template-columns: minmax(0, 1fr);
}
.editor-column,
@ -784,6 +790,36 @@ html[data-theme='dark'] button.ghost-danger:hover {
align-content: start;
}
.detail-backdrop {
position: fixed;
inset: 0;
z-index: 25;
display: flex;
justify-content: flex-end;
padding: 1rem;
background: rgba(7, 16, 29, 0.28);
backdrop-filter: blur(8px);
}
.detail-sheet {
width: min(100%, 720px);
height: calc(100vh - 2rem);
overflow: auto;
padding: 1.3rem;
border: 1px solid var(--border-strong);
border-radius: 28px;
background: var(--panel);
box-shadow: var(--shadow-lg);
}
.detail-sheet-header {
position: sticky;
top: 0;
z-index: 1;
padding-bottom: 1rem;
background: var(--panel);
}
.compact-inline-meta {
align-items: flex-start;
}
@ -1207,6 +1243,15 @@ dd {
.settings-side-panel {
position: static;
}
.detail-backdrop {
padding: 0.75rem;
}
.detail-sheet {
width: min(100%, 760px);
height: calc(100vh - 1.5rem);
}
}
@media (max-width: 900px) {
@ -1264,6 +1309,18 @@ dd {
flex-direction: column;
align-items: stretch;
}
.detail-backdrop {
align-items: stretch;
justify-content: stretch;
padding: 0;
}
.detail-sheet {
width: 100%;
height: 100vh;
border-radius: 0;
}
}
@media (max-width: 640px) {