From cb395ee13b5b5ddd4352e7c3d4216181501cc2e5 Mon Sep 17 00:00:00 2001 From: oliver <97427849+flamboh@users.noreply.github.com> Date: Wed, 14 Oct 2026 10:49:32 -0700 Subject: [PATCH] fix(web,mobile): pull request filters no longer offer the Scratch folder (#19179) --- .../pull-requests/PullRequestsScreen.tsx | 13 +++++-- .../pull-requests/pullRequestList.test.ts | 37 +++++++++++++++++++ .../features/pull-requests/pullRequestList.ts | 15 ++++++++ apps/web/src/routes/_chat.pull-requests.tsx | 7 +++- 4 files changed, 67 insertions(+), 5 deletions(-) diff --git a/apps/mobile/src/features/pull-requests/PullRequestsScreen.tsx b/apps/mobile/src/features/pull-requests/PullRequestsScreen.tsx index c37e957a4d1b1c731ffb54fc1fd79dc10f0a03cb..e3e8d3d0eb12031ea7beb38eb4707f570400d6dc 100644 --- a/apps/mobile/src/features/pull-requests/PullRequestsScreen.tsx +++ b/apps/mobile/src/features/pull-requests/PullRequestsScreen.tsx @@ -34,6 +34,7 @@ import { scopedPullRequestListKey as pullRequestKey, type EnvironmentPullRequestListEntry, PR_LIST_PAGE_SIZE, + withoutScratchProjectScope, } from "./pullRequestList"; import { useDebouncedValue } from "../../state/queries"; import { useWorkspaceTabs } from "../workspace/WorkspaceTabsContext"; @@ -102,7 +103,12 @@ export function PullRequestsScreen( }, [navigation, selectAndroidWorkspace], ); - const controls = listControls.controlsFor(environmentId); + const allProjects = useProjects(); + const savedControls = listControls.controlsFor(environmentId); + const controls = useMemo( + () => withoutScratchProjectScope(savedControls, allProjects), + [allProjects, savedControls], + ); const targets = useMemo( () => environments @@ -175,8 +181,9 @@ export function PullRequestsScreen( ].sort(), })); } - const projects = useProjects().filter( - (project) => environmentId === null || project.environmentId === environmentId, + const projects = allProjects.filter( + (project) => + !project.isScratch && (environmentId === null || project.environmentId === environmentId), ); const renderPullRequest = useCallback( ({ item }: { readonly item: EnvironmentPullRequestListEntry }) => ( diff --git a/apps/mobile/src/features/pull-requests/pullRequestList.test.ts b/apps/mobile/src/features/pull-requests/pullRequestList.test.ts index f3a085e02b453874a994fb3301ea8b2379157cfa..de5dd166ff1d4215e56330a0185f3c2d2bc9bd9f 100644 --- a/apps/mobile/src/features/pull-requests/pullRequestList.test.ts +++ b/apps/mobile/src/features/pull-requests/pullRequestList.test.ts @@ -18,6 +18,7 @@ import { pullRequestLabelColor, scopedPullRequestListKey, pullRequestListRowsAreEqual, + withoutScratchProjectScope, } from "./pullRequestList"; function entry(number: number, patch: Partial = {}): PullRequestListEntry { @@ -373,3 +374,39 @@ describe("mobile PR scan and filters", () => { expect(pullRequestLabelColor("not-a-color")).toBeNull(); }); }); + +describe("withoutScratchProjectScope", () => { + const projects = [ + { id: "repo", environmentId: "env-a" }, + { id: "scratch", environmentId: "env-a", isScratch: true as const }, + ]; + + it("reads a scope saved on the Scratch folder as all projects", () => { + const controls = withoutScratchProjectScope( + { ...DEFAULT_PR_LIST_CONTROLS, projectId: "scratch", projectEnvironmentId: "env-a" }, + projects, + ); + expect(controls.projectId).toBeUndefined(); + expect(controls.projectEnvironmentId).toBeUndefined(); + }); + + it("keeps a repository scope, and one whose projects have not arrived yet", () => { + const repository = { + ...DEFAULT_PR_LIST_CONTROLS, + projectId: "repo", + projectEnvironmentId: "env-a", + }; + expect(withoutScratchProjectScope(repository, projects)).toBe(repository); + const pending = { ...repository, projectId: "scratch" }; + expect(withoutScratchProjectScope(pending, [])).toBe(pending); + }); + + it("keeps another server's project that shares the Scratch folder's id", () => { + const elsewhere = { + ...DEFAULT_PR_LIST_CONTROLS, + projectId: "scratch", + projectEnvironmentId: "env-b", + }; + expect(withoutScratchProjectScope(elsewhere, projects)).toBe(elsewhere); + }); +}); diff --git a/apps/mobile/src/features/pull-requests/pullRequestList.ts b/apps/mobile/src/features/pull-requests/pullRequestList.ts index 4527ba1e295d08839054f2dfbd3f31c361027ee6..f0deeef6c974437182b286eab83e4a059c9a4e9c 100644 --- a/apps/mobile/src/features/pull-requests/pullRequestList.ts +++ b/apps/mobile/src/features/pull-requests/pullRequestList.ts @@ -15,6 +15,21 @@ export const DEFAULT_PR_LIST_CONTROLS: PullRequestListControls = { sort: "updated", }; +/** A scope saved on the Scratch folder is no longer offered, so it reads as "All projects". */ +export function withoutScratchProjectScope( + controls: PullRequestListControls, + projects: readonly { id: string; environmentId: string; isScratch?: true }[], +): PullRequestListControls { + return projects.some( + (project) => + project.isScratch && + project.id === controls.projectId && + project.environmentId === controls.projectEnvironmentId, + ) + ? { ...controls, projectId: undefined, projectEnvironmentId: undefined } + : controls; +} + export function pullRequestListKey( item: Pick, ) { diff --git a/apps/web/src/routes/_chat.pull-requests.tsx b/apps/web/src/routes/_chat.pull-requests.tsx index f5ff710c1ac5b817e21069adbf0b5b0f8d3bea1b..bbd05e76cbbbbef04093faa44e6fcb0dd9970da0 100644 --- a/apps/web/src/routes/_chat.pull-requests.tsx +++ b/apps/web/src/routes/_chat.pull-requests.tsx @@ -411,9 +411,12 @@ function PullRequestsRouteView() { // the one wrong answer the empty state can give. const projectsKnown = useAllEnvironmentShellsBootstrapped(); // Only the projects the page can actually read: one on an environment that cannot list pull - // requests could neither be listed nor acted on. + // requests could neither be listed nor acted on, and the Scratch folder is never a repository. const projects = useMemo( - () => allProjects.filter((project) => environmentIds.includes(project.environmentId)), + () => + allProjects.filter( + (project) => !project.isScratch && environmentIds.includes(project.environmentId), + ), [allProjects, environmentIds], ); const environmentLabels = useMemo( -- 2.54.0