workspace upadate
This commit is contained in:
@@ -259,7 +259,7 @@ export default function AdminLayout() {
|
|||||||
<Shield className="mr-2 h-4 w-4" /> Security
|
<Shield className="mr-2 h-4 w-4" /> Security
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuItem onClick={() => navigate('/admin/workspace')} className="cursor-pointer">
|
<DropdownMenuItem onClick={() => navigate('/admin/workspace')} className="cursor-pointer">
|
||||||
<LayoutGrid className="mr-2 h-4 w-4" /> Workspace & Skills
|
<LayoutGrid className="mr-2 h-4 w-4" /> Workspace
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
@@ -308,7 +308,7 @@ export default function AdminLayout() {
|
|||||||
{[
|
{[
|
||||||
{ label: 'Settings', path: '/admin/settings' },
|
{ label: 'Settings', path: '/admin/settings' },
|
||||||
{ label: 'Security', path: '/admin/profile#security' },
|
{ label: 'Security', path: '/admin/profile#security' },
|
||||||
{ label: 'Workspace & Skills', path: '/admin/workspace' },
|
{ label: 'Workspace', path: '/admin/workspace' },
|
||||||
].map((item) => (
|
].map((item) => (
|
||||||
<Link
|
<Link
|
||||||
key={item.label}
|
key={item.label}
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ export default function AdminWorkspace() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<AdminPage
|
<AdminPage
|
||||||
title="Workspace & Skills"
|
title="Workspace"
|
||||||
subtitle="Govern the AI agent capabilities that extend Owliver and KROW pages."
|
subtitle="Govern the AI agent capabilities that extend Owliver and KROW pages."
|
||||||
>
|
>
|
||||||
<div className="space-y-6 w-full">
|
<div className="space-y-6 w-full">
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
} from '@/components/ds';
|
} from '@/components/ds';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { usePreferences, useUpdatePreferences } from '@/lib/krowHooks';
|
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 { removeCustomSkill, upsertCustomSkill } from '@/lib/skills/customSkills';
|
||||||
import { countSections } from '@/lib/skills/uiConfig';
|
import { countSections } from '@/lib/skills/uiConfig';
|
||||||
import {
|
import {
|
||||||
@@ -343,6 +343,51 @@ export default function WorkspaceSkills() {
|
|||||||
toast.success(`${skill.name} restored — switched off`);
|
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. */
|
/** A row opens the editor its own kind is authored in. */
|
||||||
const editRoute = (skill) => (facet === 'owliver'
|
const editRoute = (skill) => (facet === 'owliver'
|
||||||
? `/admin/workspace/skills/owliver/${skill.id}`
|
? `/admin/workspace/skills/owliver/${skill.id}`
|
||||||
@@ -403,15 +448,38 @@ export default function WorkspaceSkills() {
|
|||||||
tone={diagnostics.some((d) => d.level === 'error') ? 'destructive' : 'warning'}
|
tone={diagnostics.some((d) => d.level === 'error') ? 'destructive' : 'warning'}
|
||||||
title={`${diagnostics.length} skill ${diagnostics.length === 1 ? 'problem' : 'problems'} in this workspace`}
|
title={`${diagnostics.length} skill ${diagnostics.length === 1 ? 'problem' : 'problems'} in this workspace`}
|
||||||
>
|
>
|
||||||
<ul className="space-y-1">
|
<div className="flex flex-col gap-3">
|
||||||
{diagnostics.map((d, i) => (
|
<ul className="space-y-2">
|
||||||
<li key={`${d.kind}:${d.skillId ?? d.path}:${i}`} className="text-caption leading-relaxed">
|
{diagnostics.map((d, i) => (
|
||||||
<span className="font-mono text-[11px]">{d.skillId || d.path}</span>
|
<li key={`${d.kind}:${d.skillId ?? d.path}:${i}`} className="text-caption leading-relaxed flex flex-col sm:flex-row sm:items-center justify-between gap-2">
|
||||||
{' — '}
|
<div>
|
||||||
{d.message}
|
<span className="font-mono text-[11px] font-semibold">{d.skillId || d.path}</span>
|
||||||
</li>
|
{' — '}
|
||||||
))}
|
<span>{d.message}</span>
|
||||||
</ul>
|
</div>
|
||||||
|
{d.skillId && (
|
||||||
|
<Button
|
||||||
|
size="xs"
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => handleFixDiagnostic(d)}
|
||||||
|
className="shrink-0 self-start sm:self-auto"
|
||||||
|
>
|
||||||
|
Remove
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
<div className="pt-2 border-t border-amber-200/50 flex justify-end">
|
||||||
|
<Button
|
||||||
|
size="xs"
|
||||||
|
variant="outline"
|
||||||
|
onClick={handleFixAllDiagnostics}
|
||||||
|
>
|
||||||
|
Resolve all problems
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</Alert>
|
</Alert>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user