fix error line

This commit is contained in:
2026-08-17 17:33:56 +05:30
parent 69b38abced
commit 7fa21a4513
105 changed files with 1296 additions and 323 deletions

View File

@@ -1,38 +1,62 @@
import React, { useMemo } from 'react';
import { Link, useNavigate } from 'react-router-dom';
import { Link } from 'react-router-dom';
import {
GraduationCap, Sparkles, TrendingUp,
LayoutTemplate, Sparkles,
BookOpen, ArrowRight
} from 'lucide-react';
import { usePreferences } from '@/lib/krowHooks';
import { allSkills } from '@/lib/skills/registry';
import { useWorkforcePaths } from '@/lib/skills/usePageSkills';
import { aiAgentSkills, allSkills, skillsWithFacet } from '@/lib/skills/registry';
import { AdminPage } from '@/pages/admin/_shell';
import { cn } from '@/lib/utils';
/**
* Workspace & Skills — Full-width workforce capabilities & AI governance hub.
* Workspace & Skills — AI agent capability governance.
*
* This page governs what *Owliver* can do. It used to govern workforce training
* as well — Training Paths and Skill Progression sat in the right-hand column —
* and that conflated two unrelated things under one word. A "skill" here is a
* capability the assistant gains; a "skill" in KROW Forge is something a person
* learns, proves and is verified in. They have different owners, different
* lifecycles and different audiences, and putting them side by side made the page
* read as though enabling a Bartending path taught Owliver to tend bar.
*
* Workforce training was not removed, only returned to where it belongs: the
* definitions, the routes and the pages are untouched, and KROW Forge
* (`/admin/university`) and Skill Development still read them. See
* `workforceTrainingSkills` in the registry for the other half of the split.
*/
export default function AdminWorkspace() {
const navigate = useNavigate();
const preferences = usePreferences();
/* Owliver's skills from Markdown registry */
/**
* AI agent skills only.
*
* Deliberately `aiAgentSkills(...)` rather than `allSkills(...)`. The registry
* holds both kinds, so the unfiltered read counted five workforce training
* paths among Owliver's capabilities — the hero said ten registered skills when
* the assistant had five. Naming the kind is also what stops a training path
* added later from reappearing here on its own.
*/
const skills = useMemo(
() => allSkills(preferences.customSkills || []),
() => aiAgentSkills(allSkills(preferences.customSkills || [])),
[preferences.customSkills]
);
const disabledSkills = preferences.disabledSkills || [];
const activeSkills = skills.filter((s) => !disabledSkills.includes(s.id)).length;
/* Workforce training paths from registry */
const { paths } = useWorkforcePaths();
/* The two kinds of agent skill — the same two lists the management page is
split into, read here from the same filtered registry so the landing page and
the manager can never disagree about what is registered. */
const owliverSkills = useMemo(() => skillsWithFacet(skills, 'owliver'), [skills]);
const boardSkills = useMemo(() => skillsWithFacet(skills, 'ui'), [skills]);
const owliverCount = owliverSkills.length;
const boardCount = boardSkills.length;
return (
<AdminPage
title="Workspace & Skills"
subtitle="Manage workforce capabilities, Owliver skills and training."
subtitle="Govern the AI agent capabilities that extend Owliver and KROW pages."
>
<div className="space-y-6 w-full">
{/* ── 1. Hero Banner (Full Width) ───────────────────────────────── */}
@@ -42,11 +66,12 @@ export default function AdminWorkspace() {
<div className="space-y-2">
<div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-white/20 backdrop-blur-md text-white text-[12px] font-semibold border border-white/30">
<Sparkles className="w-3.5 h-3.5 text-sky-300" />
Workforce Intelligence Hub
AI Capability Governance
</div>
<h1 className="text-2xl sm:text-3xl font-bold tracking-tight text-white">Capabilities & Skill Governance</h1>
<h1 className="text-2xl sm:text-3xl font-bold tracking-tight text-white">AI Agent Capabilities</h1>
<p className="text-[14px] text-blue-100 font-normal max-w-2xl">
Govern Owliver AI agent capabilities, configure workforce training paths, and track talent progression across your organization.
Govern what Owliver can understand, analyze and execute. Workforce training
paths and talent progression are managed in KROW Forge.
</p>
</div>
@@ -56,10 +81,13 @@ export default function AdminWorkspace() {
<p className="text-2xl font-bold text-white mt-0.5">{skills.length}</p>
<span className="text-[10px] text-emerald-300 font-medium">{activeSkills} Active</span>
</div>
{/* Was "Training Paths". Replaced rather than dropped: the slot is
useful, and the split of agent skills across the two lists is
what this page actually governs. */}
<div className="bg-white/10 backdrop-blur-md rounded-2xl p-4 border border-white/15 min-w-[130px] text-center">
<p className="text-[11px] uppercase tracking-wider text-blue-200 font-semibold">Training Paths</p>
<p className="text-2xl font-bold text-sky-300 mt-0.5">{paths.length}</p>
<span className="text-[10px] text-blue-200">Verified Ladders</span>
<p className="text-[11px] uppercase tracking-wider text-blue-200 font-semibold">Skill Kinds</p>
<p className="text-2xl font-bold text-sky-300 mt-0.5">{owliverCount + boardCount}</p>
<span className="text-[10px] text-blue-200">{owliverCount} Owliver · {boardCount} Board</span>
</div>
</div>
</div>
@@ -73,20 +101,22 @@ export default function AdminWorkspace() {
<div className="flex items-center justify-between border-b border-[#E0E4EA] pb-3">
<div className="flex items-center gap-2">
<Sparkles className="w-5 h-5 text-[#0838E0]" />
<h2 className="text-[16px] font-bold text-[#101820]">Owliver AI Capabilities</h2>
<h2 className="text-[16px] font-bold text-[#101820]">Owliver Skills</h2>
</div>
<span className="text-[12px] font-semibold text-[#0838E0] bg-blue-50 px-3 py-1 rounded-full border border-blue-200/60">
{skills.length} Registered · {activeSkills} Active
{owliverCount} Registered
</span>
</div>
<p className="text-[13px] text-[#687386]">
Owliver capabilities define what the AI assistant can execute autonomously during candidate screening, background matching, and contextual analysis.
Owliver skills teach the assistant what it can be asked on a page and how to answer —
screening, matching and contextual analysis. They define what the AI understands, not
what a candidate learns.
</p>
{/* Skills Sample List */}
<div className="space-y-3">
{skills.slice(0, 4).map((s) => {
{owliverSkills.slice(0, 4).map((s) => {
const isActive = !disabledSkills.includes(s.id);
return (
<div key={s.id} className="p-3.5 rounded-xl border border-[#E0E4EA] bg-[#F8F8F8]/50 flex items-center justify-between gap-3">
@@ -108,86 +138,78 @@ export default function AdminWorkspace() {
{/* CTA Button */}
<div className="pt-2">
<Link
to="/admin/workspace/skills"
to="/admin/workspace/skills?tab=owliver"
className="w-full inline-flex items-center justify-center gap-2 px-5 py-3 rounded-xl bg-[#0838E0] hover:bg-[#062BAF] text-white text-[13px] font-semibold transition-all shadow-md shadow-blue-500/20 hover:scale-[1.01]"
>
<Sparkles className="w-4 h-4" />
Manage Owliver Skills & Agent Capabilities
Manage Owliver Skills
<ArrowRight className="w-4 h-4" />
</Link>
</div>
</div>
</div>
{/* ── Right Column: Workforce Training & Skill Development ──────── */}
{/* ── Right Column: Board Skills ─────────────────────────────────
The other kind of AI agent skill. This column previously held
Workforce Training Paths and Skill Progression Tracking, both of
which are KROW Forge concerns — see the note at the top of the file.
Board skills belong here because, like Owliver skills, they are
capabilities the product gains rather than something a person
learns. */}
<div className="space-y-6">
{/* Workforce Training */}
<div className="bg-white rounded-2xl border border-[#E0E4EA] p-6 shadow-xs space-y-5">
<div className="flex items-center justify-between border-b border-[#E0E4EA] pb-3">
<div className="flex items-center gap-2">
<GraduationCap className="w-5 h-5 text-indigo-600" />
<h2 className="text-[16px] font-bold text-[#101820]">Workforce Training Paths</h2>
<LayoutTemplate className="w-5 h-5 text-[#0838E0]" />
<h2 className="text-[16px] font-bold text-[#101820]">Board Skills</h2>
</div>
<span className="text-[12px] font-semibold text-indigo-600 bg-indigo-50 px-3 py-1 rounded-full border border-indigo-200/60">
{paths.length} Active Paths
<span className="text-[12px] font-semibold text-[#0838E0] bg-blue-50 px-3 py-1 rounded-full border border-blue-200/60">
{boardCount} Registered
</span>
</div>
<p className="text-[13px] text-[#687386]">
Structured learning challenges and skill verification ladders where workforce candidates prove their real-world capabilities.
Board skills add dynamic sections to KROW pages, read from real page data. They
extend what a page shows, not what a candidate learns.
</p>
{/* Paths Sample List */}
{/* Sample list, from the same filtered registry read as the left
column — so the two columns can never disagree about what is
registered. */}
<div className="space-y-3">
{paths.slice(0, 3).map((p) => (
<div key={p.id} className="p-3.5 rounded-xl border border-[#E0E4EA] bg-[#F8F8F8]/50 flex items-center justify-between gap-3">
<div className="min-w-0 flex-1">
<p className="text-[13px] font-bold text-[#101820]">{p.name || p.id}</p>
{p.category && <p className="text-[12px] text-[#687386] capitalize mt-0.5">{p.category} Path</p>}
{boardSkills.slice(0, 4).map((s) => {
const isActive = !disabledSkills.includes(s.id);
return (
<div key={s.id} className="p-3.5 rounded-xl border border-[#E0E4EA] bg-[#F8F8F8]/50 flex items-center justify-between gap-3">
<div className="min-w-0 flex-1">
<p className="text-[13px] font-bold text-[#101820]">{s.name || s.id}</p>
{s.description && <p className="text-[12px] text-[#687386] truncate mt-0.5">{s.description}</p>}
</div>
<span className={cn(
'px-2.5 py-0.5 rounded-full text-[11px] font-semibold shrink-0',
isActive ? 'bg-emerald-50 text-[#16A765] border border-emerald-200' : 'bg-gray-100 text-gray-500'
)}>
{isActive ? 'Active' : 'Disabled'}
</span>
</div>
<span className="px-2.5 py-0.5 rounded-full bg-indigo-50 text-indigo-700 text-[11px] font-semibold border border-indigo-200">
Verified Path
</span>
</div>
))}
</div>
);
})}
{/* CTA Button */}
<div className="pt-2">
<Link
to="/admin/university"
className="w-full inline-flex items-center justify-center gap-2 px-5 py-3 rounded-xl border border-[#E0E4EA] bg-white hover:bg-[#F8F8F8] text-[#101820] text-[13px] font-semibold transition-all shadow-xs"
>
<GraduationCap className="w-4 h-4 text-indigo-600" />
Manage Training Paths & Proving Challenges
<ArrowRight className="w-4 h-4" />
</Link>
{boardSkills.length === 0 && (
<p className="text-[13px] text-[#687386] py-2">
No Board skills registered yet. A Board skill declares a section, where it
sits and what it reads.
</p>
)}
</div>
</div>
{/* Skill Development */}
<div className="bg-white rounded-2xl border border-[#E0E4EA] p-6 shadow-xs space-y-4">
<div className="flex items-center justify-between border-b border-[#E0E4EA] pb-3">
<div className="flex items-center gap-2">
<TrendingUp className="w-5 h-5 text-[#16A765]" />
<h2 className="text-[16px] font-bold text-[#101820]">Skill Progression Tracking</h2>
</div>
<span className="text-[12px] font-semibold text-[#16A765] bg-emerald-50 px-3 py-1 rounded-full border border-emerald-200/60">
Live Analytics
</span>
</div>
<p className="text-[13px] text-[#687386]">
Track talent advancement across training paths, verified levels, and candidate endorsement histories.
</p>
<div className="pt-2">
<Link
to="/admin/workspace/skill-development"
to="/admin/workspace/skills?tab=ui"
className="w-full inline-flex items-center justify-center gap-2 px-5 py-3 rounded-xl border border-[#E0E4EA] bg-white hover:bg-[#F8F8F8] text-[#101820] text-[13px] font-semibold transition-all shadow-xs"
>
<TrendingUp className="w-4 h-4 text-[#16A765]" />
View Skill Progression & Talent Growth
<LayoutTemplate className="w-4 h-4 text-[#0838E0]" />
Manage Board Skills
<ArrowRight className="w-4 h-4" />
</Link>
</div>
@@ -199,9 +221,15 @@ export default function AdminWorkspace() {
<div className="flex items-start gap-3.5 p-5 rounded-2xl bg-blue-50/60 border border-blue-200/50 text-[#0838E0] text-[13px] leading-relaxed">
<BookOpen className="w-5 h-5 shrink-0 text-[#0838E0] mt-0.5" />
<div>
<p className="font-bold text-[#101820]">Unified Markdown Registry Architecture</p>
<p className="font-bold text-[#101820]">AI skills and workforce training are different things</p>
<p className="text-[#687386] mt-0.5">
Skills define what Owliver can execute autonomously. Training paths define what the human workforce can be verified in. Both are defined as structured Markdown in one central registry, keeping candidate evaluation and skill progression seamlessly synchronized.
This page governs <span className="font-semibold">AI agent skills</span> — what Owliver
understands and what a Board skill draws on a page. <span className="font-semibold">Workforce
training</span> — training paths, proving challenges, skill verification and talent
progression — is what a person learns, and it is managed in{' '}
<Link to="/admin/university" className="font-semibold underline hover:no-underline">KROW Forge</Link>.
Both are Markdown in one registry, read through separate queries so neither appears in the
other’s surface.
</p>
</div>
</div>