mirror of
https://github.com/backnotprop/plannotator.git
synced 2026-09-14 14:17:26 +08:00
4d2dc5772e
* fix(review): restore the prior diff when leaving the Commits view Clicking a commit in the Commits panel (or its HEAD auto-select) switches the single session-global diff to commit:<sha>, and switching the panel back to Tree never switched it back, leaving the review stuck on a historical commit (shipped as an accepted v1 edge in #994). A page reload did not escape either, since GET /api/diff serves the current session diff. Client-only fix: - preCommitDiffRef captures the pre-commit diff (full diff type + base) on the first non-commit to commit switch in handleSelectCommit. - Leaving Commits for Tree restores it via fetchDiffSwitch; without a memo (post-reload) it falls back to the session default with the same resolution handleWorktreeSwitch uses. Exiting while the commit switch is still in flight also restores, superseding it server-side. - Any applied non-commit switch clears the memo in fetchDiffSwitch. - Reload un-trap: a load that is served a commit diff while the opening panel view is not Commits snaps back to the session default once. Git status keeps its existing since-base reset; the server keeps its single-active-diff model unchanged. * test(review): cover the offered-but-not-first preferred default; document the Commits detour contract
53 lines
2.3 KiB
TypeScript
53 lines
2.3 KiB
TypeScript
import type { DiffOption } from '@plannotator/shared/types';
|
|
|
|
/** The diff a Commits-view exit should switch the session back to. */
|
|
export interface CommitViewRestoreTarget {
|
|
/** FULL diff type, worktree prefix included when one applies. */
|
|
diffType: string;
|
|
/** Base to send with the switch; null means "let the server keep its own". */
|
|
base: string | null;
|
|
}
|
|
|
|
// Same sha rule App.tsx's worktree parse and the server's parseCommitDiffType
|
|
// enforce: the commit family is exactly `commit:<bare-hex>` — either the whole
|
|
// diff type or the tail of a `worktree:<path>:commit:<sha>` composition (the
|
|
// path may itself contain colons, so only the anchored tail is trusted).
|
|
const COMMIT_FAMILY_RE = /(?:^|:)commit:[0-9a-f]{4,64}$/i;
|
|
|
|
/** True for the commit-family diff types (`commit:<sha>`, plain or
|
|
* worktree-composed). Takes the FULL diff type, unlike commitShaFromMode
|
|
* which reads the already-parsed base mode. */
|
|
export function isCommitDiffType(fullDiffType: string): boolean {
|
|
return COMMIT_FAMILY_RE.test(fullDiffType);
|
|
}
|
|
|
|
/**
|
|
* Resolve the diff to switch to when the panel view leaves Commits while a
|
|
* commit diff is active. The memo — captured when the session first entered
|
|
* the commit family — wins verbatim (full diff type + base, so the restore
|
|
* lands exactly where the reviewer was). Without one (the page reloaded while
|
|
* a commit diff was active; refs don't survive), fall back to the session
|
|
* default with the SAME resolution handleWorktreeSwitch applies when it
|
|
* abandons a commit diff: the configured default when the session offers it,
|
|
* else the first offered option, else uncommitted — composed against the
|
|
* active worktree so a worktree session stays in its worktree.
|
|
*/
|
|
export function resolveCommitExitDiff(
|
|
memo: CommitViewRestoreTarget | null,
|
|
fallback: {
|
|
preferredDefault: string | null | undefined;
|
|
diffOptions: ReadonlyArray<Pick<DiffOption, 'id'>>;
|
|
activeWorktreePath: string | null;
|
|
},
|
|
): CommitViewRestoreTarget {
|
|
if (memo) return memo;
|
|
const { preferredDefault, diffOptions, activeWorktreePath } = fallback;
|
|
const resolved = diffOptions.some((o) => o.id === preferredDefault)
|
|
? (preferredDefault as string)
|
|
: (diffOptions[0]?.id ?? 'uncommitted');
|
|
return {
|
|
diffType: activeWorktreePath ? `worktree:${activeWorktreePath}:${resolved}` : resolved,
|
|
base: null,
|
|
};
|
|
}
|