diff --git a/apps/web/app/(dashboard)/skills/page.tsx b/apps/web/app/(dashboard)/skills/page.tsx index 95017940..309fe556 100644 --- a/apps/web/app/(dashboard)/skills/page.tsx +++ b/apps/web/app/(dashboard)/skills/page.tsx @@ -1,538 +1 @@ -"use client"; - -import { useState, useEffect, useCallback } from "react"; -import { - Sparkles, - Plus, - Trash2, - Save, - FileText, - FolderOpen, - AlertCircle, - X, -} from "lucide-react"; -import type { Skill, CreateSkillRequest, UpdateSkillRequest } from "@multica/types"; -import { - Dialog, - DialogContent, - DialogHeader, - DialogTitle, - DialogDescription, - DialogFooter, -} from "@/components/ui/dialog"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Textarea } from "@/components/ui/textarea"; -import { Label } from "@/components/ui/label"; -import { api } from "@/shared/api"; -import { useAuthStore } from "@/features/auth"; -import { useWorkspaceStore } from "@/features/workspace"; -import { useWSEvent } from "@/features/realtime"; - -// --------------------------------------------------------------------------- -// Create Skill Dialog -// --------------------------------------------------------------------------- - -function CreateSkillDialog({ - onClose, - onCreate, -}: { - onClose: () => void; - onCreate: (data: CreateSkillRequest) => Promise; -}) { - const [name, setName] = useState(""); - const [description, setDescription] = useState(""); - const [creating, setCreating] = useState(false); - - const handleSubmit = async () => { - if (!name.trim()) return; - setCreating(true); - try { - await onCreate({ name: name.trim(), description: description.trim() }); - onClose(); - } catch { - setCreating(false); - } - }; - - return ( - { if (!v) onClose(); }}> - - - Create Skill - - Create a reusable skill that can be assigned to agents. - - - -
-
- - setName(e.target.value)} - placeholder="e.g. Code Review, Bug Triage" - className="mt-1" - onKeyDown={(e) => e.key === "Enter" && handleSubmit()} - /> -
-
- - setDescription(e.target.value)} - placeholder="Brief description of what this skill does" - className="mt-1" - /> -
-
- - - - - -
-
- ); -} - -// --------------------------------------------------------------------------- -// Skill List Item -// --------------------------------------------------------------------------- - -function SkillListItem({ - skill, - isSelected, - onClick, -}: { - skill: Skill; - isSelected: boolean; - onClick: () => void; -}) { - return ( - - ); -} - -// --------------------------------------------------------------------------- -// File Editor -// --------------------------------------------------------------------------- - -function FileEditor({ - files, - onFilesChange, -}: { - files: { path: string; content: string }[]; - onFilesChange: (files: { path: string; content: string }[]) => void; -}) { - const [editingIndex, setEditingIndex] = useState(null); - - const addFile = () => { - onFilesChange([...files, { path: "", content: "" }]); - setEditingIndex(files.length); - }; - - const updateFile = (index: number, field: "path" | "content", value: string) => { - const updated = files.map((f, i) => - i === index ? { ...f, [field]: value } : f, - ); - onFilesChange(updated); - }; - - const removeFile = (index: number) => { - onFilesChange(files.filter((_, i) => i !== index)); - if (editingIndex === index) setEditingIndex(null); - }; - - return ( -
-
-
-

Supporting Files

-

- Templates, scripts, or reference files available to the agent. -

-
- -
- - {files.length === 0 ? ( -
- -

No supporting files

-
- ) : ( -
- {files.map((file, index) => ( -
-
- - updateFile(index, "path", e.target.value)} - placeholder="path/to/file.md" - className="h-7 border-0 p-0 text-xs font-mono shadow-none focus-visible:ring-0" - /> - - -
- {editingIndex === index && ( -