feat: New MC with left sidebar + Horus AI Management

This commit is contained in:
root
2026-02-16 12:21:12 +00:00
parent 98dfe1a442
commit 604b4b7db4
3 changed files with 481 additions and 191 deletions
+183
View File
@@ -0,0 +1,183 @@
"use client";
import { useState, useEffect } from "react";
import { AISkill, ApiConfig, CronJob, defaultSkills, defaultApis, defaultCronJobs } from "@/lib/ai-management/types";
const STORAGE_KEYS = {
skills: "horus:skills",
apis: "horus:apis",
crons: "horus:crons",
};
export default function AIManagement() {
const [skills, setSkills] = useState<AISkill[]>(defaultSkills);
const [apis, setApis] = useState<ApiConfig[]>(defaultApis);
const [crons, setCrons] = useState<CronJob[]>(defaultCronJobs);
const [activeTab, setActiveTab] = useState<"skills" | "apis" | "crons">("skills");
// Load from localStorage
useEffect(() => {
if (typeof window === "undefined") return;
const savedSkills = localStorage.getItem(STORAGE_KEYS.skills);
if (savedSkills) setSkills(JSON.parse(savedSkills));
const savedApis = localStorage.getItem(STORAGE_KEYS.apis);
if (savedApis) setApis(JSON.parse(savedApis));
const savedCrons = localStorage.getItem(STORAGE_KEYS.crons);
if (savedCrons) setCrons(JSON.parse(savedCrons));
}, []);
// Save changes
const toggleSkill = (id: string) => {
const updated = skills.map(s => s.id === id ? { ...s, enabled: !s.enabled } : s);
setSkills(updated);
localStorage.setItem(STORAGE_KEYS.skills, JSON.stringify(updated));
};
const toggleCron = (id: string) => {
const updated = crons.map(c => c.id === id ? { ...c, enabled: !c.enabled } : c);
setCrons(updated);
localStorage.setItem(STORAGE_KEYS.crons, JSON.stringify(updated));
};
const categoryColors: Record<string, string> = {
development: "bg-blue-500/20 text-blue-400",
research: "bg-purple-500/20 text-purple-400",
automation: "bg-green-500/20 text-green-400",
communication: "bg-yellow-500/20 text-yellow-400",
};
return (
<div className="space-y-6">
{/* Header */}
<div>
<h2 className="text-2xl font-bold">🤖 Horus AI Management</h2>
<p className="text-white/60 mt-1">Configure skills, APIs, and automation for your AI assistant</p>
</div>
{/* Tabs */}
<div className="flex gap-2">
{[
{ id: "skills", label: "Skills", icon: "🧩" },
{ id: "apis", label: "APIs", icon: "🔑" },
{ id: "crons", label: "Automation", icon: "⏰" },
].map((tab) => (
<button
key={tab.id}
onClick={() => setActiveTab(tab.id as any)}
className={`px-4 py-2 rounded-lg text-sm font-medium transition ${
activeTab === tab.id
? "bg-brand-pink text-white"
: "bg-white/10 text-white/70 hover:bg-white/20"
}`}
>
{tab.icon} {tab.label}
</button>
))}
</div>
{/* Skills Tab */}
{activeTab === "skills" && (
<div className="grid gap-3">
{skills.map((skill) => (
<div
key={skill.id}
className="flex items-center justify-between p-4 rounded-xl border border-white/10 bg-white/5"
>
<div className="flex items-center gap-3">
<div className={`px-2 py-1 rounded text-xs font-medium ${categoryColors[skill.category]}`}>
{skill.category}
</div>
<div>
<p className="font-medium">{skill.name}</p>
<p className="text-sm text-white/50">{skill.description}</p>
</div>
</div>
<button
onClick={() => toggleSkill(skill.id)}
className={`w-12 h-6 rounded-full transition relative ${
skill.enabled ? "bg-green-500" : "bg-white/20"
}`}
>
<span
className={`absolute top-1 w-4 h-4 rounded-full bg-white transition ${
skill.enabled ? "left-7" : "left-1"
}`}
/>
</button>
</div>
))}
</div>
)}
{/* APIs Tab */}
{activeTab === "apis" && (
<div className="grid gap-3">
{apis.map((api) => (
<div
key={api.id}
className="flex items-center justify-between p-4 rounded-xl border border-white/10 bg-white/5"
>
<div>
<p className="font-medium flex items-center gap-2">
{api.name}
{api.configured && <span className="text-green-400 text-xs"> Configured</span>}
</p>
<p className="text-sm text-white/50">{api.description}</p>
</div>
<button
className={`px-3 py-1.5 rounded-lg text-xs font-medium ${
api.configured
? "bg-green-500/20 text-green-400"
: "bg-white/10 text-white/60 hover:bg-white/20"
}`}
>
{api.configured ? "Active" : "Configure"}
</button>
</div>
))}
<div className="mt-4 p-4 rounded-xl border border-yellow-500/30 bg-yellow-500/10">
<p className="text-sm text-yellow-200">
💡 To configure APIs, give me the keys or run: <code className="bg-black/30 px-2 py-1 rounded">openclaw configure --section auth --set KEY=value</code>
</p>
</div>
</div>
)}
{/* Automation/Crons Tab */}
{activeTab === "crons" && (
<div className="grid gap-3">
{crons.map((cron) => (
<div
key={cron.id}
className="flex items-center justify-between p-4 rounded-xl border border-white/10 bg-white/5"
>
<div>
<p className="font-medium">{cron.name}</p>
<p className="text-sm text-white/50">
{cron.schedule}
{cron.nextRun && <span className="ml-2 text-brand-pink">Next: {cron.nextRun}</span>}
</p>
</div>
<button
onClick={() => toggleCron(cron.id)}
className={`w-12 h-6 rounded-full transition relative ${
cron.enabled ? "bg-green-500" : "bg-white/20"
}`}
>
<span
className={`absolute top-1 w-4 h-4 rounded-full bg-white transition ${
cron.enabled ? "left-7" : "left-1"
}`}
/>
</button>
</div>
))}
</div>
)}
</div>
);
}