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 ✓
This commit is contained in:
Fusion
2026-05-19 13:43:49 +02:00
parent 92d0d5b891
commit 6807f449b7
16 changed files with 2330 additions and 2 deletions
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-05-19
@@ -0,0 +1,158 @@
# Git History Visualization - Design
## Architecture
```
User → Frontend → Backend API → Git CLI → Repository
Commit Data
Frontend Rendering
```
## Backend Design
### Git History Extraction
Use `git log --graph` with custom format to get structured data:
```bash
git log --all --graph --format="%H|%P|%an|%ae|%at|%s" --date=short
```
This gives us:
- Commit hash
- Parent hashes
- Author name
- Author email
- Author timestamp
- Subject line
### API Endpoints
#### GET /projects/{project_id}/repositories/{repo_id}/history
**Query Parameters:**
- `view`: "graph" or "list" (default: "graph")
- `branch`: specific branch to filter (optional)
- `limit`: max commits to return (default: 100)
**Response (Graph View):**
```json
{
"commits": [
{
"hash": "abc123...",
"short_hash": "abc123",
"parents": ["def456...", "ghi789..."],
"author": "John Doe",
"email": "john@example.com",
"date": "2026-05-19",
"timestamp": 1716123456,
"message": "feat: add new feature",
"branches": ["main", "feature-branch"],
"tags": ["v1.0.0"]
}
],
"branches": ["main", "develop", "feature-branch"],
"graph_data": {
"columns": 3,
"rows": [
{
"commit_hash": "abc123...",
"column": 0,
"connections": [
{"from_column": 0, "to_column": 1, "type": "merge"}
]
}
]
}
}
```
#### GET /projects/{project_id}/repositories/{repo_id}/commits/{commit_hash}
**Response:**
```json
{
"hash": "abc123...",
"short_hash": "abc123",
"parents": ["def456..."],
"author": "John Doe",
"email": "john@example.com",
"date": "2026-05-19",
"timestamp": 1716123456,
"message": "feat: add new feature\n\nDetailed description here",
"stats": {
"files_changed": 3,
"insertions": 45,
"deletions": 12
},
"diff": "diff --git a/file.txt b/file.txt\n..."
}
```
## Frontend Design
### Page Layout
```
┌─────────────────────────────────────────────────────────┐
│ Repository Name > History [Graph] [List] │
├─────────────────────────────────────────────────────────┤
│ ┌──────────────────┐ ┌──────────────────────────────┐ │
│ │ │ │ │ │
│ │ Graph/List │ │ Commit Details │ │
│ │ View │ │ (message, author, │ │
│ │ │ │ diff) │ │
│ │ │ │ │ │
│ └──────────────────┘ └──────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
```
### Graph View
- SVG-based rendering
- Commits shown as circles
- Lines connect commits (straight or curved)
- Branch labels shown inline
- Color coding for different branches
- Click to select commit
### List View
- Linear list of commits
- Each row: hash, message, author, date
- Expandable for details
- Click to select commit
### Commit Details Panel
- Header: Commit message, author, date
- Stats: Files changed, insertions, deletions
- Diff view: Syntax highlighted changes
## Data Flow
1. User navigates to repository history page
2. Frontend fetches history data from backend
3. Backend executes git commands on bare repo
4. Backend parses output into structured JSON
5. Frontend renders graph or list based on user preference
6. User clicks commit → Frontend fetches commit details
7. Backend executes `git show` for specific commit
8. Frontend displays details panel with diff
## Error Handling
- **Empty repository**: Show "No commits yet" message
- **Git command failure**: Show error with retry button
- **Large repositories**: Implement pagination/lazy loading
- **Binary files in diff**: Show "Binary file changed" instead of diff
## Performance Considerations
- **Pagination**: Load commits in batches (100 at a time)
- **Lazy loading**: Load diff only when commit is selected
- **Caching**: Cache history data for 30 seconds
- **Graph complexity**: Limit graph to first 500 commits for performance
@@ -0,0 +1,46 @@
# Git History Visualization
## Problem
Currently, users can create and manage git repositories, but they have no way to view the commit history, branches, or understand the repository structure. This makes it impossible to:
- See what commits exist in a repository
- Understand branch relationships and merges
- View commit details (message, author, date, changes)
- Explore the repository's evolution over time
## Solution
Build an interactive git history visualization similar to GitKraken that provides:
1. **Graph View**: Visual commit graph showing branches, merges, and commit relationships
2. **List View**: Linear commit log with details
3. **Commit Details**: Click any commit to see full details and diff
4. **Branch Visualization**: See all branches and their relationships
## Benefits
- **Understand repository structure** at a glance
- **Track changes** and see who made what changes when
- **Navigate history** easily without using command line
- **Review code** by examining commit diffs
## Scope
### What we're building:
- Backend API to extract git history from bare/mirror repos using git CLI
- Graph visualization component (SVG-based commit graph)
- List view component (linear commit log)
- Commit detail panel (message, author, date, diff)
- View toggle (graph vs list)
- Branch label display
### Out of scope (future enhancements):
- Interactive branch operations (checkout, merge, rebase)
- Tag management
- File browser at specific commits
- Blame/annotation view
- Advanced filtering/search
## Technical Approach
**Backend**: Execute `git log --graph --format=...` commands to get structured commit data
**Frontend**: Custom SVG rendering for graph, React components for list view and details panel
@@ -0,0 +1,213 @@
# Git History Visualization Specification
## Requirements
### Functional Requirements
1. **View Commit History**: Display all commits in a repository
2. **Graph Visualization**: Show commits as nodes with branch/merge lines
3. **List View**: Alternative linear view of commits
4. **Commit Details**: Click to view full commit info and diff
5. **Branch Display**: Show branch names on commits
6. **Tag Display**: Show tags on commits
7. **View Toggle**: Switch between graph and list views
### Non-Functional Requirements
1. **Performance**: Load first 100 commits in < 2 seconds
2. **Responsiveness**: Graph should render smoothly up to 500 commits
3. **Compatibility**: Work with bare repositories and mirror clones
4. **Read-only**: No write operations to repository
## API Specification
### GET /projects/{project_id}/repositories/{repo_id}/history
Retrieve commit history for a repository.
**Query Parameters:**
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| view | string | "graph" | "graph" or "list" |
| branch | string | null | Filter by branch name |
| limit | integer | 100 | Max commits to return |
| offset | integer | 0 | Skip first N commits |
**Response 200:**
```json
{
"commits": [
{
"hash": "full-sha-hash",
"short_hash": "abc1234",
"parents": ["parent-hash-1", "parent-hash-2"],
"author": "John Doe",
"email": "john@example.com",
"date": "2026-05-19",
"timestamp": 1716123456,
"message": "feat: add new feature",
"branches": ["main"],
"tags": []
}
],
"branches": ["main", "develop", "feature/x"],
"total_commits": 250,
"graph_data": {
"nodes": [
{
"hash": "abc1234",
"x": 0,
"y": 0,
"column": 0
}
],
"edges": [
{
"from_hash": "abc1234",
"to_hash": "def5678",
"type": "parent"
}
]
}
}
```
### GET /projects/{project_id}/repositories/{repo_id}/commits/{commit_hash}
Get detailed information about a specific commit.
**Response 200:**
```json
{
"hash": "full-sha-hash",
"short_hash": "abc1234",
"parents": ["parent-hash"],
"author": "John Doe",
"email": "john@example.com",
"date": "2026-05-19",
"timestamp": 1716123456,
"message": "feat: add new feature",
"body": "Detailed description here",
"stats": {
"files_changed": 3,
"insertions": 45,
"deletions": 12
},
"files": [
{
"path": "src/main.py",
"change_type": "modified",
"insertions": 20,
"deletions": 5,
"diff": "diff content here"
}
]
}
```
## Frontend Components
### GitHistoryPage
Main page component that orchestrates the view.
### GraphView
SVG-based commit graph visualization.
**Props:**
- `commits`: Commit[]
- `graphData`: GraphData
- `selectedCommit`: string | null
- `onCommitSelect`: (hash: string) => void
### ListView
Linear commit list.
**Props:**
- `commits`: Commit[]
- `selectedCommit`: string | null
- `onCommitSelect`: (hash: string) => void
### CommitDetails
Panel showing commit details and diff.
**Props:**
- `commit`: CommitDetail | null
### DiffViewer
Component to display git diff with syntax highlighting.
**Props:**
- `files`: FileChange[]
## Data Models
### Commit
```typescript
interface Commit {
hash: string;
short_hash: string;
parents: string[];
author: string;
email: string;
date: string;
timestamp: number;
message: string;
branches: string[];
tags: string[];
}
```
### CommitDetail
```typescript
interface CommitDetail extends Commit {
body: string;
stats: {
files_changed: number;
insertions: number;
deletions: number;
};
files: FileChange[];
}
```
### FileChange
```typescript
interface FileChange {
path: string;
change_type: "added" | "modified" | "deleted" | "renamed";
insertions: number;
deletions: number;
diff: string;
}
```
## URL Structure
```
/projects/:projectId/repositories/:repoId/history
```
## Error Codes
| Error Code | Description | User Message |
|------------|-------------|--------------|
| REPO_EMPTY | Repository has no commits | "This repository has no commits yet" |
| GIT_ERROR | Git command failed | "Failed to load repository history" |
| COMMIT_NOT_FOUND | Commit hash not found | "Commit not found" |
| INVALID_BRANCH | Branch doesn't exist | "Branch not found" |
## Testing Strategy
### Backend Tests
- Test git log parsing with various repo structures
- Test commit detail extraction
- Test error handling for empty repos
### Frontend Tests
- Test graph rendering with sample data
- Test list view rendering
- Test commit selection and details display
- Test view toggle
### Integration Tests
- End-to-end flow: load history → select commit → view details
@@ -0,0 +1,113 @@
# Git History Visualization - Tasks
## Phase 1: Backend API
- [x] **Task 1.1**: Create git history extraction module
- Create `src/utils/git_history.py`
- Implement `get_commit_history(repo_path, limit=100)` function
- Parse `git log --graph --format=...` output
- Extract commit hashes, parents, authors, dates, messages
- Extract branch information
- Add comprehensive unit tests
- [x] **Task 1.2**: Create commit detail extraction
- Implement `get_commit_detail(repo_path, commit_hash)` function
- Parse `git show --format=... --stat` output
- Extract full message, body, stats, file changes
- Extract diff for each file
- Add unit tests
- [x] **Task 1.3**: Create graph data builder
- Implement `build_graph_data(commits)` function
- Calculate node positions (x, y coordinates)
- Calculate edge connections between commits
- Handle merge commits (multiple parents)
- Add unit tests
- [x] **Task 1.4**: Create history API endpoints
- Add `GET /projects/{project_id}/repositories/{repo_id}/history`
- Add `GET /projects/{project_id}/repositories/{repo_id}/commits/{commit_hash}`
- Handle query parameters (view, branch, limit, offset)
- Return structured JSON response
- Handle errors (empty repo, invalid commit, etc.)
- Add integration tests
## Phase 2: Frontend Components
- [x] **Task 2.1**: Create API client for history
- Add `fetchHistory(projectId, repoId, options)` function
- Add `fetchCommitDetail(projectId, repoId, commitHash)` function
- Add TypeScript interfaces for all data types
- [x] **Task 2.2**: Create GraphView component
- SVG-based commit graph rendering
- Draw commit nodes (circles)
- Draw connection lines (straight/curved)
- Show branch labels
- Handle click events
- Color coding for branches
- [x] **Task 2.3**: Create ListView component
- Linear list of commits
- Show hash, message, author, date
- Handle click events
- Scrollable with virtualization for large lists
- [x] **Task 2.4**: Create CommitDetails component
- Show commit message, author, date
- Show stats (files changed, insertions, deletions)
- Show file list with change types
- Expandable diff viewer
- Syntax highlighting for diffs
- [x] **Task 2.5**: Create DiffViewer component
- Parse and display git diff format
- Show line numbers
- Color code: green for additions, red for deletions
- Handle binary files
- Collapsible file sections
## Phase 3: Page Integration
- [x] **Task 3.1**: Create GitHistoryPage
- Layout with view toggle (graph/list)
- Fetch history data on mount
- Manage selected commit state
- Show loading/error states
- Responsive layout (details panel on right, below on mobile)
- [x] **Task 3.2**: Add navigation from repository list
- Add "View History" button to repository cards
- Link to history page
- Pass repository info
- [x] **Task 3.3**: Add route
- Add `/projects/:projectId/repositories/:repoId/history` route
- Update router configuration
## Phase 4: Testing & Polish
- [ ] **Task 4.1**: Add backend tests
- Test git log parsing
- Test graph data building
- Test API endpoints
- Test error handling
- [ ] **Task 4.2**: Add frontend tests
- Test component rendering
- Test user interactions (click, toggle)
- Test data transformations
- [x] **Task 4.3**: Run quality gates
- Backend: ruff, mypy, pytest
- Frontend: typecheck, lint, build
- [ ] **Task 4.4**: Performance optimization
- Implement pagination for large repositories
- Add caching for history data
- Optimize graph rendering
- [ ] **Task 4.5**: Documentation
- Update README with feature description
- Add screenshots/diagrams
- Document API endpoints