Git commit history (#1534)
* feat(app): add fileView preference for changes panel * feat(app): add buildDiffTree util for changed-files tree * feat(app): add changed-files tree directory row * feat(app): changed-files tree view mode in changes panel (#117) * feat(protocol): add checkout.commits.list RPC + commitsList feature flag * feat(server): list branch commits ahead of base with on-remote flags * feat(server): handle checkout.commits.list RPC and advertise capability * feat(client): checkout.commits.list method + useCommitsQuery hook * feat(app): per-commit inline view with local-vs-remote markers (#117) * feat(protocol,server): per-commit file diff RPC (checkout.commits.file_diff) * feat(app): open per-commit file diff on click (#117) * refactor: surface baseRef + commits loading/error, drop dead depth field * fix(app): flip commit local/remote dot — local hollow, remote filled * feat(app): list/tree view for expanded commit file list (#117) * fix(app): syntax-highlight per-commit file diff to match Changes view * feat(app): draggable resize between commits and diff sections * refactor(app): dedupe wrap-text helpers into diff-highlighted-text * fix(app): clean up commits resize drag on unmount + a11y label * fix(app): collapse commits section by default * fix(app): render per-commit file diff with the shared Changes line renderer * perf(app): memoize shared diff line row; drop redundant DiffLineView wrapper * refactor(app): extract shared DiffFileBody; render commit file diff through it * fix(app): hide inline-comment affordance in per-commit diffs (no reviewActions) * feat(app): move commits to a resizable bottom drawer in the Changes panel * feat(review): commitSha scoping for per-commit review drafts + attachment * feat(app): per-commit inline comments wired through to the composer (#117) * refactor(app): own commit file-diff open state in CommitFileList (drop reset effect) * refactor(app): colocate diff-render cluster under git/diff-file-body/ * feat(app): add diff tab target kind (working/commit diff tabs) * feat(app): useDiffFiles hook unifying working + commit diff targets * feat(app): diff tab panel rendering working/commit diffs * feat(app): open a commit diff tab on commit click; drop per-commit drawer/file list * feat(app): open/scroll working diff tab on changed-file click * fix(app): keep commit diff tabs ephemeral; align working diff whitespace * feat(app): collapsible file sections in the diff tab, collapsed by default * feat(app): make the on-remote commit dot more subtle Dims the filled green remote dot (row + legend) to ~0.55 opacity so the local-only ring stays the state that draws the eye. * Reshape commit diffs around the existing Changes view * Fix diff tab migration complexity after rebase * Address diff tab review findings * Clean up diff tab review interfaces * Collapse commit diffs into the existing view * Load commits when expanded --------- Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { describe, expect, test } from "vitest";
|
||||
import { describe, expect, it, test } from "vitest";
|
||||
import {
|
||||
buildDeterministicWorkspaceTabId,
|
||||
normalizeWorkspaceTabTarget,
|
||||
@@ -43,3 +43,56 @@ describe("provider subagent tab identity", () => {
|
||||
expect(first).not.toBe(second);
|
||||
});
|
||||
});
|
||||
|
||||
describe("commit diff tab identity", () => {
|
||||
it("keys a commit diff tab by its sha", () => {
|
||||
expect(buildDeterministicWorkspaceTabId({ kind: "commit_diff", sha: "abc123" })).toBe(
|
||||
"commit_diff_abc123",
|
||||
);
|
||||
});
|
||||
|
||||
it("does not collide a commit diff tab id with a file tab id", () => {
|
||||
const diffId = buildDeterministicWorkspaceTabId({ kind: "commit_diff", sha: "abc123" });
|
||||
const fileId = buildDeterministicWorkspaceTabId({
|
||||
kind: "file",
|
||||
path: "abc123",
|
||||
});
|
||||
expect(diffId).not.toBe(fileId);
|
||||
});
|
||||
|
||||
it("treats two commit diff targets with the same sha as equal", () => {
|
||||
expect(
|
||||
workspaceTabTargetsEqual(
|
||||
{ kind: "commit_diff", sha: "abc123" },
|
||||
{ kind: "commit_diff", sha: "abc123" },
|
||||
),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("treats commit diff targets with different shas as unequal", () => {
|
||||
expect(
|
||||
workspaceTabTargetsEqual(
|
||||
{ kind: "commit_diff", sha: "abc123" },
|
||||
{ kind: "commit_diff", sha: "def456" },
|
||||
),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it("normalizes a commit diff target", () => {
|
||||
expect(
|
||||
normalizeWorkspaceTabTarget({
|
||||
kind: "commit_diff",
|
||||
sha: "abc123",
|
||||
}),
|
||||
).toEqual({ kind: "commit_diff", sha: "abc123" });
|
||||
});
|
||||
|
||||
it("rejects a commit diff target with a blank sha", () => {
|
||||
expect(
|
||||
normalizeWorkspaceTabTarget({
|
||||
kind: "commit_diff",
|
||||
sha: " ",
|
||||
}),
|
||||
).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -28,22 +28,37 @@ export function normalizeWorkspaceTabTarget(
|
||||
? { kind: "provider_subagent", parentAgentId, subagentId }
|
||||
: null;
|
||||
}
|
||||
if (value.kind === "terminal") {
|
||||
const terminalId = trimNonEmpty(value.terminalId);
|
||||
return terminalId ? { kind: "terminal", terminalId } : null;
|
||||
}
|
||||
if (value.kind === "browser") {
|
||||
const browserId = trimNonEmpty(value.browserId);
|
||||
return browserId ? { kind: "browser", browserId } : null;
|
||||
}
|
||||
if (value.kind === "file") {
|
||||
return normalizeFileTabTarget(value);
|
||||
}
|
||||
if (value.kind === "setup") {
|
||||
const workspaceId = trimNonEmpty(value.workspaceId);
|
||||
return workspaceId ? { kind: "setup", workspaceId } : null;
|
||||
return normalizeSimpleWorkspaceTabTarget(value);
|
||||
}
|
||||
|
||||
function normalizeSimpleWorkspaceTabTarget(value: WorkspaceTabTarget): WorkspaceTabTarget | null {
|
||||
switch (value.kind) {
|
||||
case "agent": {
|
||||
const agentId = trimNonEmpty(value.agentId);
|
||||
return agentId ? { kind: "agent", agentId } : null;
|
||||
}
|
||||
case "terminal": {
|
||||
const terminalId = trimNonEmpty(value.terminalId);
|
||||
return terminalId ? { kind: "terminal", terminalId } : null;
|
||||
}
|
||||
case "browser": {
|
||||
const browserId = trimNonEmpty(value.browserId);
|
||||
return browserId ? { kind: "browser", browserId } : null;
|
||||
}
|
||||
case "setup": {
|
||||
const workspaceId = trimNonEmpty(value.workspaceId);
|
||||
return workspaceId ? { kind: "setup", workspaceId } : null;
|
||||
}
|
||||
case "commit_diff": {
|
||||
const sha = trimNonEmpty(value.sha);
|
||||
return sha ? { kind: "commit_diff", sha } : null;
|
||||
}
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function normalizeWorkspaceDraftTabSetup(
|
||||
@@ -98,6 +113,9 @@ export function workspaceTabTargetsEqual(
|
||||
if (left.kind === "setup" && right.kind === "setup") {
|
||||
return left.workspaceId === right.workspaceId;
|
||||
}
|
||||
if (left.kind === "commit_diff" && right.kind === "commit_diff") {
|
||||
return left.sha === right.sha;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -153,6 +171,9 @@ export function buildDeterministicWorkspaceTabId(target: WorkspaceTabTarget): st
|
||||
if (target.kind === "setup") {
|
||||
return `setup_${target.workspaceId}`;
|
||||
}
|
||||
if (target.kind === "commit_diff") {
|
||||
return `commit_diff_${target.sha}`;
|
||||
}
|
||||
return `file_${target.path}`;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user