Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions apps/web/src/components/ChatView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2112,12 +2112,13 @@ function ChatViewContent(props: ChatViewProps) {
worktreePath: activeThread?.worktreePath ?? null,
})
: null;
const gitStatusCwd = activeThread?.worktreePath ?? gitCwd;
const gitStatusQuery = useEnvironmentQuery(
gitCwd === null
gitStatusCwd === null
? null
: vcsEnvironment.status({
environmentId,
input: { cwd: gitCwd },
input: { cwd: gitStatusCwd },
}),
);
const keybindings = useAtomValue(primaryServerKeybindingsAtom);
Expand Down Expand Up @@ -2151,6 +2152,9 @@ function ChatViewContent(props: ChatViewProps) {
terminalUiLaunchContext?.threadId === activeThreadId ? terminalUiLaunchContext : null;
// Default true while loading to avoid toolbar flicker.
const isGitRepo = gitStatusQuery.data?.isRepo ?? true;
const initialDiffPanelGitScope =
Comment thread
cursor[bot] marked this conversation as resolved.
gitStatusQuery.data?.hasWorkingTreeChanges === true ? "unstaged" : "branch";
const diffPanelGitStatusResolutionKey = gitStatusQuery.data ? "resolved" : "pending";
const terminalShortcutLabelOptions = useMemo(
() => ({
context: {
Expand Down Expand Up @@ -4968,7 +4972,12 @@ function ChatViewContent(props: ChatViewProps) {
/>
) : activeRightPanelSurface?.kind === "diff" ? (
<Suspense fallback={null}>
<DiffPanel mode="embedded" composerDraftTarget={composerDraftTarget} />
<DiffPanel
key={`${activeThreadKey}:${diffPanelGitStatusResolutionKey}`}
mode="embedded"
composerDraftTarget={composerDraftTarget}
initialGitScope={initialDiffPanelGitScope}
/>
</Suspense>
) : activeRightPanelSurface?.kind === "plan" ? (
<PlanSidebar
Expand Down
18 changes: 14 additions & 4 deletions apps/web/src/components/DiffPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -178,13 +178,19 @@ const DIFF_PANEL_UNSAFE_CSS = `
interface DiffPanelProps {
mode?: DiffPanelMode;
composerDraftTarget: ScopedThreadRef | DraftId;
initialGitScope: "branch" | "unstaged";
}

export { DiffWorkerPoolProvider } from "./DiffWorkerPoolProvider";

export default function DiffPanel({ mode = "inline", composerDraftTarget }: DiffPanelProps) {
export default function DiffPanel({
mode = "inline",
composerDraftTarget,
initialGitScope: initialGitScopeProp,
}: DiffPanelProps) {
const { resolvedTheme } = useTheme();
const settings = useClientSettings();
const [initialGitScope] = useState(initialGitScopeProp);
const [diffRenderMode, setDiffRenderMode] = useState<DiffRenderMode>("stacked");
const [wordWrap, setWordWrap] = useState(settings.wordWrap);
const [diffIgnoreWhitespace, setDiffIgnoreWhitespace] = useState(settings.diffIgnoreWhitespace);
Expand All @@ -199,9 +205,6 @@ export default function DiffPanel({ mode = "inline", composerDraftTarget }: Diff
strict: false,
select: (params) => resolveThreadRouteRef(params),
});
const diffSelection = useDiffPanelStore((state) =>
selectThreadDiffPanelSelection(state.byThreadKey, routeThreadRef),
);
const activeThreadId = routeThreadRef?.threadId ?? null;
const activeThread = useThread(routeThreadRef);
const activeProjectId = activeThread?.projectId ?? null;
Expand Down Expand Up @@ -229,6 +232,13 @@ export default function DiffPanel({ mode = "inline", composerDraftTarget }: Diff
})
: null,
);
const diffSelection = useDiffPanelStore((state) =>
Comment thread
macroscopeapp[bot] marked this conversation as resolved.
selectThreadDiffPanelSelection(
state.byThreadKey,
routeThreadRef,
initialGitScope === "unstaged",
),
);
const isGitRepo = gitStatusQuery.data?.isRepo ?? true;
const { turnDiffSummaries, inferredCheckpointTurnCountByTurnId } =
useTurnDiffSummaries(activeThread);
Expand Down
16 changes: 15 additions & 1 deletion apps/web/src/diffPanelStore.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,26 @@ const THREAD_REF = scopeThreadRef(EnvironmentId.make("environment-1"), ThreadId.
describe("diffPanelStore", () => {
beforeEach(() => useDiffPanelStore.setState({ byThreadKey: {}, branchBaseRefByThreadKey: {} }));

it("defaults each thread to branch changes with automatic base selection", () => {
it("defaults each thread to branch changes when the working tree is clean", () => {
expect(
selectThreadDiffPanelSelection(useDiffPanelStore.getState().byThreadKey, THREAD_REF),
).toEqual({ kind: "branch", baseRef: null });
});

it("defaults each thread to working changes when the working tree is dirty", () => {
expect(
selectThreadDiffPanelSelection(useDiffPanelStore.getState().byThreadKey, THREAD_REF, true),
).toEqual({ kind: "unstaged" });
});

it("preserves an explicit scope selection when the working tree state changes", () => {
useDiffPanelStore.getState().selectGitScope(THREAD_REF, "branch");

expect(
selectThreadDiffPanelSelection(useDiffPanelStore.getState().byThreadKey, THREAD_REF, true),
).toEqual({ kind: "branch", baseRef: null });
});

it("clears incompatible selection fields when changing scopes", () => {
const store = useDiffPanelStore.getState();
store.selectTurn(THREAD_REF, TurnId.make("turn-1"), "src/app.ts");
Expand Down
7 changes: 6 additions & 1 deletion apps/web/src/diffPanelStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export type DiffPanelSelection =
| { kind: "turn"; turnId: TurnId; filePath: string | null; revealRequestId: number };

const DEFAULT_SELECTION: DiffPanelSelection = { kind: "branch", baseRef: null };
const DEFAULT_WORKING_TREE_SELECTION: DiffPanelSelection = { kind: "unstaged" };

interface DiffPanelStoreState {
byThreadKey: Record<string, DiffPanelSelection>;
Expand Down Expand Up @@ -133,7 +134,11 @@ export const useDiffPanelStore = create<DiffPanelStoreState>()(
export function selectThreadDiffPanelSelection(
byThreadKey: Record<string, DiffPanelSelection>,
ref: ScopedThreadRef | null | undefined,
hasWorkingTreeChanges = false,
): DiffPanelSelection {
if (!ref) return DEFAULT_SELECTION;
return byThreadKey[scopedThreadKey(ref)] ?? DEFAULT_SELECTION;
return (
byThreadKey[scopedThreadKey(ref)] ??
(hasWorkingTreeChanges ? DEFAULT_WORKING_TREE_SELECTION : DEFAULT_SELECTION)
);
}
Loading