From d098ecad649de09794f4604fd3791af0f121e0bf Mon Sep 17 00:00:00 2001 From: stmoonar Date: Mon, 2 Feb 2026 09:05:05 +0800 Subject: [PATCH] fix(skills): handle Windows path separator in installed status matching (#868) * fix(skills): handle Windows path separator in installed status matching Use regex to split directory path by both / and \ to correctly extract the install name on Windows, fixing the issue where installed skills were not showing as installed in the discovery page filter. Co-Authored-By: Claude Opus 4.5 * feat(skills): add repository filter to skills discovery page - Add dropdown to filter skills by repository (owner/name) - Extract unique repos from discoverable skills list - Add truncate style for long repo names with hover title - Add i18n translations for zh/en/ja Co-Authored-By: Claude Opus 4.5 --------- Co-authored-by: Claude Opus 4.5 --- src/components/skills/SkillsPage.tsx | 65 +++++++++++++++++++++++++--- src/i18n/locales/en.json | 4 +- src/i18n/locales/ja.json | 4 +- src/i18n/locales/zh.json | 4 +- 4 files changed, 69 insertions(+), 8 deletions(-) diff --git a/src/components/skills/SkillsPage.tsx b/src/components/skills/SkillsPage.tsx index 73865513..adb100e4 100644 --- a/src/components/skills/SkillsPage.tsx +++ b/src/components/skills/SkillsPage.tsx @@ -43,6 +43,7 @@ export const SkillsPage = forwardRef( const { t } = useTranslation(); const [repoManagerOpen, setRepoManagerOpen] = useState(false); const [searchQuery, setSearchQuery] = useState(""); + const [filterRepo, setFilterRepo] = useState("all"); const [filterStatus, setFilterStatus] = useState< "all" | "installed" | "uninstalled" >("all"); @@ -80,12 +81,25 @@ export const SkillsPage = forwardRef( type DiscoverableSkillItem = DiscoverableSkill & { installed: boolean }; + // 从可发现技能中提取所有仓库选项 + const repoOptions = useMemo(() => { + if (!discoverableSkills) return []; + const repoSet = new Set(); + discoverableSkills.forEach((s) => { + if (s.repoOwner && s.repoName) { + repoSet.add(`${s.repoOwner}/${s.repoName}`); + } + }); + return Array.from(repoSet).sort(); + }, [discoverableSkills]); + // 为发现列表补齐 installed 状态,供 SkillCard 使用 const skills: DiscoverableSkillItem[] = useMemo(() => { if (!discoverableSkills) return []; return discoverableSkills.map((d) => { + // 同时处理 / 和 \ 路径分隔符(兼容 Windows 和 Unix) const installName = - d.directory.split("/").pop()?.toLowerCase() || + d.directory.split(/[/\\]/).pop()?.toLowerCase() || d.directory.toLowerCase(); // 使用 directory + repoOwner + repoName 组合判断是否已安装 const key = `${installName}:${d.repoOwner.toLowerCase()}:${d.repoName.toLowerCase()}`; @@ -179,12 +193,21 @@ export const SkillsPage = forwardRef( // 过滤技能列表 const filteredSkills = useMemo(() => { - const byStatus = skills.filter((skill) => { + // 按仓库筛选 + const byRepo = skills.filter((skill) => { + if (filterRepo === "all") return true; + const skillRepo = `${skill.repoOwner}/${skill.repoName}`; + return skillRepo === filterRepo; + }); + + // 按安装状态筛选 + const byStatus = byRepo.filter((skill) => { if (filterStatus === "installed") return skill.installed; if (filterStatus === "uninstalled") return !skill.installed; return true; }); + // 按搜索关键词筛选 if (!searchQuery.trim()) return byStatus; const query = searchQuery.toLowerCase(); @@ -199,7 +222,7 @@ export const SkillsPage = forwardRef( directory.includes(query) ); }); - }, [skills, searchQuery, filterStatus]); + }, [skills, searchQuery, filterRepo, filterStatus]); return (
@@ -228,7 +251,7 @@ export const SkillsPage = forwardRef(
) : ( <> - {/* 搜索框 */} + {/* 搜索框和筛选器 */}
@@ -240,7 +263,39 @@ export const SkillsPage = forwardRef( className="pl-9 pr-3" />
-
+ {/* 仓库筛选 */} +
+ +
+ {/* 安装状态筛选 */} +