diff --git a/src/layouts/AdminLayout.jsx b/src/layouts/AdminLayout.jsx index 5dd8839..8784e30 100644 --- a/src/layouts/AdminLayout.jsx +++ b/src/layouts/AdminLayout.jsx @@ -259,7 +259,7 @@ export default function AdminLayout() { Security navigate('/admin/workspace')} className="cursor-pointer"> - Workspace & Skills + Workspace (
diff --git a/src/pages/admin/WorkspaceSkills.jsx b/src/pages/admin/WorkspaceSkills.jsx index 0602c07..b7233df 100644 --- a/src/pages/admin/WorkspaceSkills.jsx +++ b/src/pages/admin/WorkspaceSkills.jsx @@ -10,7 +10,7 @@ import { } from '@/components/ds'; import { cn } from '@/lib/utils'; import { usePreferences, useUpdatePreferences } from '@/lib/krowHooks'; -import { PAGE_KEYS, readSkillRegistry, skillsWithFacet } from '@/lib/skills/registry'; +import { PAGE_KEYS, parseSkill, readSkillRegistry, skillsWithFacet } from '@/lib/skills/registry'; import { removeCustomSkill, upsertCustomSkill } from '@/lib/skills/customSkills'; import { countSections } from '@/lib/skills/uiConfig'; import { @@ -343,6 +343,51 @@ export default function WorkspaceSkills() { toast.success(`${skill.name} restored — switched off`); }; + const handleFixDiagnostic = (d) => { + if (!d.skillId) return; + const isCustom = customSkills.some((cs) => { + try { + const parsed = parseSkill(typeof cs === 'string' ? cs : cs?.raw ?? '', { custom: true }); + return parsed?.id === d.skillId; + } catch { + return false; + } + }); + + if (isCustom) { + const nextCustom = removeCustomSkill(customSkills, d.skillId); + updatePreferences.mutate({ customSkills: nextCustom }); + toast.success(`Removed custom skill "${d.skillId}"`); + } else { + const patch = { + removedSkills: [...new Set([...removedSkills, d.skillId])], + disabledSkills: [...new Set([...disabledSkills, d.skillId])], + }; + updatePreferences.mutate(patch); + toast.success(`Removed "${d.skillId}" from workspace`); + } + }; + + const handleFixAllDiagnostics = () => { + let nextCustom = [...customSkills]; + let nextRemoved = [...removedSkills]; + let nextDisabled = [...disabledSkills]; + + diagnostics.forEach((d) => { + if (!d.skillId) return; + nextCustom = removeCustomSkill(nextCustom, d.skillId); + nextRemoved = [...new Set([...nextRemoved, d.skillId])]; + nextDisabled = [...new Set([...nextDisabled, d.skillId])]; + }); + + updatePreferences.mutate({ + customSkills: nextCustom, + removedSkills: nextRemoved, + disabledSkills: nextDisabled, + }); + toast.success('Resolved all skill problems'); + }; + /** A row opens the editor its own kind is authored in. */ const editRoute = (skill) => (facet === 'owliver' ? `/admin/workspace/skills/owliver/${skill.id}` @@ -403,15 +448,38 @@ export default function WorkspaceSkills() { tone={diagnostics.some((d) => d.level === 'error') ? 'destructive' : 'warning'} title={`${diagnostics.length} skill ${diagnostics.length === 1 ? 'problem' : 'problems'} in this workspace`} > -
    - {diagnostics.map((d, i) => ( -
  • - {d.skillId || d.path} - {' — '} - {d.message} -
  • - ))} -
+
+
    + {diagnostics.map((d, i) => ( +
  • +
    + {d.skillId || d.path} + {' — '} + {d.message} +
    + {d.skillId && ( + + )} +
  • + ))} +
+
+ +
+
)}