PAP-10257 Fix Team Catalog routes dropping /PAP/ company prefix on navigate

Add "teams" to BOARD_ROUTE_ROOTS so extractCompanyPrefixFromPath no longer
misreads the first segment of `/teams/<key>` as a company prefix ("TEAMS").
Without this, useNavigate skipped the re-prefix rewrite and auto-select /
row clicks / file-tree clicks landed on `/teams/<key>` → "Company not found".
Mirrors the sibling `skills` route precedent.

Bonus: rename the search filter URL param from `q` to `search` so it matches
the sibling full-word params (kind/category/risk). `?search=` now both filters
the list and populates the search input, fixing the empty-textbox finding.

Adds a regression unit test covering prefix-preserving navigation for team
routes (auto-select, nested /files paths, idempotency, round-trip).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
DottaandClaude Opus 4.8 committed 2026-06-05 03:20:50 +00:00
1 parent 85e5b161b2
commit 04fd454af6
3 files changed
+25 -2

No files matched your search

+22
View File
@@ -35,4 +35,26 @@ describe("company routes", () => {
expect(applyCompanyPrefix("/search?q=hello%20world", "PAP")).toBe("/PAP/search?q=hello%20world");
expect(toCompanyRelativePath("/PAP/search?q=foo")).toBe("/search?q=foo");
});
// Regression for PAP-10257: Team Catalog navigation (auto-select + row/file
// clicks) produces company-relative `/teams/<key>` paths. Without `teams` in
// the board-route allowlist, `extractCompanyPrefixFromPath` misread the first
// segment as a company prefix ("TEAMS") and `useNavigate` skipped the rewrite,
// dropping the `/PAP/` prefix and crashing into "Company not found".
it("re-prefixes team catalog routes so navigate preserves the company prefix", () => {
expect(isBoardPathWithoutPrefix("/teams")).toBe(true);
expect(isBoardPathWithoutPrefix("/teams/core-exec-team")).toBe(true);
expect(extractCompanyPrefixFromPath("/teams/core-exec-team")).toBeNull();
// Auto-select effect: `/teams/<first-key>` must gain the `/PAP/` prefix.
expect(applyCompanyPrefix("/teams/core-exec-team", "PAP")).toBe("/PAP/teams/core-exec-team");
// File-tree click: nested `/files/<encoded>` path is preserved under the prefix.
expect(applyCompanyPrefix("/teams/core-exec-team/files/TEAM.md", "PAP")).toBe(
"/PAP/teams/core-exec-team/files/TEAM.md",
);
// Already-prefixed paths are left untouched (idempotent — no double prefix).
expect(applyCompanyPrefix("/PAP/teams/core-exec-team", "PAP")).toBe("/PAP/teams/core-exec-team");
// Round-trips back to a company-relative path.
expect(toCompanyRelativePath("/PAP/teams/core-exec-team")).toBe("/teams/core-exec-team");
});
});
+1
View File
@@ -3,6 +3,7 @@ const BOARD_ROUTE_ROOTS = new Set([
"companies",
"company",
"skills",
"teams",
"org",
"agents",
"projects",
+2 -2
View File
@@ -2129,7 +2129,7 @@ export function TeamCatalog() {
const selectedRef = parsedRoute.catalogRef;
const selectedFilePath = parsedRoute.filePath;
const q = searchParams.get("q") ?? "";
const q = searchParams.get("search") ?? "";
const kindFilter = (searchParams.get("kind") as KindFilter) ?? "all";
const categoryFilter = searchParams.get("category") ?? "";
const riskFilter = (searchParams.get("risk") as RiskFilter) ?? "any";
@@ -2229,7 +2229,7 @@ export function TeamCatalog() {
<Search className="absolute left-2.5 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground" />
<Input
value={q}
onChange={(e) => setFilterParam("q", e.target.value)}
onChange={(e) => setFilterParam("search", e.target.value)}
placeholder="Search teams"
className="h-8 w-56 pl-8"
/>