Skip to content

feat: Add checkpoint diff preview and custom delete confirmation dialog - #59

Merged
frankbria merged 4 commits into
mainfrom
parallel-mishn4p7-euxv
Dec 5, 2025
Merged

feat: Add checkpoint diff preview and custom delete confirmation dialog#59
frankbria merged 4 commits into
mainfrom
parallel-mishn4p7-euxv

Conversation

@frankbria

Copy link
Copy Markdown
Owner

Summary

Implements expandable checkpoint items with git diff preview and replaces browser confirm dialog with custom DeleteConfirmationDialog component.

Closes #47

Changes

Backend

  • ✅ Added CheckpointDiffResponse model in codeframe/ui/models.py
  • ✅ Added GET endpoint /api/projects/{project_id}/checkpoints/{checkpoint_id}/diff
    • Returns files changed, insertions, deletions statistics
    • Parses git numstat output for accurate diff statistics
    • Uses existing CheckpointManager._show_diff() method

Frontend

Expandable Checkpoint Diff Preview

  • ✅ Checkpoint items are now clickable to expand and view git diff
  • ✅ State management for:
    • Expanded checkpoint ID tracking
    • Diff caching (prevents redundant API calls)
    • Loading state per checkpoint
    • Error handling per checkpoint
  • ✅ Diff display features:
    • Loading spinner while fetching
    • Error messages for failed fetches
    • Summary statistics (files changed, insertions, deletions)
    • Syntax-highlighted diff output:
      • Green for additions (+)
      • Red for deletions (-)
      • Blue for line numbers (@@)
    • "No changes detected" message for empty diffs
  • ✅ Proper event handling (restore/delete buttons don't trigger expansion)

Custom Delete Confirmation Dialog

  • ✅ Created DeleteConfirmationDialog.tsx component
    • Follows established modal pattern (similar to BlockerModal)
    • Fixed overlay with backdrop click handling
    • Escape key support to close dialog
    • Warning icon with destructive action styling (red)
    • Clear warning message with checkpoint name
    • Disabled state during deletion ("Deleting..." feedback)
  • ✅ Integrated into CheckpointList
    • Replaced window.confirm() with custom dialog
    • State management for dialog visibility and deletion status
    • Proper error handling and user feedback

Testing

  • ✅ Removed test.skip decorators from 2 E2E tests:
    • test_checkpoint_ui.spec.ts:122 - "should display checkpoint diff preview"
    • test_checkpoint_ui.spec.ts:167 - "should allow deleting checkpoint"
  • ✅ All required testids implemented:
    • checkpoint-diff - Diff display container
    • no-changes-message - Empty diff message
    • delete-confirmation-dialog - Delete dialog container
    • delete-warning - Warning message
    • delete-confirm-button - Confirm deletion button
    • delete-cancel-button - Cancel deletion button
  • ✅ All 19 backend checkpoint manager tests pass
  • ✅ Python linting passes (ruff check)

Files Changed

  • codeframe/ui/models.py - Added CheckpointDiffResponse model
  • codeframe/ui/server.py - Added GET /diff endpoint (109 lines)
  • web-ui/src/components/checkpoints/CheckpointList.tsx - Expandable diffs + delete dialog
  • web-ui/src/components/checkpoints/DeleteConfirmationDialog.tsx - New file (145 lines)
  • tests/e2e/test_checkpoint_ui.spec.ts - Removed skip decorators

Testing Instructions

Manual Testing

  1. Start the backend server: uv run python -m codeframe.ui.server
  2. Start the frontend: cd web-ui && npm run dev
  3. Navigate to Checkpoints page
  4. Test diff preview:
    • Click any checkpoint item to expand
    • Verify diff loads with statistics
    • Verify syntax highlighting (green/red/blue)
    • Click again to collapse
  5. Test delete confirmation:
    • Click "Delete" button on any checkpoint
    • Verify custom dialog appears (not browser confirm)
    • Verify warning message shows checkpoint name
    • Test "Cancel" button (dialog closes, checkpoint remains)
    • Test "Delete" button (checkpoint is deleted)

Automated Testing

# Backend tests
uv run pytest tests/lib/test_checkpoint_manager.py -v

# E2E tests
cd tests/e2e
npx playwright test test_checkpoint_ui.spec.ts

Screenshots

Add screenshots of the diff preview and delete dialog if needed

Acceptance Criteria

  • ✅ Checkpoint diff preview displays on expand
  • ✅ Diff shows files changed or "no changes" message
  • ✅ Custom delete dialog replaces browser confirm
  • ✅ All testids implemented
  • ✅ Both E2E tests enabled
  • ✅ Skip decorators removed

Breaking Changes

None. This is a pure enhancement that adds new features without changing existing behavior.

Migration Notes

None required.

- Replace hover tooltip with inline "Depends on: task-1, task-3" text
- Remove .skip from two dependency tests (lines 248, 382)
- Update dependency count test to match new format
- Simplify implementation from 40 lines to 6 lines

Fixes #42

Test Results:
- All 38 TaskTreeView tests pass
- Full suite: 1096 tests pass
- No regressions introduced

Visual Change:
Before: "↳ 1 dependency" (hover for details)
After: "Depends on: task-1, task-3" (inline, immediately visible)
1. Type Safety (CRITICAL):
   - Added defensive check: hasDependencies && task.depends_on &&
   - Prevents runtime error if depends_on is undefined
   - TypeScript type narrowing now properly handled

2. UX Improvement - Restore Rich Information:
   - Added tooltip with task numbers, titles, and status
   - Tooltip format: "T-001: Implement auth (completed)"
   - Keeps inline visibility while providing detailed hover info
   - Addresses UX regression from removing rich tooltip

3. Visual Spacing:
   - Added ml-2 margin for better badge separation
   - Added cursor-help for tooltip discoverability

Test Results:
- All 38 TaskTreeView tests pass
- No regressions introduced

Visual Result:
Inline: "Depends on: task-1, task-3"
Hover: "T-001: Implement auth (completed)
        T-003: Setup database (in_progress)"
Implements expandable checkpoint items with git diff preview and replaces
browser confirm dialog with custom DeleteConfirmationDialog component.

Backend Changes:
- Add CheckpointDiffResponse model for diff API responses
- Add GET /api/projects/{id}/checkpoints/{id}/diff endpoint
- Parse git numstat output for files changed, insertions, deletions statistics

Frontend Changes:
- Make checkpoint items clickable to expand and show git diff
- Add state management for expanded checkpoints and diff caching
- Implement syntax-highlighted diff display (green/red/blue)
- Add loading spinner and error handling for diff fetching
- Create DeleteConfirmationDialog component following modal pattern
- Replace window.confirm() with custom delete confirmation dialog
- Add all required testids for E2E testing

Testing:
- Remove skip decorators from 2 E2E tests in test_checkpoint_ui.spec.ts
- All 19 backend checkpoint manager tests pass
- Python linting passes (ruff check)

Closes #47
@coderabbitai

coderabbitai Bot commented Dec 5, 2025

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@frankbria has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 1 minutes and 30 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 969b10b and 1e69b14.

📒 Files selected for processing (8)
  • codeframe/ui/models.py (1 hunks)
  • codeframe/ui/server.py (2 hunks)
  • tests/e2e/test_checkpoint_ui.spec.ts (2 hunks)
  • web-ui/src/api/checkpoints.ts (2 hunks)
  • web-ui/src/components/TaskTreeView.test.tsx (3 hunks)
  • web-ui/src/components/TaskTreeView.tsx (1 hunks)
  • web-ui/src/components/checkpoints/CheckpointList.tsx (7 hunks)
  • web-ui/src/components/checkpoints/DeleteConfirmationDialog.tsx (1 hunks)
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch parallel-mishn4p7-euxv

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@claude

claude Bot commented Dec 5, 2025

Copy link
Copy Markdown

Code Review - PR #59: Checkpoint Diff Preview & Delete Dialog

Thank you for this comprehensive PR! The implementation is well-structured and follows the project conventions. Here's my detailed review:


Strengths

1. Code Quality

  • Clean separation of concerns: Backend API logic properly separated from frontend components
  • Consistent naming conventions: Following established patterns (snake_case for Python, camelCase for TypeScript)
  • Proper TypeScript types: Well-defined interfaces in checkpoints.ts
  • Good error handling: Try-catch blocks with user-friendly error messages
  • Accessibility features: ARIA labels, keyboard support (Escape key), proper role attributes

2. User Experience

  • Inline diff preview: Excellent UX improvement with expandable diffs
  • Syntax highlighting: Color-coded diff output (green/red/blue) improves readability
  • Loading states: Spinner during async operations
  • Custom delete dialog: Much better than browser confirm, consistent with app design
  • Event propagation handling: Proper stopPropagation() on Restore/Delete buttons

3. Performance Optimizations

  • Diff caching: Prevents redundant API calls when toggling expansion (CheckpointList.tsx:20)
  • Per-checkpoint loading state: Granular UI feedback
  • Efficient state management: Using Map for O(1) lookups

🔍 Issues Found

Critical Issues

1. Missing Input Validation (server.py:3512-3562)

The get_checkpoint_diff endpoint doesn't validate that the git commit exists before attempting diff operations.

Impact: 500 errors with cryptic messages if commit is missing/corrupted

Recommendation: Add git commit validation before attempting diff

2. Subprocess Security Risk (server.py:3519-3548)

Using raw subprocess calls with database values (git_commit) without format validation.

Impact: Potential command injection if database is compromised

Recommendation: Validate git commit SHA format with regex: ^[a-f0-9]{7,40}$

High Priority Issues

3. Race Condition in Diff Fetching (CheckpointList.tsx:146-180)

When rapidly clicking checkpoints, multiple API calls could be in flight simultaneously.

Impact: Unexpected UI state, wasted API calls, incorrect cache updates

Recommendation: Use AbortController to cancel previous requests when starting new ones

4. Error Handling Gap (server.py:3549-3558)

When git diff --numstat fails, returns zeros for all stats (misleading - looks like no changes).

Impact: Users can't distinguish "no changes" from "parsing failed"

Recommendation: Return -1 or explicit error message when parsing fails

5. Memory Issue with Large Diffs (CheckpointList.tsx:20, server.py:3520)

Storing large diffs in memory (Map cache + API response) without size limits.

Impact: Performance degradation, potential browser crashes with many large checkpoints

Recommendation: Add diff size limits (truncate at 10MB) and cache size limits (max 10 items)

Medium Priority Issues

6. Missing Loading State Cleanup (CheckpointList.tsx:172-177)

State updates on unmounted component during async operations.

Impact: React warnings in console, potential memory leaks

Recommendation: Add isMounted flag in useEffect cleanup

7. Accessibility - Focus Management (DeleteConfirmationDialog.tsx)

No automatic focus when dialog opens.

Impact: Keyboard users must tab through entire page to reach dialog

Recommendation: Auto-focus Cancel button on dialog open with useRef + useEffect

8. Binary File Handling (server.py:3535-3540)

Binary files marked as - get counted as 0 insertions/deletions, losing information.

Impact: Diff stats incomplete - users don't know binary files changed

Recommendation: Track binary files separately in response model

Low Priority Issues

9. Test Coverage Gap

No unit tests for getCheckpointDiff API function or diff caching logic.

Recommendation: Add unit tests for new functions (api/checkpoints.test.ts)

10. Inconsistent Empty State Handling (CheckpointList.tsx:436)

Checks both files_changed === 0 AND !diff.trim() - could miss edge cases.

Recommendation: Use only files_changed (more reliable source of truth)

11. Missing HTTP Caching Headers (server.py:3455)

Checkpoint diffs are immutable but no cache headers set.

Impact: Repeated API calls for same checkpoint diff

Recommendation: Add Cache-Control: public, max-age=31536000, immutable header


🧪 Testing Recommendations

Missing Test Scenarios

  1. Rapid checkpoint expansion (race condition testing)
  2. Large diff handling (performance testing)
  3. Network failure recovery during diff fetch
  4. Dialog backdrop click behavior
  5. Keyboard navigation in delete dialog
  6. Empty/corrupted git commits

📚 Documentation Needs

  1. API endpoint docs: Add OpenAPI/Swagger annotations for new endpoint
  2. Component docs: Add JSDoc comments to DeleteConfirmationDialog props
  3. CLAUDE.md update: Document diff preview feature in Sprint 10 section
  4. Error codes: Document HTTP error codes (400 vs 404 vs 500)

🎯 Summary

Must Fix Before Merge

  1. ⚠️ Add git commit SHA validation for security (Issue Brainstorming: Integrate remaining general concepts into specification #2)
  2. ⚠️ Validate git commit exists before diff (Issue Add Claude Code GitHub Workflow #1)
  3. ⚠️ Fix error handling for numstat parsing (Issue feat: Project schema refactoring with source types and workspace management #4)

Should Fix Soon

  1. Add AbortController for race condition (Issue feat(sprint-4): Multi-Agent Coordination System - P0 & P1 Complete #3)
  2. Add memory limits for large diffs (Issue feat: Project schema refactoring with API endpoint integration #5)
  3. Add component unmount cleanup (Issue Project Schema Refactoring - Flexible Source Types & Deployment Modes #6)

Nice to Have

  1. Focus management, binary file tracking, unit tests, HTTP caching

📊 Overall Assessment

Rating: 8/10 - Very Good Implementation

Strengths: Clean architecture, excellent UX, proper TypeScript types, good accessibility

Concerns: Security validation, error handling, memory management for large diffs

This is a solid implementation that significantly improves checkpoint management UX. The identified issues are mostly edge cases and hardening improvements. With the critical security validations addressed, this will be a great addition.

Files Changed: 7 files (+454/-63 lines)

  • Backend: New diff endpoint with numstat parsing ✅
  • Frontend: Expandable diffs with syntax highlighting ✅
  • New component: Custom delete dialog ✅
  • Tests: E2E tests enabled ✅

Great work! 🎉

Resolves all Critical, High, and Medium priority issues identified in code review.

Critical Issues Fixed:
1. Git commit validation - Added SHA format validation (^[a-f0-9]{7,40}$) to prevent command injection
2. Git commit existence check - Verify commit exists before attempting diff operations
3. Subprocess security - Validate all git commit SHAs before use in subprocess calls

High Priority Issues Fixed:
4. Race condition prevention - Implemented AbortController to cancel in-flight requests
5. Error handling - Return explicit 500 errors instead of misleading zeros when parsing fails
6. Memory limits - Added 10MB diff size limit and 10-item cache limit

Medium Priority Issues Fixed:
7. Component cleanup - Added isMounted ref to prevent state updates on unmounted components
8. Accessibility - Auto-focus Cancel button in DeleteConfirmationDialog for keyboard users
9. Binary file tracking - Count binary files separately (exposed in X-Binary-Files header)

Additional Improvements:
- Added HTTP caching headers (Cache-Control: immutable) for checkpoint diffs
- Added timeouts for git operations (5s verification, 30s diff)
- Improved error messages with detailed failure information
- LRU cache eviction for checkpoint diffs

Backend Changes:
- server.py: Enhanced get_checkpoint_diff endpoint with validation and limits
- Added git cat-file check to verify commit existence
- Added regex validation for git SHA format
- Added size limits and truncation for large diffs
- Better subprocess error handling with timeouts

Frontend Changes:
- CheckpointList.tsx: Added AbortController and cleanup logic
- api/checkpoints.ts: Added optional AbortSignal parameter
- DeleteConfirmationDialog.tsx: Added focus management with useRef
- Implemented isMounted pattern to prevent memory leaks
- Added cache size limits (max 10 items with LRU eviction)

Testing: All 19 backend checkpoint manager tests passing
@frankbria

Copy link
Copy Markdown
Owner Author

Code Review Fixes Applied ✅

Addressed all Critical, High, and Medium priority issues from code review.

Critical Issues Fixed (Security & Validation)

  1. Git Commit Validation

    • Added SHA format validation using regex: ^[a-f0-9]{7,40}$
    • Prevents command injection if database is compromised
    • Returns 500 error for invalid SHA formats
  2. Git Commit Existence Check

    • Added git cat-file -e verification before diff operations
    • Returns 404 with clear message if commit doesn't exist
    • Prevents cryptic 500 errors from missing commits
  3. Subprocess Security

    • All git commit SHAs validated before subprocess calls
    • Added 5-second timeout for verification
    • Added 30-second timeout for diff operations

High Priority Issues Fixed (Race Conditions & Memory)

  1. Race Condition Prevention

    • Implemented AbortController in CheckpointList.tsx
    • Cancels previous requests when new ones start
    • Prevents unexpected UI state and wasted API calls
    • API client now accepts optional AbortSignal
  2. Better Error Handling

    • Returns explicit 500 error when git diff --numstat fails
    • No more misleading zeros that look like "no changes"
    • Error messages include truncated stderr output for debugging
  3. Memory Limits

    • Backend: 10MB diff size limit with truncation message
    • Frontend: 10-item cache limit with LRU eviction
    • Prevents performance degradation with large/many checkpoints

Medium Priority Issues Fixed (UX & Accessibility)

  1. Component Cleanup

    • Added isMounted ref in CheckpointList.tsx
    • Prevents state updates on unmounted components
    • Cancels in-flight requests on unmount
    • No more React warnings or memory leaks
  2. Accessibility - Focus Management

    • Auto-focus Cancel button in DeleteConfirmationDialog
    • Keyboard users don't need to tab through entire page
    • 100ms delay to ensure dialog is rendered
  3. Binary File Tracking

    • Binary files counted separately (not as 0 insertions/deletions)
    • Exposed in X-Binary-Files HTTP header
    • Frontend can display binary file count if needed

Additional Improvements

  • ✅ HTTP caching headers: Cache-Control: public, max-age=31536000, immutable
  • ✅ Detailed error messages with failure context
  • ✅ All subprocess calls have timeouts
  • ✅ Improved logging for debugging

Testing

  • ✅ All 19 backend checkpoint manager tests passing
  • ✅ Python linting passes (ruff check)
  • ✅ No breaking changes to existing functionality

Files Changed

  • codeframe/ui/server.py - Enhanced security and validation
  • web-ui/src/components/checkpoints/CheckpointList.tsx - Race condition fixes
  • web-ui/src/api/checkpoints.ts - AbortSignal support
  • web-ui/src/components/checkpoints/DeleteConfirmationDialog.tsx - Focus management

Ready for re-review! 🚀

@claude

claude Bot commented Dec 5, 2025

Copy link
Copy Markdown

Code Review for PR #59: Checkpoint Diff Preview & Custom Delete Dialog

✅ Overall Assessment

This is a well-implemented feature that adds significant value to the checkpoint management UI. The code demonstrates strong attention to:

  • Security best practices
  • Performance optimization
  • Error handling
  • User experience

🔒 Security

Strengths:

  • Excellent command injection prevention (server.py:3506-3513): Git SHA validation with regex pattern before subprocess calls
  • Git commit verification before diff operations (server.py:3518-3533)
  • Proper input sanitization throughout

Recommendations:

  1. Consider path traversal protection in workspace_path
  2. Rate limiting: Consider adding rate limiting to the diff endpoint to prevent DoS via expensive git operations

🐛 Potential Issues

1. Race Condition in Cache Eviction (CheckpointList.tsx:212-217)
The cache eviction logic uses Map.keys().next().value which may not evict the oldest entry reliably. Consider tracking insertion order explicitly with timestamps.

2. Missing Path Import (server.py:3520)
The code uses Path(workspace_path) but does not import Path at the function level.

3. Potential Memory Leak (CheckpointList.tsx:191-198)
The isMounted check happens after state updates start. Check isMounted BEFORE starting async work.

⚡ Performance Considerations

Strengths:

  • Excellent caching strategy with 10-item limit prevents unbounded memory growth
  • AbortController usage (CheckpointList.tsx:187) prevents race conditions
  • Immutable cache headers (server.py:3593) enable browser-level caching
  • 10MB diff size limit (server.py:3544-3547) prevents memory exhaustion

Recommendations:

  1. Add debouncing for rapid expand/collapse clicks
  2. Consider pagination for very large diffs
  3. Add loading skeleton instead of spinner for better perceived performance

📊 Code Quality

Strengths:

  • Clear separation of concerns
  • Comprehensive error handling with user-friendly messages
  • Excellent accessibility (ARIA labels, keyboard support)
  • Clean, readable code with good comments

Minor Issues:

  1. Inconsistent error handling in handleConfirmDelete
  2. Magic numbers should be constants at module level
  3. TaskTreeView changes should be in separate PR (scope creep)

🧪 Test Coverage

Strengths:

  • E2E tests properly enabled
  • Tests cover both happy path and edge cases
  • All required testids implemented

Recommendations:

  1. Add backend unit tests for diff endpoint edge cases
  2. Add frontend unit tests for cache eviction, AbortController cleanup, error states

🎨 User Experience

Excellent UX decisions:

  • Click-to-expand is intuitive
  • Loading states provide clear feedback
  • Syntax highlighting makes diffs readable
  • Custom delete dialog is professional
  • Keyboard support (Escape, focus management)

✨ Verdict

APPROVED with minor recommendations. This PR significantly improves checkpoint management UX while maintaining security and performance best practices.

Risk: Low | Test Coverage: Good | Security: Strong | Performance: Good

Great work! 🎉

@frankbria
frankbria merged commit 7993baf into main Dec 5, 2025
8 of 10 checks passed
@frankbria
frankbria deleted the parallel-mishn4p7-euxv branch December 5, 2025 07:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement Checkpoint diff preview and proper delete confirmation dialog

1 participant