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:
adradr
2026-07-16 17:36:41 +02:00
committed by GitHub
co-authored by Mohamed Boudra
parent 5da6548aff
commit 0d3b717cf3
44 changed files with 2843 additions and 439 deletions
+102
View File
@@ -0,0 +1,102 @@
import type { CheckoutCommit } from "@getpaseo/protocol/messages";
import { useFetchQuery } from "@/data/query";
import { checkoutCommitsQueryKey } from "@/git/query-keys";
import { useHostRuntimeClient, useHostRuntimeIsConnected } from "@/runtime/host-runtime";
import { useSessionStore } from "@/stores/session-store";
// Commits ahead of base change rarely while the section is open; this keeps a
// collapse/re-expand cycle warm without leaving the fetch result stale for long.
const CHECKOUT_COMMITS_STALE_TIME = 30_000;
interface UseCheckoutCommitsQueryOptions {
serverId: string;
cwd: string;
enabled?: boolean;
}
export interface CheckoutCommitsData {
baseRef: string | null;
commits: CheckoutCommit[];
}
export type CheckoutCommitsQueryResult =
| { status: "unsupported" }
| { status: "idle" }
| { status: "connecting" }
| { status: "loading" }
| { status: "error"; error: Error }
| { status: "loaded"; data: CheckoutCommitsData };
interface ResolveCheckoutCommitsQueryResultInput {
enabled: boolean;
capabilityPresent: boolean;
canFetch: boolean;
data: CheckoutCommitsData | undefined;
isPlaceholderData: boolean;
error: Error | null;
}
export function resolveCheckoutCommitsQueryResult({
enabled,
capabilityPresent,
canFetch,
data,
isPlaceholderData,
error,
}: ResolveCheckoutCommitsQueryResultInput): CheckoutCommitsQueryResult {
if (!capabilityPresent) {
return { status: "unsupported" };
}
if (data && !isPlaceholderData) {
return { status: "loaded", data };
}
if (!enabled) {
return { status: "idle" };
}
if (!canFetch) {
return { status: "connecting" };
}
if (error) {
return { status: "error", error };
}
return { status: "loading" };
}
export function useCheckoutCommitsQuery({
serverId,
cwd,
enabled = true,
}: UseCheckoutCommitsQueryOptions): CheckoutCommitsQueryResult {
const client = useHostRuntimeClient(serverId);
const isConnected = useHostRuntimeIsConnected(serverId);
// COMPAT(commitsList): added in v0.1.110, remove gate after 2027-01-16.
// Single capability-detection site; downstream reads a clean load-state union.
const capabilityPresent = useSessionStore(
(state) => state.sessions[serverId]?.serverInfo?.features?.commitsList === true,
);
const canFetch = Boolean(cwd) && Boolean(client) && isConnected;
const queryEnabled = enabled && capabilityPresent && canFetch;
const query = useFetchQuery<CheckoutCommitsData>({
queryKey: checkoutCommitsQueryKey(serverId, cwd),
queryFn: async () => {
if (!client) {
throw new Error("Host disconnected");
}
return client.listCheckoutCommits(cwd);
},
enabled: queryEnabled,
staleTimeMs: CHECKOUT_COMMITS_STALE_TIME,
dataShape: "list",
});
return resolveCheckoutCommitsQueryResult({
enabled,
capabilityPresent,
canFetch,
data: query.data,
isPlaceholderData: query.isPlaceholderData,
error: query.error,
});
}