History

Default diffs to working changes (#3974)

Jake Leventhal committed 3 months ago

Commit 38e0bb01 parent 765e1b54 files · +47 −9Browse files

Unified · Split

4 files
  1. apps/web/src/components/ChatView.tsx +12 −3
  2. apps/web/src/components/DiffPanel.tsx +14 −4
  3. apps/web/src/diffPanelStore.test.ts +15 −1
  4. apps/web/src/diffPanelStore.ts +6 −1
apps/web/src/components/ChatView.tsx+12−3
@@ -2252,12 +2252,13 @@ function ChatViewContent(props: ChatViewProps) { · 2251 unmodified lines
22522252 worktreePath: activeThread?.worktreePath ?? null,
22532253 })
22542254 : null;
2255+ const gitStatusCwd = activeThread?.worktreePath ?? gitCwd;
22552256 const gitStatusQuery = useEnvironmentQuery(
2256− gitCwd === null
2257+ gitStatusCwd === null
22572258 ? null
22582259 : vcsEnvironment.status({
22592260 environmentId,
2260− input: { cwd: gitCwd },
2261+ input: { cwd: gitStatusCwd },
22612262 }),
22622263 );
22632264 const keybindings = useAtomValue(primaryServerKeybindingsAtom);
@@ -2291,6 +2292,9 @@ function ChatViewContent(props: ChatViewProps) { · 27 unmodified lines
22912292 terminalUiLaunchContext?.threadId === activeThreadId ? terminalUiLaunchContext : null;
22922293 // Default true while loading to avoid toolbar flicker.
22932294 const isGitRepo = gitStatusQuery.data?.isRepo ?? true;
2295+ const initialDiffPanelGitScope =
2296+ gitStatusQuery.data?.hasWorkingTreeChanges === true ? "unstaged" : "branch";
2297+ const diffPanelGitStatusResolutionKey = gitStatusQuery.data ? "resolved" : "pending";
22942298 const terminalShortcutLabelOptions = useMemo(
22952299 () => ({
22962300 context: {
@@ -5136,7 +5140,12 @@ function ChatViewContent(props: ChatViewProps) { · 2839 unmodified lines
51365140 />
51375141 ) : activeRightPanelSurface?.kind === "diff" ? (
51385142 <Suspense fallback={null}>
5139− <DiffPanel mode="embedded" composerDraftTarget={composerDraftTarget} />
5143+ <DiffPanel
5144+ key={`${activeThreadKey}:${diffPanelGitStatusResolutionKey}`}
5145+ mode="embedded"
5146+ composerDraftTarget={composerDraftTarget}
5147+ initialGitScope={initialDiffPanelGitScope}
5148+ />
51405149 </Suspense>
51415150 ) : activeRightPanelSurface?.kind === "plan" ? (
51425151 <PlanSidebar
apps/web/src/components/DiffPanel.tsx+14−4
@@ -178,13 +178,19 @@ const DIFF_PANEL_UNSAFE_CSS = ` · 177 unmodified lines
178178 interface DiffPanelProps {
179179 mode?: DiffPanelMode;
180180 composerDraftTarget: ScopedThreadRef | DraftId;
181+ initialGitScope: "branch" | "unstaged";
181182 }
182183
183184 export { DiffWorkerPoolProvider } from "./DiffWorkerPoolProvider";
184185
185−export default function DiffPanel({ mode = "inline", composerDraftTarget }: DiffPanelProps) {
186+export default function DiffPanel({
187+ mode = "inline",
188+ composerDraftTarget,
189+ initialGitScope: initialGitScopeProp,
190+}: DiffPanelProps) {
186191 const { resolvedTheme } = useTheme();
187192 const settings = useClientSettings();
193+ const [initialGitScope] = useState(initialGitScopeProp);
188194 const [diffRenderMode, setDiffRenderMode] = useState<DiffRenderMode>("stacked");
189195 const [wordWrap, setWordWrap] = useState(settings.wordWrap);
190196 const [diffIgnoreWhitespace, setDiffIgnoreWhitespace] = useState(settings.diffIgnoreWhitespace);
@@ -199,9 +205,6 @@ export default function DiffPanel({ mode = "inline", composerDraftTarget }: Diff · 8 unmodified lines
199205 strict: false,
200206 select: (params) => resolveThreadRouteRef(params),
201207 });
202− const diffSelection = useDiffPanelStore((state) =>
203− selectThreadDiffPanelSelection(state.byThreadKey, routeThreadRef),
204− );
205208 const activeThreadId = routeThreadRef?.threadId ?? null;
206209 const activeThread = useThread(routeThreadRef);
207210 const activeProjectId = activeThread?.projectId ?? null;
@@ -229,6 +232,13 @@ export default function DiffPanel({ mode = "inline", composerDraftTarget }: Diff · 21 unmodified lines
229232 })
230233 : null,
231234 );
235+ const diffSelection = useDiffPanelStore((state) =>
236+ selectThreadDiffPanelSelection(
237+ state.byThreadKey,
238+ routeThreadRef,
239+ initialGitScope === "unstaged",
240+ ),
241+ );
232242 const isGitRepo = gitStatusQuery.data?.isRepo ?? true;
233243 const { turnDiffSummaries, inferredCheckpointTurnCountByTurnId } =
234244 useTurnDiffSummaries(activeThread);
apps/web/src/diffPanelStore.test.ts+15−1
@@ -9,12 +9,26 @@ const THREAD_REF = scopeThreadRef(EnvironmentId.make("environment-1"), ThreadId. · 8 unmodified lines
99 describe("diffPanelStore", () => {
1010 beforeEach(() => useDiffPanelStore.setState({ byThreadKey: {}, branchBaseRefByThreadKey: {} }));
1111
12− it("defaults each thread to branch changes with automatic base selection", () => {
12+ it("defaults each thread to branch changes when the working tree is clean", () => {
1313 expect(
1414 selectThreadDiffPanelSelection(useDiffPanelStore.getState().byThreadKey, THREAD_REF),
1515 ).toEqual({ kind: "branch", baseRef: null });
1616 });
1717
18+ it("defaults each thread to working changes when the working tree is dirty", () => {
19+ expect(
20+ selectThreadDiffPanelSelection(useDiffPanelStore.getState().byThreadKey, THREAD_REF, true),
21+ ).toEqual({ kind: "unstaged" });
22+ });
23+
24+ it("preserves an explicit scope selection when the working tree state changes", () => {
25+ useDiffPanelStore.getState().selectGitScope(THREAD_REF, "branch");
26+
27+ expect(
28+ selectThreadDiffPanelSelection(useDiffPanelStore.getState().byThreadKey, THREAD_REF, true),
29+ ).toEqual({ kind: "branch", baseRef: null });
30+ });
31+
1832 it("clears incompatible selection fields when changing scopes", () => {
1933 const store = useDiffPanelStore.getState();
2034 store.selectTurn(THREAD_REF, TurnId.make("turn-1"), "src/app.ts");
apps/web/src/diffPanelStore.ts+6−1
@@ -11,6 +11,7 @@ export type DiffPanelSelection = · 10 unmodified lines
1111 | { kind: "turn"; turnId: TurnId; filePath: string | null; revealRequestId: number };
1212
1313 const DEFAULT_SELECTION: DiffPanelSelection = { kind: "branch", baseRef: null };
14+const DEFAULT_WORKING_TREE_SELECTION: DiffPanelSelection = { kind: "unstaged" };
1415
1516 interface DiffPanelStoreState {
1617 byThreadKey: Record<string, DiffPanelSelection>;
@@ -133,7 +134,11 @@ export const useDiffPanelStore = create<DiffPanelStoreState>()( · 116 unmodified lines
133134 export function selectThreadDiffPanelSelection(
134135 byThreadKey: Record<string, DiffPanelSelection>,
135136 ref: ScopedThreadRef | null | undefined,
137+ hasWorkingTreeChanges = false,
136138 ): DiffPanelSelection {
137139 if (!ref) return DEFAULT_SELECTION;
138− return byThreadKey[scopedThreadKey(ref)] ?? DEFAULT_SELECTION;
140+ return (
141+ byThreadKey[scopedThreadKey(ref)] ??
142+ (hasWorkingTreeChanges ? DEFAULT_WORKING_TREE_SELECTION : DEFAULT_SELECTION)
143+ );
139144 }