Skip to content

feat(code): add diff source selector#1785

Open
adboio wants to merge 1 commit intomainfrom
04-21-feat_code_add_diff_source_selector
Open

feat(code): add diff source selector#1785
adboio wants to merge 1 commit intomainfrom
04-21-feat_code_add_diff_source_selector

Conversation

@adboio
Copy link
Copy Markdown
Contributor

@adboio adboio commented Apr 21, 2026

Problem

for local tasks we only show one diff - just the local diff state

this means when you push changes or open a PR, the diff panel becomes empty

Changes

adds a new diff source selector dropdown menu

right now it has two options:

  1. local (what we had already)
  2. branch vs. default

this will include "PR" as an option soon!

Screenshot 2026-04-21 at 4.06.41 PM.png
Screenshot 2026-04-21 at 4.06.43 PM.png

How did you test this?

manully

Copy link
Copy Markdown
Contributor Author

adboio commented Apr 21, 2026

This stack of pull requests is managed by Graphite. Learn more about stacking.

@adboio adboio requested a review from a team April 21, 2026 20:17
@adboio adboio marked this pull request as ready for review April 21, 2026 20:19
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Apr 21, 2026

Prompt To Fix All With AI
This is a comment left during a code review.
Path: apps/code/src/renderer/features/code-review/utils/resolveDiffSource.test.ts
Line: 1-96

Comment:
**Prefer parameterised tests**

All 8 test cases call the same function with different inputs — this is exactly what `it.each` is for. Per the team's standard, parameterised tests are preferred.

```ts
describe("resolveDiffSource", () => {
  it.each([
    // heuristic (no user choice)
    { configured: null, hasLocalChanges: true,  linkedBranch: "feat/x", aheadOfDefault: 3, expected: "local",  desc: "uncommitted changes → local" },
    { configured: null, hasLocalChanges: false, linkedBranch: "feat/x", aheadOfDefault: 2, expected: "branch", desc: "clean tree with commits ahead → branch" },
    { configured: null, hasLocalChanges: false, linkedBranch: null,     aheadOfDefault: 0, expected: "local",  desc: "no linked branch → local" },
    { configured: null, hasLocalChanges: false, linkedBranch: "feat/x", aheadOfDefault: 0, expected: "local",  desc: "no commits ahead → local" },
    // explicit override
    { configured: "local",  hasLocalChanges: false, linkedBranch: "feat/x", aheadOfDefault: 5, expected: "local",  desc: "explicit local respected even when branch available" },
    { configured: "branch", hasLocalChanges: true,  linkedBranch: "feat/x", aheadOfDefault: 1, expected: "branch", desc: "explicit branch respected when available" },
    { configured: "branch", hasLocalChanges: false, linkedBranch: null,     aheadOfDefault: 0, expected: "local",  desc: "explicit branch falls back to local (no linked branch)" },
    { configured: "branch", hasLocalChanges: false, linkedBranch: "feat/x", aheadOfDefault: 0, expected: "local",  desc: "explicit branch falls back to local (no commits ahead)" },
  ] as const)("$desc", ({ configured, hasLocalChanges, linkedBranch, aheadOfDefault, expected }) => {
    expect(resolveDiffSource({ configured, hasLocalChanges, linkedBranch, aheadOfDefault })).toBe(expected);
  });
});
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: apps/code/src/renderer/features/code-review/components/ReviewPage.tsx
Line: 201-211

Comment:
**Misleading empty state when `repoSlug` is unavailable**

When `repoInfo` is `undefined` (e.g., `useGitQueries` hasn't resolved yet or the remote origin is unset), `repoSlug` is `null` and the query is disabled. `files` stays as `EMPTY_BRANCH_FILES`, so `isLoading` is `false` and `isEmpty` is `true`, causing "No file changes to review" to appear — even though the real issue is that the repo slug couldn't be determined. A user who has commits ahead of default would see this and think the feature is broken.

Consider checking `!repoSlug` explicitly and rendering a distinct message, or keeping `isLoading={isLoading || (!repoSlug && isReviewOpen)}` to show the spinner while metadata is still resolving.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "feat(code): add diff source selector" | Re-trigger Greptile

Comment on lines +1 to +96
import { describe, expect, it } from "vitest";
import { resolveDiffSource } from "./resolveDiffSource";

describe("resolveDiffSource", () => {
describe("heuristic (no user choice)", () => {
it("picks local when there are uncommitted changes", () => {
expect(
resolveDiffSource({
configured: null,
hasLocalChanges: true,
linkedBranch: "feat/x",
aheadOfDefault: 3,
}),
).toBe("local");
});

it("picks branch on clean tree with commits ahead", () => {
expect(
resolveDiffSource({
configured: null,
hasLocalChanges: false,
linkedBranch: "feat/x",
aheadOfDefault: 2,
}),
).toBe("branch");
});

it("picks local on clean tree with no linked branch", () => {
expect(
resolveDiffSource({
configured: null,
hasLocalChanges: false,
linkedBranch: null,
aheadOfDefault: 0,
}),
).toBe("local");
});

it("picks local on clean tree with linked branch but no commits ahead", () => {
expect(
resolveDiffSource({
configured: null,
hasLocalChanges: false,
linkedBranch: "feat/x",
aheadOfDefault: 0,
}),
).toBe("local");
});
});

describe("explicit override", () => {
it("respects explicit local even when branch is available", () => {
expect(
resolveDiffSource({
configured: "local",
hasLocalChanges: false,
linkedBranch: "feat/x",
aheadOfDefault: 5,
}),
).toBe("local");
});

it("respects explicit branch when available", () => {
expect(
resolveDiffSource({
configured: "branch",
hasLocalChanges: true,
linkedBranch: "feat/x",
aheadOfDefault: 1,
}),
).toBe("branch");
});

it("falls back to local when explicit branch is unavailable (no linked branch)", () => {
expect(
resolveDiffSource({
configured: "branch",
hasLocalChanges: false,
linkedBranch: null,
aheadOfDefault: 0,
}),
).toBe("local");
});

it("falls back to local when explicit branch is unavailable (no commits ahead)", () => {
expect(
resolveDiffSource({
configured: "branch",
hasLocalChanges: false,
linkedBranch: "feat/x",
aheadOfDefault: 0,
}),
).toBe("local");
});
});
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Prefer parameterised tests

All 8 test cases call the same function with different inputs — this is exactly what it.each is for. Per the team's standard, parameterised tests are preferred.

describe("resolveDiffSource", () => {
  it.each([
    // heuristic (no user choice)
    { configured: null, hasLocalChanges: true,  linkedBranch: "feat/x", aheadOfDefault: 3, expected: "local",  desc: "uncommitted changes → local" },
    { configured: null, hasLocalChanges: false, linkedBranch: "feat/x", aheadOfDefault: 2, expected: "branch", desc: "clean tree with commits ahead → branch" },
    { configured: null, hasLocalChanges: false, linkedBranch: null,     aheadOfDefault: 0, expected: "local",  desc: "no linked branch → local" },
    { configured: null, hasLocalChanges: false, linkedBranch: "feat/x", aheadOfDefault: 0, expected: "local",  desc: "no commits ahead → local" },
    // explicit override
    { configured: "local",  hasLocalChanges: false, linkedBranch: "feat/x", aheadOfDefault: 5, expected: "local",  desc: "explicit local respected even when branch available" },
    { configured: "branch", hasLocalChanges: true,  linkedBranch: "feat/x", aheadOfDefault: 1, expected: "branch", desc: "explicit branch respected when available" },
    { configured: "branch", hasLocalChanges: false, linkedBranch: null,     aheadOfDefault: 0, expected: "local",  desc: "explicit branch falls back to local (no linked branch)" },
    { configured: "branch", hasLocalChanges: false, linkedBranch: "feat/x", aheadOfDefault: 0, expected: "local",  desc: "explicit branch falls back to local (no commits ahead)" },
  ] as const)("$desc", ({ configured, hasLocalChanges, linkedBranch, aheadOfDefault, expected }) => {
    expect(resolveDiffSource({ configured, hasLocalChanges, linkedBranch, aheadOfDefault })).toBe(expected);
  });
});
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/code/src/renderer/features/code-review/utils/resolveDiffSource.test.ts
Line: 1-96

Comment:
**Prefer parameterised tests**

All 8 test cases call the same function with different inputs — this is exactly what `it.each` is for. Per the team's standard, parameterised tests are preferred.

```ts
describe("resolveDiffSource", () => {
  it.each([
    // heuristic (no user choice)
    { configured: null, hasLocalChanges: true,  linkedBranch: "feat/x", aheadOfDefault: 3, expected: "local",  desc: "uncommitted changes → local" },
    { configured: null, hasLocalChanges: false, linkedBranch: "feat/x", aheadOfDefault: 2, expected: "branch", desc: "clean tree with commits ahead → branch" },
    { configured: null, hasLocalChanges: false, linkedBranch: null,     aheadOfDefault: 0, expected: "local",  desc: "no linked branch → local" },
    { configured: null, hasLocalChanges: false, linkedBranch: "feat/x", aheadOfDefault: 0, expected: "local",  desc: "no commits ahead → local" },
    // explicit override
    { configured: "local",  hasLocalChanges: false, linkedBranch: "feat/x", aheadOfDefault: 5, expected: "local",  desc: "explicit local respected even when branch available" },
    { configured: "branch", hasLocalChanges: true,  linkedBranch: "feat/x", aheadOfDefault: 1, expected: "branch", desc: "explicit branch respected when available" },
    { configured: "branch", hasLocalChanges: false, linkedBranch: null,     aheadOfDefault: 0, expected: "local",  desc: "explicit branch falls back to local (no linked branch)" },
    { configured: "branch", hasLocalChanges: false, linkedBranch: "feat/x", aheadOfDefault: 0, expected: "local",  desc: "explicit branch falls back to local (no commits ahead)" },
  ] as const)("$desc", ({ configured, hasLocalChanges, linkedBranch, aheadOfDefault, expected }) => {
    expect(resolveDiffSource({ configured, hasLocalChanges, linkedBranch, aheadOfDefault })).toBe(expected);
  });
});
```

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +201 to +211
const { data: files = EMPTY_BRANCH_FILES, isLoading } = useQuery(
trpc.git.getBranchChangedFiles.queryOptions(
{ repo: repoSlug as string, branch },
{
enabled: isReviewOpen && !!repoSlug,
staleTime: 30_000,
refetchInterval: 30_000,
retry: 1,
},
),
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Misleading empty state when repoSlug is unavailable

When repoInfo is undefined (e.g., useGitQueries hasn't resolved yet or the remote origin is unset), repoSlug is null and the query is disabled. files stays as EMPTY_BRANCH_FILES, so isLoading is false and isEmpty is true, causing "No file changes to review" to appear — even though the real issue is that the repo slug couldn't be determined. A user who has commits ahead of default would see this and think the feature is broken.

Consider checking !repoSlug explicitly and rendering a distinct message, or keeping isLoading={isLoading || (!repoSlug && isReviewOpen)} to show the spinner while metadata is still resolving.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/code/src/renderer/features/code-review/components/ReviewPage.tsx
Line: 201-211

Comment:
**Misleading empty state when `repoSlug` is unavailable**

When `repoInfo` is `undefined` (e.g., `useGitQueries` hasn't resolved yet or the remote origin is unset), `repoSlug` is `null` and the query is disabled. `files` stays as `EMPTY_BRANCH_FILES`, so `isLoading` is `false` and `isEmpty` is `true`, causing "No file changes to review" to appear — even though the real issue is that the repo slug couldn't be determined. A user who has commits ahead of default would see this and think the feature is broken.

Consider checking `!repoSlug` explicitly and rendering a distinct message, or keeping `isLoading={isLoading || (!repoSlug && isReviewOpen)}` to show the spinner while metadata is still resolving.

How can I resolve this? If you propose a fix, please make it concise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant