mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-05 16:04:43 +00:00
* 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>
92 lines
3.0 KiB
TypeScript
92 lines
3.0 KiB
TypeScript
import { useMemo } from "react";
|
|
import { useReplicaQuery } from "@/data/query";
|
|
import { checkoutDiffPushRoute } from "@/data/push-router";
|
|
import { useHostRuntimeIsConnected } from "@/runtime/host-runtime";
|
|
import type { ParsedDiffFile, SubscribeCheckoutDiffResponse } from "@getpaseo/protocol/messages";
|
|
import { checkoutDiffQueryKey } from "@/git/query-keys";
|
|
|
|
interface UseCheckoutDiffQueryOptions {
|
|
serverId: string;
|
|
cwd: string;
|
|
mode: "uncommitted" | "base";
|
|
baseRef?: string;
|
|
ignoreWhitespace?: boolean;
|
|
enabled?: boolean;
|
|
}
|
|
|
|
type CheckoutDiffQueryPayload = Omit<SubscribeCheckoutDiffResponse["payload"], "subscriptionId">;
|
|
|
|
// Re-export the canonical protocol type so all consumers share one definition.
|
|
export type { ParsedDiffFile };
|
|
export type DiffHunk = ParsedDiffFile["hunks"][number];
|
|
export type DiffLine = DiffHunk["lines"][number];
|
|
export type HighlightToken = NonNullable<DiffLine["tokens"]>[number];
|
|
|
|
function normalizeCheckoutDiffCompare(compare: {
|
|
mode: "uncommitted" | "base";
|
|
baseRef?: string;
|
|
ignoreWhitespace?: boolean;
|
|
}): { mode: "uncommitted" | "base"; baseRef?: string; ignoreWhitespace?: boolean } {
|
|
const ignoreWhitespace = compare.ignoreWhitespace === true;
|
|
if (compare.mode === "uncommitted") {
|
|
return { mode: "uncommitted", ignoreWhitespace };
|
|
}
|
|
const trimmedBaseRef = compare.baseRef?.trim();
|
|
return trimmedBaseRef
|
|
? { mode: "base", baseRef: trimmedBaseRef, ignoreWhitespace }
|
|
: { mode: "base", ignoreWhitespace };
|
|
}
|
|
|
|
export function useCheckoutDiffQuery({
|
|
serverId,
|
|
cwd,
|
|
mode,
|
|
baseRef,
|
|
ignoreWhitespace,
|
|
enabled = true,
|
|
}: UseCheckoutDiffQueryOptions) {
|
|
const isConnected = useHostRuntimeIsConnected(serverId);
|
|
const normalizedCompare = useMemo(
|
|
() => normalizeCheckoutDiffCompare({ mode, baseRef, ignoreWhitespace }),
|
|
[mode, baseRef, ignoreWhitespace],
|
|
);
|
|
const compareMode = normalizedCompare.mode;
|
|
const compareBaseRef = normalizedCompare.baseRef;
|
|
const compareIgnoreWhitespace = normalizedCompare.ignoreWhitespace;
|
|
const queryKey = useMemo(
|
|
() => checkoutDiffQueryKey(serverId, cwd, mode, baseRef, compareIgnoreWhitespace),
|
|
[serverId, cwd, mode, baseRef, compareIgnoreWhitespace],
|
|
);
|
|
const subscriptionId = useMemo(() => `checkoutDiff:${JSON.stringify(queryKey)}`, [queryKey]);
|
|
const routeEnabled = Boolean(enabled && isConnected && cwd);
|
|
|
|
const query = useReplicaQuery<CheckoutDiffQueryPayload>({
|
|
queryKey,
|
|
enabled: routeEnabled,
|
|
pushEvent: "checkout_diff_update",
|
|
meta: checkoutDiffPushRoute({
|
|
enabled: routeEnabled,
|
|
serverId,
|
|
subscriptionId,
|
|
cwd,
|
|
compare: {
|
|
mode: compareMode,
|
|
...(compareBaseRef ? { baseRef: compareBaseRef } : {}),
|
|
ignoreWhitespace: compareIgnoreWhitespace,
|
|
},
|
|
}),
|
|
});
|
|
|
|
const payload = query.data ?? null;
|
|
const payloadError = payload?.error ?? null;
|
|
|
|
return {
|
|
files: payload?.files ?? [],
|
|
payloadError,
|
|
isLoading: payload === null && enabled && isConnected,
|
|
isFetching: false,
|
|
isError: Boolean(payloadError),
|
|
error: null,
|
|
};
|
|
}
|