# Spec: Workspace-First UI Refresh ## Status | Field | Value | |---|---| | Phase | **Spec** | | Based on | [Proposal](proposal.md) | | Next | Design | ## Overview Replace the old "Repository Workspace" (direct repo file browser) with a **Workspace-First** model. The workspace detail page becomes the primary work surface. Projects page shows inline repos + workspaces. Old `repo-workspace.tsx` is deleted. ## Decisions | # | Question | Answer | |---|---|---| | 1 | URL structure | `/workspaces/:id` (flat) | | 2 | Sidebar nav order | Workspaces → Projects | | 3 | New Workspace flow | Inline form on project page | | 4 | Branch switching | Dropdown in workspace header | | 5 | Empty tool state | "Start a tool" prompt card | | 6 | Mobile tabs | Files / Git / Tools / Settings | | 7 | Git toolbar | Collapsible top bar on Files tab | | 8 | Git tab content | History, diff, full commit log | ## User Flows ### Flow 1: Open a Project 1. User clicks "Projects" in sidebar 2. Sees project cards with inline repositories 3. Each repo shows its workspaces as clickable cards 4. User clicks a workspace → navigates to `/workspaces/:id` ### Flow 2: Work in a Workspace 1. User is on `/workspaces/:id` 2. **Files tab** (default): File tree (left) + file viewer/editor (right). Git toolbar at top. 3. User edits a file, commits via git toolbar 4. **Git tab**: Full history, diff view, detailed commit log 5. **Tools tab**: See running instances, click "Start Tool" → inline modal 6. **Settings tab**: Sync workspace, rename, delete ### Flow 3: Create a Workspace 1. User on Projects page, expands a repo 2. Clicks "+ New Workspace" next to a repo 3. Inline form appears: name input, branch dropdown 4. Submits → workspace created, appears in list ### Flow 4: Start a Tool 1. User on workspace detail, Tools tab 2. If no instances: "Start a tool on this workspace" card 3. If instances: list of cards + "Start Another" button 4. Click → inline modal: tool type picker, config profile (optional) 5. Submit → instance created, appears in list with status ## Backend API ### New Endpoints (workspace-scoped) All endpoints operate on the workspace clone path (`workspace.path`). ``` # Files GET /workspaces/{workspace_id}/files?path=&branch= → List directory entries GET /workspaces/{workspace_id}/files/content?path=&branch= → Get file content POST /workspaces/{workspace_id}/files/content Body: { path, content, message } → Commit file change # Git GET /workspaces/{workspace_id}/git/status → { modified, added, deleted, untracked, branch } GET /workspaces/{workspace_id}/git/branches → { branches, default_branch, current_branch } POST /workspaces/{workspace_id}/git/commit Body: { message, files? } → Commit staged changes POST /workspaces/{workspace_id}/git/push → Push current branch POST /workspaces/{workspace_id}/git/pull → Pull current branch POST /workspaces/{workspace_id}/git/fetch → Fetch from origin POST /workspaces/{workspace_id}/git/checkout Body: { branch } → Switch branch GET /workspaces/{workspace_id}/git/history Query: ?path=&limit=50 → Commit history for file or entire repo # Tools (instances on this workspace) GET /workspaces/{workspace_id}/instances → List tool instances using this workspace POST /workspaces/{workspace_id}/instances Body: { tool_type_id, display_name?, config_profile_id? } → Create instance on this workspace ``` ### Existing Endpoints (unchanged) ``` GET /workspaces/ POST /workspaces/ (body: { repo_id, name, branch }) DELETE /workspaces/{id} POST /workspaces/{id}/sync PATCH /workspaces/{id} ``` Note: `POST /workspaces/` now accepts `repo_id` directly instead of nested under `/projects/{pid}/repositories/{rid}/workspaces`. ### Modified Endpoints ``` GET /projects/ → Now includes `repositories` array with `workspaces` sub-array ``` ## Database Schema No changes. Existing `workspaces` table is sufficient. ## Frontend Routes ``` / → Dashboard (unchanged) /workspaces → All workspaces list (refreshed) /workspaces/:id → Workspace detail (NEW, replaces repo-workspace) /projects → Projects list (refreshed) /projects/:id → Project detail with repos + workspaces (NEW) /sessions → Sessions list (unchanged) /settings → Settings (unchanged) ``` ## UI Components ### WorkspaceDetailPage (`/workspaces/:id`) ``` ┌──────────────────────────────────────────────────────────────┐ │ Breadcrumb: Projects > {project} > {repo} > {workspace} │ │ [Branch ▼ main] [Sync] [Start Tool] [Settings] │ ├──────────────────────────────────────────────────────────────┤ │ Tab bar: [Files] [Git] [Tools] [Settings] │ ├──────────────────────────────────────────────────────────────┤ │ │ │ {Active Tab Content} │ │ │ └──────────────────────────────────────────────────────────────┘ ``` #### Files Tab (default) ``` ┌──────────────────────────────────────────────────────────────┐ │ Git Toolbar (collapsible) │ │ [Modified: 3] [Staged: 2] [Commit ▼] [Push] [Pull] [Fetch] │ ├──────────────┬───────────────────────────────────────────────┤ │ │ │ │ File Tree │ File Viewer / Editor │ │ (workspace │ │ │ path) │ Breadcrumbs: src > utils > helpers.ts │ │ │ │ │ 📁 src/ │ [Edit] [History] │ │ 📄 README │ │ │ │ export function ... │ │ │ │ └──────────────┴───────────────────────────────────────────────┘ ``` **Git Toolbar**: Collapsible bar above file content. Shows: - Status counters: Modified, Added, Deleted, Untracked - Commit button (with message input when expanded) - Push, Pull, Fetch buttons - Branch selector dropdown #### Git Tab ``` ┌──────────────────────────────────────────────────────────────┐ │ Branch: [main ▼] [New Branch] [Merge] [Compare] │ ├──────────────────────────────────────────────────────────────┤ │ │ │ Commit History │ │ ┌────────────────────────────────────────────────────┐ │ │ │ ● abc123 Fix auth middleware │ │ │ │ ● def456 Add user profile page │ │ │ │ ● 789abc Initial commit │ │ │ └────────────────────────────────────────────────────┘ │ │ │ │ [Show Diff] [Checkout] [Revert] │ │ │ └──────────────────────────────────────────────────────────────┘ ``` #### Tools Tab ``` ┌──────────────────────────────────────────────────────────────┐ │ Active Tool Instances │ │ │ │ ┌─────────────┐ ┌─────────────┐ [+ Start Tool] │ │ │ Code Server │ │ Terminal │ │ │ │ ● Running │ │ ● Stopped │ │ │ │ [Open] [Stop│ │ [Start] [×] │ │ │ └─────────────┘ └─────────────┘ │ │ │ │ ─ or ─ │ │ │ │ ┌────────────────────────────────────────────────────┐ │ │ │ No tools running on this workspace │ │ │ │ Start a tool to begin coding │ │ │ │ [Start Tool] │ │ │ └────────────────────────────────────────────────────┘ │ │ │ └──────────────────────────────────────────────────────────────┘ ``` #### Settings Tab ``` ┌──────────────────────────────────────────────────────────────┐ │ Workspace Settings │ │ │ │ Name: [my-feature-branch ] │ │ Branch: main (tracks origin/main) │ │ Path: /data/working-copies/{repo-id}/{name} │ │ Created: 2024-01-15 │ │ Last Sync: 2024-01-20 14:32 │ │ │ │ [Rename] [Sync Now] [Delete Workspace] │ │ │ └──────────────────────────────────────────────────────────────┘ ``` ### ProjectsPage (`/projects`) ``` ┌──────────────────────────────────────────────────────────────┐ │ Projects [+ New Project] │ ├──────────────────────────────────────────────────────────────┤ │ │ │ ┌────────────────────────────────────────────────────┐ │ │ │ My Web App │ │ │ │ A full-stack application │ │ │ ├────────────────────────────────────────────────────┤ │ │ │ Repositories: │ │ │ │ │ │ │ │ ▼ frontend (git@github.com:me/frontend.git) │ │ │ │ ┌──────────┐ ┌─────────────┐ [+ New Workspace] │ │ │ │ │ main │ │ feature-ui │ │ │ │ │ │ ● 2 inst │ │ ● 0 inst │ │ │ │ │ └──────────┘ └─────────────┘ │ │ │ │ │ │ │ │ ▶ backend (git@github.com:me/backend.git) │ │ │ │ ┌──────────┐ [+ New Workspace] │ │ │ │ │ main │ │ │ │ │ │ ● 1 inst │ │ │ │ │ └──────────┘ │ │ │ │ │ │ │ │ [Edit Project] [Delete] │ │ │ └────────────────────────────────────────────────────┘ │ │ │ └──────────────────────────────────────────────────────────────┘ ``` **Workspace Card**: Small card showing: - Name - Status badge (ready/syncing/error) - Instance count (dot + number) - Click navigates to `/workspaces/:id` **New Workspace Button**: Inline form on click: ``` [Name: __________] [Branch: main ▼] [Create] [Cancel] ``` ### Mobile Layout Bottom tab bar (4 tabs, always visible): ``` ┌────────────────────────────────────┐ │ {Tab Content - full screen} │ │ │ │ │ │ │ ├────────────────────────────────────┤ │ 📁 Files 🔀 Git 🛠 Tools ⚙ Settings│ └────────────────────────────────────┘ ``` **Files tab**: File tree full screen, tap file → viewer overlay **Git tab**: Commit history list, tap commit → diff overlay **Tools tab**: Instance cards stacked vertically **Settings tab**: Same as desktop settings, scrollable ## State & Data Flow ### Workspace Detail Page ``` useWorkspace(workspaceId) → fetch /workspaces/{id} useWorkspaceFiles(workspaceId, path?, branch?) → fetch /workspaces/{id}/files useWorkspaceGitStatus(workspaceId) → fetch /workspaces/{id}/git/status useWorkspaceInstances(workspaceId) → fetch /workspaces/{id}/instances ``` All hooks poll/refetch on: - Tab switch - User action (commit, push, etc.) - 30s background refresh ### Projects Page ``` useProjects() → fetch /projects/ useProjectWorkspaces(projectId) → derived from project.repositories.workspaces ``` ## Error Handling | Scenario | UX | |---|---| | Workspace not found | 404 page with "Workspace not found" + link to workspaces | | Git operation fails | Toast with git stderr, retry button | | File read fails | "File not found" in viewer, check if on correct branch | | No tool types available | "No tools configured" + link to Tool Workshop | | Workspace path missing | "Workspace files not found — try syncing" | ## Accessibility - Tab bar: `role="tablist"`, keyboard arrow navigation - File tree: `role="tree"`, arrow key expansion - Git toolbar: All buttons have `aria-label` - Focus management: Modal traps focus, returns on close ## Performance - File tree: Virtualized for repos > 1000 files - Git history: Paginated (50 commits per page) - Image files: Lazy loaded in viewer - Polling: 30s for instances, 10s for git status when visible ## Acceptance Criteria - [ ] `repo-workspace.tsx` and related components deleted - [ ] `/projects/:id` route shows project detail, not file browser - [ ] `/workspaces/:id` route shows workspace detail page - [ ] File browser reads from workspace clone path - [ ] File viewer/editor works on workspace files - [ ] Git toolbar on Files tab supports commit/push/pull/fetch - [ ] Git tab shows commit history with diff - [ ] Tools tab lists instances + spawn modal - [ ] Settings tab shows workspace info + rename/sync/delete - [ ] Projects page shows inline repos + workspace cards - [ ] Inline "New Workspace" form on project page - [ ] Mobile: 4-tab bottom navigation - [ ] All existing tests pass or updated - [ ] ruff clean, TypeScript clean, eslint clean