'use client' import { useState } from 'react' import { Chip, ChipConfirmModal, ChipInput, Search } from '@sim/emcn' import { createLogger } from '@sim/logger' import { getErrorMessage } from '@sim/utils/errors' import { ArrowRight, Plus } from 'lucide-react' import { useParams } from 'next/navigation' import { useQueryState } from 'nuqs' import { SkillTile } from '@/app/workspace/[workspaceId]/components' import { IntegrationTabsHeader } from '@/app/workspace/[workspaceId]/integrations/components/integration-tabs-header' import { ShowcaseWithExplore } from '@/app/workspace/[workspaceId]/integrations/components/showcase-with-explore' import { SkillModal } from '@/app/workspace/[workspaceId]/skills/components/skill-modal' import { skillIdParam, skillIdUrlKeys } from '@/app/workspace/[workspaceId]/skills/search-params' import { useDeleteSkill, useSkills } from '@/hooks/queries/skills' const logger = createLogger('SkillsSettings') const SKILLS_LABEL = 'Skills' interface SkillItemProps { name: string description: string onClick: () => void } function SkillItem({ name, description, onClick }: SkillItemProps) { return ( ) } interface SkillSectionProps { label: string children: React.ReactNode } function SkillSection({ label, children }: SkillSectionProps) { return (
{label}
{children}
) } export function Skills() { const params = useParams() const workspaceId = (params?.workspaceId as string) || '' const { data: skills = [], isLoading, error } = useSkills(workspaceId) const deleteSkillMutation = useDeleteSkill() const [searchTerm, setSearchTerm] = useState('') const [editingSkillId, setEditingSkillId] = useQueryState(skillIdParam.key, { ...skillIdParam.parser, ...skillIdUrlKeys, }) const [showAddForm, setShowAddForm] = useState(false) const [skillToDelete, setSkillToDelete] = useState<{ id: string; name: string } | null>(null) const [showDeleteDialog, setShowDeleteDialog] = useState(false) /** Derive the skill being edited from the loaded list — never store the object in the URL. */ const editingSkill = editingSkillId ? (skills.find((s) => s.id === editingSkillId) ?? null) : null const filteredSkills = skills.filter((s) => { if (!searchTerm.trim()) return true const searchLower = searchTerm.toLowerCase() return ( s.name.toLowerCase().includes(searchLower) || s.description.toLowerCase().includes(searchLower) ) }) const handleDeleteClick = (skillId: string) => { const s = skills.find((sk) => sk.id === skillId) if (!s) return setSkillToDelete({ id: skillId, name: s.name }) setShowDeleteDialog(true) } const handleDeleteSkill = async () => { if (!skillToDelete) return setShowDeleteDialog(false) try { await deleteSkillMutation.mutateAsync({ workspaceId, skillId: skillToDelete.id, }) logger.info(`Deleted skill: ${skillToDelete.id}`) } catch (error) { logger.error('Error deleting skill:', error) } finally { setSkillToDelete(null) } } const handleSkillSaved = () => { setShowAddForm(false) setEditingSkillId(null) } const showNoResults = searchTerm.trim() && filteredSkills.length === 0 const handleOpenAddForm = () => { setEditingSkillId(null) setShowAddForm(true) } const addButton = ( Add to Sim ) return (
setSearchTerm(e.target.value)} disabled={isLoading} className='flex-1' />
{error ? (
{getErrorMessage(error, 'Failed to load skills')}
) : filteredSkills.length > 0 ? ( {filteredSkills.map((s) => ( setEditingSkillId(s.id)} /> ))} ) : showNoResults ? (
No skills found matching “{searchTerm}”
) : null}
{ if (!open) { setShowAddForm(false) setEditingSkillId(null) } }} onSave={handleSkillSaved} onDelete={(skillId) => { setEditingSkillId(null) handleDeleteClick(skillId) }} initialValues={editingSkill ?? undefined} />
) }