Files
headquarter/openspec/changes/repo-workspace/design.md
T
Fusion 6807f449b7 feat: add repository workspace as default project view
- Create git file utilities (list_tree, get_file_content, list_branches, commit_file)
- Add file browsing API endpoints (list, content, branches, update)
- Create RepoWorkspace page with sidebar + main content layout
- Add FileTree component with directory navigation
- Add FileViewer component for viewing file contents
- Update project list to link to workspace
- Add workspace CSS styles
- Update router with workspace route

Quality gates: ruff ✓, mypy ✓, typecheck ✓, build ✓
2026-05-19 13:43:49 +02:00

270 lines
7.9 KiB
Markdown

# Repository Workspace - Design
## Architecture
```
Project List
↓ (click project)
Repo Workspace (default view)
├─ Sidebar (200px)
│ ├─ Repo Selector (dropdown)
│ ├─ Branch Selector (dropdown)
│ └─ File Tree (scrollable)
│ ├─ 📁 src/
│ │ └─ 📄 main.py
│ ├─ 📁 tests/
│ └─ 📄 README.md
└─ Main Content
├─ Breadcrumbs: src > main.py
├─ Toolbar: [Edit] [Raw] [History]
└─ Content Area
├─ File View (syntax highlighted)
└─ Edit View (textarea with save)
```
## Page Layout
### Route: `/projects/:projectId`
This replaces the current placeholder and becomes the default project view.
### Layout Structure
```
┌─────────────────────────────────────────────────────────────┐
│ App Shell (Header + Nav) │
├─────────────────────────────────────────────────────────────┤
│ Project Header │
│ "My Project" [Repos] [History] [Settings]│
├─────────────────┬───────────────────────────────────────────┤
│ │ │
│ Sidebar │ Main Content │
│ ┌───────────┐ │ ┌─────────────────────────────────────┐ │
│ │ Repo ▼ │ │ │ Breadcrumbs: src > components │ │
│ ├───────────┤ │ ├─────────────────────────────────────┤ │
│ │ Branch ▼ │ │ │ [Edit] [History] [Blame] │ │
│ ├───────────┤ │ ├─────────────────────────────────────┤ │
│ │ 📁 src/ │ │ │ │ │
│ │ 📁 tests/ │ │ │ function hello() { │ │
│ │ 📄 README │ │ │ return "world"; │ │
│ │ ... │ │ │ } │ │
│ │ │ │ │ │ │
│ └───────────┘ │ └─────────────────────────────────────┘ │
│ │ │
└─────────────────┴───────────────────────────────────────────┘
```
## Data Flow
### 1. Page Load
```
Load /projects/:id
→ Fetch project details
→ Fetch repositories list
→ Fetch default branch file tree (first repo)
→ Render workspace
```
### 2. Repository Switch
```
Select repo from dropdown
→ Fetch branches list
→ Fetch default branch file tree
→ Reset file viewer
```
### 3. Branch Switch
```
Select branch from dropdown
→ Fetch file tree for branch
→ If viewing a file: re-fetch file content for branch
```
### 4. File Navigation
```
Click file in tree
→ Fetch file content (with syntax highlighting hint)
→ Show in viewer
→ Update breadcrumbs
```
## API Endpoints
### GET /projects/{project_id}/repositories/{repo_id}/files
List files at a path (like `ls` for git).
**Query Parameters:**
- `branch`: Branch name (default: repo's default branch)
- `path`: Directory path (default: root)
**Response:**
```json
{
"path": "src",
"branch": "main",
"entries": [
{
"name": "components",
"type": "directory",
"path": "src/components"
},
{
"name": "main.py",
"type": "file",
"path": "src/main.py",
"size": 1234,
"last_commit": {
"hash": "abc123",
"message": "Initial commit",
"date": "2024-01-01T00:00:00Z"
}
}
]
}
```
### GET /projects/{project_id}/repositories/{repo_id}/files/content
Get file content.
**Query Parameters:**
- `branch`: Branch name
- `path`: File path
**Response:**
```json
{
"path": "src/main.py",
"branch": "main",
"content": "function hello() {\n return 'world';\n}",
"size": 42,
"encoding": "utf-8",
"language": "python"
}
```
### GET /projects/{project_id}/repositories/{repo_id}/branches
List branches.
**Response:**
```json
{
"branches": [
{
"name": "main",
"is_default": true,
"last_commit": "abc123"
},
{
"name": "feature/new-thing",
"is_default": false,
"last_commit": "def456"
}
],
"default_branch": "main"
}
```
### POST /projects/{project_id}/repositories/{repo_id}/files/content
Update file content (for quick edits).
**Request Body:**
```json
{
"path": "src/main.py",
"branch": "main",
"content": "function hello() {\n return 'world!!!';\n}",
"commit_message": "Quick edit: update greeting",
"author_name": "User Name",
"author_email": "user@example.com"
}
```
## Components
### RepoWorkspace (Page)
- Orchestrates layout: sidebar + main content
- Manages repo/branch/file state
- Handles URL params (projectId, optional repoId)
### FileTree (Sidebar Component)
- Recursive tree view
- Expandable folders
- File icons based on extension
- Active file highlight
- Click to open file
### RepoSelector (Component)
- Dropdown of project repositories
- Shows active repo name
- Switch triggers repo change
### BranchSelector (Component)
- Dropdown of branches
- Shows active branch
- Switch triggers branch change
### FileViewer (Component)
- Syntax highlighted content
- Line numbers
- View/Edit toggle
- Breadcrumb navigation
### Breadcrumbs (Component)
- Path segments as clickable links
- Shows current file location
## State Management
### URL State
```
/projects/:projectId?repo=:repoId&branch=:branch&path=:path
```
- repo: selected repository ID
- branch: active branch name
- path: current file/directory path
### React State (per workspace)
```typescript
interface WorkspaceState {
projectId: string;
selectedRepoId: string | null;
selectedBranch: string;
currentPath: string;
selectedFile: string | null;
fileContent: string | null;
isEditing: boolean;
fileTree: FileTreeEntry[];
branches: Branch[];
repositories: Repository[];
}
```
## Implementation Order
1. **Backend file APIs** - List files, get content, list branches
2. **Backend update API** - Save file changes (commit)
3. **Project list clickable** - Link to workspace
4. **Workspace page shell** - Layout with sidebar + main
5. **File tree component** - Recursive directory listing
6. **File viewer component** - Content display
7. **Repo/branch selectors** - Dropdowns with state
8. **Edit mode** - Toggle + save
9. **URL state sync** - Sync selections to URL
10. **Polish** - Icons, syntax highlighting, error handling
## Error Handling
- **Repo not found**: Show error, allow selecting another
- **Branch not found**: Show error, default to main
- **File not found**: Show 404 in viewer
- **Permission denied**: Show auth error
- **Binary files**: Show "Binary file, cannot display" message
- **Large files**: Show warning, offer download
## Performance Considerations
- **Lazy load file tree**: Only expand directories when clicked
- **Cache file content**: Don't re-fetch if file hasn't changed
- **Debounce tree loading**: When switching branches, debounce
- **Virtual scrolling**: For large directories (100+ files)
- **Syntax highlighting**: Use lightweight highlighter, async load