()
| 35 | } |
| 36 | |
| 37 | export function SkillManager() { |
| 38 | const { t } = useTranslation(); |
| 39 | const [skills, setSkills] = useState<Skill[]>([]); |
| 40 | const [loading, setLoading] = useState(true); |
| 41 | |
| 42 | useEffect(() => { |
| 43 | loadSkills(); |
| 44 | }, []); |
| 45 | |
| 46 | async function loadSkills() { |
| 47 | try { |
| 48 | const dbSkills = await getSkills(); |
| 49 | |
| 50 | // Merge built-in skills with database skills |
| 51 | const mergedSkills = builtinSkills.map((builtin) => { |
| 52 | const dbSkill = dbSkills.find((s) => s.id === builtin.id); |
| 53 | return dbSkill |
| 54 | ? { |
| 55 | ...builtin, |
| 56 | description: dbSkill.description, |
| 57 | enabled: dbSkill.enabled, |
| 58 | prompt: dbSkill.prompt, |
| 59 | updatedAt: dbSkill.updatedAt, |
| 60 | } |
| 61 | : builtin; |
| 62 | }); |
| 63 | |
| 64 | // Add custom skills from database |
| 65 | const customSkills = dbSkills.filter((s) => !s.builtIn); |
| 66 | |
| 67 | setSkills([...mergedSkills, ...customSkills]); |
| 68 | } catch (error) { |
| 69 | console.error("Failed to load skills:", error); |
| 70 | // Fallback to built-in skills only |
| 71 | setSkills(builtinSkills); |
| 72 | } finally { |
| 73 | setLoading(false); |
| 74 | } |
| 75 | } |
| 76 | |
| 77 | async function toggleSkill(skillId: string, enabled: boolean) { |
| 78 | const skill = skills.find((s) => s.id === skillId); |
| 79 | if (!skill) return; |
| 80 | |
| 81 | const updatedSkill = { ...skill, enabled, updatedAt: Date.now() }; |
| 82 | try { |
| 83 | await upsertSkill(updatedSkill); |
| 84 | setSkills((prev) => prev.map((s) => (s.id === skillId ? updatedSkill : s))); |
| 85 | } catch (error) { |
| 86 | console.error("Failed to update skill:", error); |
| 87 | } |
| 88 | } |
| 89 | |
| 90 | const enabledCount = skills.filter((s) => s.enabled).length; |
| 91 | |
| 92 | return ( |
| 93 | <div className="space-y-6 p-4 pt-3"> |
| 94 | <section className="rounded-lg bg-muted/60 p-4"> |
nothing calls this directly
no test coverage detected