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:
@@ -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
|
||||
Reference in New Issue
Block a user