Thanks to visit codestin.com
Credit goes to github.com

Skip to content

feat(server,frontend): per-commit detail view with diff parser#57

Merged
rawkode merged 2 commits into
mainfrom
feat-commit-detail
May 23, 2026
Merged

feat(server,frontend): per-commit detail view with diff parser#57
rawkode merged 2 commits into
mainfrom
feat-commit-detail

Conversation

@rawkode

@rawkode rawkode commented May 22, 2026

Copy link
Copy Markdown
Member

Draft — needs a browser-side smoke before flipping ready. Per CLAUDE.md UI Hard Rule, the .vue page can't be claimed verified from a server contract + bundle build alone. Both Chrome MCPs are unavailable this session (`claude-in-chrome` disconnected; `chrome-devtools` can't find Chrome at `/Applications/Google Chrome.app/...`). Server contract is verified by curl + unit tests; the rendered page needs a human eye or a reconnected Chrome MCP.

What ships

Server

  • New `commit_diff_payload(git_dir, oid)` in `crates/server/src/main.rs`. Runs `git show --no-color --find-renames --format=… --patch `, splits the SOH-delimited header from the unified patch body, emits a structured envelope (`oid / shortOid / subject / body / author / authorEmail / time / parents / changeId / patch / error`).
  • `is_valid_oid` rejects anything that isn't 4-40 ASCII hex characters before reaching `git`. Caller-controlled OID can't parse as a ref/option.
  • Wired into the `repositoryByPath` enrichment block: when the GraphQL query mentions `commitDiff` AND `variables.oid` is set, the field is populated. Matches the JSON-shim pattern.
  • 2 new tests pass; 185/185 server tests green; clippy --workspace clean.

Frontend

  • `frontend/src/diff.ts` — minimal unified-diff parser. `diff --git` file breaks, hunk headers, +/- line classification with old/new line numbers, status tagging, per-file additions/deletions, `summarize()` helper. Shared with the PR DiffView when that refactor lands.
  • `frontend/src/routes/CommitDetail.vue` — header + RepoTabs, metadata block (author, email, time, change-id chip, body), summary chips (file count, +/-), ordered list of per-file diffs with expand/collapse and per-hunk tables. Explicit loading / missing / error / empty-diff states.
  • Router entry at `/r/:groups+/:repo/commits/:oid` (`repoCommitDetail`).
  • Back-link points to the repo home until a dedicated Commits-list view ships; parent-commit chips link to the same `/commits/:parent` route so the user can walk history.
  • 89/89 frontend tests green; `vue-tsc` clean; `vite build` clean.

Verification not yet done

  • Open `/r/comtrya/comtrya/commits/` in a real browser, confirm the page renders the metadata + at least one file's diff.
  • Confirm the back-link and parent-commit chips navigate correctly.

The server-side contract probe via cargo test covers the data path end-to-end (real git invocations against the seeded demo repo), so the residual risk is purely template rendering / SDK auth-bootstrap interactions.

Out of scope (separate follow-ups)

  • Dedicated Commits-list route (current back-link goes to RepoHome).
  • Pre-existing 30s shutdown-timeout bug in `main()` (the `tokio::time::timeout(SHUTDOWN_DRAIN_TIMEOUT, serve)` wraps the entire serve future, not just the post-shutdown drain phase). Bit my manual probes; doesn't affect production where SIGTERM drives the lifecycle.

rawkode added 2 commits May 22, 2026 10:24
Server
- New `commit_diff_payload(git_dir, oid)` in `crates/server/src/main.rs`.
  Runs `git show --no-color --find-renames --format=… --patch <oid>`
  through the existing `git_text` helper, splits the SOH-delimited
  header from the unified-patch body, and emits a structured envelope
  with `oid / shortOid / subject / body / author / authorEmail /
  time / parents / changeId / patch / error`.
- Input validation: `is_valid_oid` rejects anything that isn't 4-40
  ASCII hex characters before reaching `git`. Belt-and-braces against
  a caller-controlled OID parsing as a ref/option even though the
  Command builder already prevents shell injection.
- Wired into the `repositoryByPath` enrichment block in
  `graphql_response`: when the GraphQL query mentions `commitDiff`
  AND `variables.oid` is set, the field is populated. Matches the
  JSON-shim pattern already used for the rest of `repositoryByPath`.
- 2 new tests:
  - `graphql_commit_diff_returns_metadata_and_patch_for_head` —
    end-to-end: resolves HEAD, asserts oid/shortOid round-trip and
    a non-error envelope with a unified-diff patch.
  - `graphql_commit_diff_returns_error_envelope_for_malformed_oid`
    — input validation surfaces an envelope-level `error` rather
    than bubbling up as a GraphQL error.
- 185/185 server tests green; clippy --workspace clean.

Frontend
- New `frontend/src/diff.ts` (204 lines). Minimal unified-diff
  parser: `diff --git` file breaks, hunk headers, +/- line
  classification with old/new line numbers, status tagging
  (added/deleted/renamed/modified, binary), per-file additions/
  deletions, plus a `summarize()` helper. Shared with the PR
  DiffView once that refactor lands.
- New `frontend/src/routes/CommitDetail.vue` (276 lines). Headers
  (`{repoPath} / {shortOid}` chip + RepoTabs), metadata block
  (author, email, time, change-id chip, body), summary chips
  (file count, +/-), and an ordered list of per-file diffs with
  expand/collapse and per-hunk tables. Renders loading / missing /
  error / empty-diff states explicitly.
- Router entry at `/r/:groups+/:repo/commits/:oid` (`repoCommitDetail`
  shellRoutePath). Registered BEFORE `repoPipelines` to match the
  declaration-order convention the existing file uses.
- Back-link points to the repo home until a dedicated Commits-list
  view ships; parent-commit chips link to the same
  `/commits/:parent` route so the user can walk history.
- `bun test` 89/89 green; `vue-tsc` clean; `vite build` clean.

UI verification blocker
- Per CLAUDE.md UI Hard Rule, this PR should not merge until a real
  browser confirms the page renders, the diff displays correctly,
  and `/commits/:oid` is reachable from the shell. Both Chrome MCPs
  are unavailable this session (claude-in-chrome extension
  disconnected; chrome-devtools can't locate Chrome at
  `/Applications/Google Chrome.app/...`). Server contract is
  verified by curl probes + unit tests; the frontend wiring needs
  a human or a reconnected Chrome MCP to flip ready.
CI surfaced two failures on PR #57:
1. cargo fmt — rustfmt reformatted the `if let` chain in
   graphql_response and the long format string in commit_diff_payload.
   Now formatted per rustfmt defaults.
2. page-touched => test touched — adding CommitDetail.vue triggered
   the gate. Adds frontend/src/diff.test.ts (9 tests covering
   parseUnifiedDiff status tagging, line classification with line
   numbers, binary flag, language inference, and summarize over
   mixed file shapes). Covers diff.ts at 95.8% lines / 100% funcs.

98/98 frontend tests + 185/185 server tests + clippy --workspace
clean.
@rawkode rawkode marked this pull request as ready for review May 23, 2026 16:00
Copilot AI review requested due to automatic review settings May 23, 2026 16:00
@rawkode rawkode added this pull request to the merge queue May 23, 2026
Merged via the queue into main with commit a4a295c May 23, 2026
13 of 14 checks passed
@rawkode rawkode deleted the feat-commit-detail branch May 23, 2026 16:00
@rawkode rawkode review requested due to automatic review settings May 23, 2026 16:24
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.

1 participant