workspace upadate

This commit is contained in:
2026-08-17 19:52:44 +05:30
parent 7fa21a4513
commit aa2fb41871
3 changed files with 81 additions and 13 deletions

View File

@@ -259,7 +259,7 @@ export default function AdminLayout() {
<Shield className="mr-2 h-4 w-4" /> Security
</DropdownMenuItem>
<DropdownMenuItem onClick={() => navigate('/admin/workspace')} className="cursor-pointer">
<LayoutGrid className="mr-2 h-4 w-4" /> Workspace &amp; Skills
<LayoutGrid className="mr-2 h-4 w-4" /> Workspace
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem
@@ -308,7 +308,7 @@ export default function AdminLayout() {
{[
{ label: 'Settings', path: '/admin/settings' },
{ label: 'Security', path: '/admin/profile#security' },
{ label: 'Workspace & Skills', path: '/admin/workspace' },
{ label: 'Workspace', path: '/admin/workspace' },
].map((item) => (
<Link
key={item.label}

View File

@@ -55,7 +55,7 @@ export default function AdminWorkspace() {
return (
<AdminPage
title="Workspace & Skills"
title="Workspace"
subtitle="Govern the AI agent capabilities that extend Owliver and KROW pages."
>
<div className="space-y-6 w-full">

View File

@@ -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`}
>
<ul className="space-y-1">
{diagnostics.map((d, i) => (
<li key={`${d.kind}:${d.skillId ?? d.path}:${i}`} className="text-caption leading-relaxed">
<span className="font-mono text-[11px]">{d.skillId || d.path}</span>
{' — '}
{d.message}
</li>
))}
</ul>
<div className="flex flex-col gap-3">
<ul className="space-y-2">
{diagnostics.map((d, i) => (
<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>
<span className="font-mono text-[11px] font-semibold">{d.skillId || d.path}</span>
{' — '}
<span>{d.message}</span>
</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>
)}