| author | |
| committer | |
| log | df26ef99859ac757409f5332b185a89cc7f40267 |
| tree | c110820d985ecc0b9c643c31cff16cb49f816fab |
| parent | 41d86c1b1c273ed662d59c90aa9685476bac962c |
| signature | Signed by PGP key B5690EEEBB952194 |
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>3 files changed, 44 insertions(+), 2 deletions(-)
apps/web/src/components/pullRequest/pullRequestListPreferences.ts+1-1| ... | @@ -25,7 +25,7 @@ export interface PullRequestListPreferences { | ... | @@ -25,7 +25,7 @@ export interface PullRequestListPreferences { |
| 25 | readonly environmentId?: EnvironmentId; | 25 | readonly environmentId?: EnvironmentId; |
| 26 | readonly projectId?: ProjectId; | 26 | readonly projectId?: ProjectId; |
| 27 | readonly host?: string; | 27 | readonly host?: string; |
| 28 | readonly q?: string; | 28 | readonly q?: string | undefined; |
| 29 | readonly draft?: "only" | "hide"; | 29 | readonly draft?: "only" | "hide"; |
| 30 | readonly review?: NonNullable<PullRequestListFilters["review"]>; | 30 | readonly review?: NonNullable<PullRequestListFilters["review"]>; |
| 31 | readonly checks?: NonNullable<PullRequestListFilters["checks"]>; | 31 | readonly checks?: NonNullable<PullRequestListFilters["checks"]>; |
apps/web/src/components/pullRequest/pullRequestsRouteSearch.test.ts created+40| ... | @@ -0,0 +1,40 @@ | ||
| 1 | import { | ||
| 2 | createMemoryHistory, | ||
| 3 | createRootRoute, | ||
| 4 | createRoute, | ||
| 5 | createRouter, | ||
| 6 | } from "@tanstack/react-router"; | ||
| 7 | import { describe, expect, it } from "vite-plus/test"; | ||
| 8 | |||
| 9 | import { Route as PullRequestsRoute } from "../../routes/_chat.pull-requests"; | ||
| 10 | |||
| 11 | /** Matches a URL in a router shaped like the app's: a layout without its own search rules. */ | ||
| 12 | function matchedSearch(url: string) { | ||
| 13 | const root = createRootRoute(); | ||
| 14 | const chat = createRoute({ getParentRoute: () => root, id: "_chat" }); | ||
| 15 | const pullRequests = createRoute({ | ||
| 16 | getParentRoute: () => chat, | ||
| 17 | path: "pull-requests", | ||
| 18 | validateSearch: PullRequestsRoute.options.validateSearch, | ||
| 19 | }); | ||
| 20 | const router = createRouter({ | ||
| 21 | routeTree: root.addChildren([chat.addChildren([pullRequests])]), | ||
| 22 | history: createMemoryHistory({ initialEntries: [url] }), | ||
| 23 | }); | ||
| 24 | // The search a component reads through `useSearch` is the matched route's, not the URL's. | ||
| 25 | return router.matchRoutes(router.latestLocation).at(-1)?.search as | ||
| 26 | | Record<string, unknown> | ||
| 27 | | undefined; | ||
| 28 | } | ||
| 29 | |||
| 30 | describe("pull requests route search", () => { | ||
| 31 | it("drops a q the URL parser turned into a number", () => { | ||
| 32 | expect(matchedSearch("/pull-requests?q=4089")?.q).toBeUndefined(); | ||
| 33 | expect(matchedSearch("/pull-requests?q=true")?.q).toBeUndefined(); | ||
| 34 | }); | ||
| 35 | |||
| 36 | it("keeps a q that is text, including quoted digits", () => { | ||
| 37 | expect(matchedSearch("/pull-requests?q=fix")?.q).toBe("fix"); | ||
| 38 | expect(matchedSearch("/pull-requests?q=%224089%22")?.q).toBe("4089"); | ||
| 39 | }); | ||
| 40 | }); | ||
apps/web/src/routes/_chat.pull-requests.tsx+3-1| ... | @@ -332,7 +332,9 @@ export const Route = createFileRoute("/_chat/pull-requests")({ | ... | @@ -332,7 +332,9 @@ export const Route = createFileRoute("/_chat/pull-requests")({ |
| 332 | ...(typeof raw.selectedEnvironmentId === "string" && raw.selectedEnvironmentId | 332 | ...(typeof raw.selectedEnvironmentId === "string" && raw.selectedEnvironmentId |
| 333 | ? { selectedEnvironmentId: raw.selectedEnvironmentId as EnvironmentId } | 333 | ? { selectedEnvironmentId: raw.selectedEnvironmentId as EnvironmentId } |
| 334 | : {}), | 334 | : {}), |
| 335 | ...(typeof raw.q === "string" && raw.q ? { q: raw.q.slice(0, 200) } : {}), | 335 | // Always an own key: the router lays this result over the parent route's unvalidated |
| 336 | // search, so leaving out a `q` the URL parser made a number would let the number through. | ||
| 337 | q: typeof raw.q === "string" && raw.q ? raw.q.slice(0, 200) : undefined, | ||
| 336 | ...(raw.draft === "only" || raw.draft === "hide" ? { draft: raw.draft } : {}), | 338 | ...(raw.draft === "only" || raw.draft === "hide" ? { draft: raw.draft } : {}), |
| 337 | ...(raw.review === "approved" || | 339 | ...(raw.review === "approved" || |
| 338 | raw.review === "changes-requested" || | 340 | raw.review === "changes-requested" || |