mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-07 16:35:48 +01:00
Hide teams catalog UI
This commit is contained in:
1 parent
f7b55ebfd3
commit
7b9b79860e
6 files changed
+28
-23
No files matched your search
@@ -37,7 +37,6 @@ import { CompanySettingsPluginPage } from "./pages/CompanySettingsPluginPage";
|
||||
import { CompanyAccess, CompanyAccessLegacyRoute } from "./pages/CompanyAccess";
|
||||
import { CompanyInvites } from "./pages/CompanyInvites";
|
||||
import { CompanySkills } from "./pages/CompanySkills";
|
||||
import { TeamCatalog } from "./pages/TeamCatalog";
|
||||
import { Secrets } from "./pages/Secrets";
|
||||
import { CompanyExport } from "./pages/CompanyExport";
|
||||
import { CompanyImport } from "./pages/CompanyImport";
|
||||
@@ -84,7 +83,6 @@ function boardRoutes() {
|
||||
<Route path="company/settings/secrets" element={<Secrets />} />
|
||||
<Route path="company/settings/:settingsRoutePath/*" element={<CompanySettingsPluginPage />} />
|
||||
<Route path="skills/*" element={<CompanySkills />} />
|
||||
<Route path="teams/*" element={<TeamCatalog />} />
|
||||
<Route path="settings" element={<LegacySettingsRedirect />} />
|
||||
<Route path="settings/*" element={<LegacySettingsRedirect />} />
|
||||
<Route path="plugins/:pluginId" element={<PluginPage />} />
|
||||
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
SquarePen,
|
||||
Network,
|
||||
Boxes,
|
||||
Users2,
|
||||
Repeat,
|
||||
GitBranch,
|
||||
Settings,
|
||||
@@ -122,7 +121,6 @@ export function Sidebar() {
|
||||
|
||||
<SidebarSection label="Company">
|
||||
<SidebarNavItem to="/org" label="Org" icon={Network} />
|
||||
<SidebarNavItem to="/teams" label="Teams" icon={Users2} />
|
||||
<SidebarNavItem to="/skills" label="Skills" icon={Boxes} />
|
||||
<SidebarNavItem to="/costs" label="Costs" icon={DollarSign} />
|
||||
<SidebarNavItem to="/activity" label="Activity" icon={History} />
|
||||
|
||||
@@ -37,24 +37,31 @@ describe("company routes", () => {
|
||||
});
|
||||
|
||||
// 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".
|
||||
// clicks) produces company-relative `/teams-catalog/<key>` paths. Without
|
||||
// `teams-catalog` in the board-route allowlist, `extractCompanyPrefixFromPath`
|
||||
// misread the first segment as a company prefix 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();
|
||||
expect(isBoardPathWithoutPrefix("/teams")).toBe(false);
|
||||
expect(isBoardPathWithoutPrefix("/teams-catalog")).toBe(true);
|
||||
expect(isBoardPathWithoutPrefix("/teams-catalog/core-exec-team")).toBe(true);
|
||||
expect(extractCompanyPrefixFromPath("/teams-catalog/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");
|
||||
// Auto-select effect: `/teams-catalog/<first-key>` must gain the `/PAP/` prefix.
|
||||
expect(applyCompanyPrefix("/teams-catalog/core-exec-team", "PAP")).toBe(
|
||||
"/PAP/teams-catalog/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",
|
||||
expect(applyCompanyPrefix("/teams-catalog/core-exec-team/files/TEAM.md", "PAP")).toBe(
|
||||
"/PAP/teams-catalog/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");
|
||||
expect(applyCompanyPrefix("/PAP/teams-catalog/core-exec-team", "PAP")).toBe(
|
||||
"/PAP/teams-catalog/core-exec-team",
|
||||
);
|
||||
// Round-trips back to a company-relative path.
|
||||
expect(toCompanyRelativePath("/PAP/teams/core-exec-team")).toBe("/teams/core-exec-team");
|
||||
expect(toCompanyRelativePath("/PAP/teams-catalog/core-exec-team")).toBe(
|
||||
"/teams-catalog/core-exec-team",
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -3,7 +3,7 @@ const BOARD_ROUTE_ROOTS = new Set([
|
||||
"companies",
|
||||
"company",
|
||||
"skills",
|
||||
"teams",
|
||||
"teams-catalog",
|
||||
"org",
|
||||
"agents",
|
||||
"projects",
|
||||
|
||||
@@ -1462,7 +1462,7 @@ export function DesignGuide() {
|
||||
{/* ============================================================ */}
|
||||
<Section title="Team Catalog">
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Components from the Team Catalog browse/install surface (<code className="font-mono text-xs">/teams</code>).
|
||||
Components from the Team Catalog browse/install surface (<code className="font-mono text-xs">/teams-catalog</code>).
|
||||
Fixtures are shared with the Storybook stories.
|
||||
</p>
|
||||
|
||||
|
||||
@@ -184,6 +184,8 @@ function decodeTeamFilePath(encoded: string | undefined): string | null {
|
||||
|
||||
type ParsedRoute = { catalogRef: string | null; filePath: string | null };
|
||||
|
||||
const TEAM_CATALOG_ROUTE_ROOT = "/teams-catalog";
|
||||
|
||||
function parseTeamRoute(routePath: string | undefined): ParsedRoute {
|
||||
if (!routePath) return { catalogRef: null, filePath: null };
|
||||
const segments = routePath.split("/").filter(Boolean);
|
||||
@@ -196,7 +198,7 @@ function parseTeamRoute(routePath: string | undefined): ParsedRoute {
|
||||
}
|
||||
|
||||
function teamRoute(catalogRef: string, filePath?: string | null): string {
|
||||
const base = `/teams/${encodeURIComponent(catalogRef)}`;
|
||||
const base = `${TEAM_CATALOG_ROUTE_ROOT}/${encodeURIComponent(catalogRef)}`;
|
||||
if (filePath) return `${base}/files/${encodeTeamFilePath(filePath)}`;
|
||||
return base;
|
||||
}
|
||||
@@ -2184,7 +2186,7 @@ export function TeamCatalog() {
|
||||
|
||||
// Preserve the active filter query (search/kind/category/risk) across in-page
|
||||
// navigation. Without this, auto-select and team-row / file-tree clicks rebuild
|
||||
// a fresh `/teams/<key>` path from `teamRoute()` and drop the query string, so a
|
||||
// a fresh `/teams-catalog/<key>` path from `teamRoute()` and drop the query string, so a
|
||||
// landing `?search=…` unfiltered the list and emptied the search box (PAP-10257
|
||||
// follow-up). `applyCompanyPrefix` already preserves query strings.
|
||||
const filterQuery = searchParams.toString();
|
||||
@@ -2199,7 +2201,7 @@ export function TeamCatalog() {
|
||||
useEffect(() => {
|
||||
setBreadcrumbs([
|
||||
{ label: "Org Chart", href: "/org" },
|
||||
{ label: "Teams", href: "/teams" },
|
||||
{ label: "Teams", href: TEAM_CATALOG_ROUTE_ROOT },
|
||||
]);
|
||||
}, [setBreadcrumbs]);
|
||||
|
||||
@@ -2485,7 +2487,7 @@ export function TeamCatalog() {
|
||||
{!isDesktop && selectedTeam && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => navigate(withFilters("/teams"))}
|
||||
onClick={() => navigate(withFilters(TEAM_CATALOG_ROUTE_ROOT))}
|
||||
className="flex items-center gap-1.5 border-b border-border px-4 py-2 text-sm text-muted-foreground hover:text-foreground"
|
||||
>
|
||||
<ChevronLeft className="h-4 w-4" /> Back to catalog
|
||||
|
||||
Reference in new issue
Block a user