From be8bbf40b9e763d442e83fcd0049d574b31edb2d Mon Sep 17 00:00:00 2001 From: Dotta Date: Sun, 5 Jul 2026 12:35:07 +0000 Subject: [PATCH] Fix rules-of-hooks crash on CompanySkills when company context resolves The folder-rail scoped-counts useMemo (railSkillFolderResult) sat below the "if (!selectedCompanyId)" early return, so the page threw "Rendered more hooks than during the previous render" the moment the companies query resolved after a fresh load. Hoist it (with its input consts) above the early return. Co-Authored-By: Paperclip --- ui/src/pages/CompanySkills.tsx | 54 +++++++++++++++++----------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/ui/src/pages/CompanySkills.tsx b/ui/src/pages/CompanySkills.tsx index e80554703d4..f5cc2a19238 100644 --- a/ui/src/pages/CompanySkills.tsx +++ b/ui/src/pages/CompanySkills.tsx @@ -4538,6 +4538,33 @@ export function CompanySkills() { }, }); + const skillFolderResult = skillFoldersQuery.data ?? null; + const showInstalledFolders = isDiscovery && discoveryTab === "installed"; + // Rail counts reflect the current category/search scope, never the folder + // filter itself (ux-spec §5.3). + const railSkillFolderResult = useMemo(() => { + if (!skillFolderResult || discoveryTab !== "installed") return skillFolderResult; + const scoped = discoveryTabCards.filter((card) => { + if (discoveryCategory && !card.categories.includes(discoveryCategory)) return false; + return discoveryMatchesSearch(card, discoverySearch.trim()); + }); + const counts = new Map(); + let unfiled = 0; + for (const card of scoped) { + if (card.folderId) counts.set(card.folderId, (counts.get(card.folderId) ?? 0) + 1); + else unfiled += 1; + } + return { + ...skillFolderResult, + allCount: scoped.length, + unfiledCount: unfiled, + folders: skillFolderResult.folders.map((folder) => ({ + ...folder, + itemCount: counts.get(folder.id) ?? 0, + })), + }; + }, [skillFolderResult, discoveryTab, discoveryTabCards, discoveryCategory, discoverySearch]); + if (!selectedCompanyId) { return ; } @@ -4581,33 +4608,6 @@ export function CompanySkills() { const studioDescription = studioForkFromId ? "Review the fork metadata and create an editable company copy." : "Create an editable company skill in the Paperclip workspace."; - const skillFolderResult = skillFoldersQuery.data ?? null; - const showInstalledFolders = isDiscovery && discoveryTab === "installed"; - // Rail counts reflect the current category/search scope, never the folder - // filter itself (ux-spec §5.3). - const railSkillFolderResult = useMemo(() => { - if (!skillFolderResult || discoveryTab !== "installed") return skillFolderResult; - const scoped = discoveryTabCards.filter((card) => { - if (discoveryCategory && !card.categories.includes(discoveryCategory)) return false; - return discoveryMatchesSearch(card, discoverySearch.trim()); - }); - const counts = new Map(); - let unfiled = 0; - for (const card of scoped) { - if (card.folderId) counts.set(card.folderId, (counts.get(card.folderId) ?? 0) + 1); - else unfiled += 1; - } - return { - ...skillFolderResult, - allCount: scoped.length, - unfiledCount: unfiled, - folders: skillFolderResult.folders.map((folder) => ({ - ...folder, - itemCount: counts.get(folder.id) ?? 0, - })), - }; - }, [skillFolderResult, discoveryTab, discoveryTabCards, discoveryCategory, discoverySearch]); - return ( <> {policyDenial.denial ? (