import React, { useState, useEffect, useMemo } from 'react';
import SkillsPageContent from '../components/SkillsPageContent';
import { getSkills, createSkill, updateSkill, deleteSkill } from '../../../services/apiService';
export default function SkillsPage({ user, Icon }) {
const [skills, setSkills] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [searchQuery, setSearchQuery] = useState('');
const [activeFilter, setActiveFilter] = useState('all'); // all, system, mine, group
const [showSystemSkills, setShowSystemSkills] = useState(false);
const [viewingDoc, setViewingDoc] = useState(null);
const [showRawDoc, setShowRawDoc] = useState(false);
const [isModalOpen, setIsModalOpen] = useState(false);
const [editingSkill, setEditingSkill] = useState(null);
const [formData, setFormData] = useState({
name: '',
description: '',
skill_type: 'local',
config: '{}',
is_system: false,
system_prompt: '',
is_enabled: true,
features: ['swarm_control'],
extra_metadata: { emoji: '⚙️' },
preview_markdown: ''
});
const [showAdvanced, setShowAdvanced] = useState(false);
const fetchSkills = async () => {
try {
setLoading(true);
const data = await getSkills();
setSkills(data);
setError(null);
} catch (err) {
setError("Failed to load skills.");
} finally {
setLoading(false);
}
};
useEffect(() => {
fetchSkills();
}, []);
const filteredSkills = useMemo(() => {
return skills.filter(skill => {
const matchesSearch = skill.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
(skill.description || '').toLowerCase().includes(searchQuery.toLowerCase());
if (!matchesSearch) return false;
if (!showSystemSkills && skill.is_system && activeFilter !== 'system') return false;
if (activeFilter === 'all') return true;
if (activeFilter === 'system') return skill.is_system;
if (activeFilter === 'mine') return !skill.is_system && skill.owner_id === user?.id;
if (activeFilter === 'group') return skill.group_id && !skill.is_system;
return true;
});
}, [skills, searchQuery, activeFilter, user, showSystemSkills]);
const stats = useMemo(() => ({
total: skills.filter(s => showSystemSkills || activeFilter === 'system' || !s.is_system).length,
system: skills.filter(s => s.is_system).length,
mine: skills.filter(s => !s.is_system && s.owner_id === user?.id).length,
group: skills.filter(s => s.group_id).length,
enabled: skills.filter(s => s.is_enabled).length
}), [skills, user, showSystemSkills, activeFilter]);
const openModal = (skill = null) => {
if (skill) {
setEditingSkill(skill);
setFormData({
name: skill.name,
description: skill.description || '',
skill_type: skill.skill_type,
config: JSON.stringify(skill.config, null, 2),
is_system: skill.is_system,
system_prompt: skill.system_prompt || '',
is_enabled: skill.is_enabled ?? true,
features: skill.features || ['swarm_control'],
extra_metadata: skill.extra_metadata || { emoji: '⚙️' },
preview_markdown: skill.preview_markdown || ''
});
} else {
setEditingSkill(null);
setFormData({
name: '',
description: '',
skill_type: 'local',
config: '{}',
is_system: false,
system_prompt: '',
is_enabled: true,
features: ['swarm_control'],
extra_metadata: { emoji: '⚙️' },
preview_markdown: ''
});
}
setIsModalOpen(true);
};
const handleClone = (skill) => {
setEditingSkill(null);
setFormData({
name: `${skill.name}_clone`,
description: skill.description || '',
skill_type: skill.skill_type,
config: JSON.stringify(skill.config, null, 2),
is_system: false,
system_prompt: skill.system_prompt || '',
is_enabled: true,
features: skill.features || ['swarm_control'],
extra_metadata: skill.extra_metadata || { emoji: '⚙️' },
preview_markdown: skill.preview_markdown || ''
});
setIsModalOpen(true);
};
const closeModal = () => {
setIsModalOpen(false);
setEditingSkill(null);
setViewingDoc(null);
setShowRawDoc(false);
};
const handleSave = async () => {
try {
let configObj = {};
try {
configObj = JSON.parse(formData.config);
} catch (e) {
alert("Invalid JSON in config");
return;
}
const payload = {
...formData,
config: configObj
};
if (editingSkill) {
await updateSkill(editingSkill.id, payload);
} else {
await createSkill(payload);
}
closeModal();
fetchSkills();
} catch (err) {
alert("Error saving skill");
}
};
const handleDelete = async (id) => {
if (!window.confirm("Are you sure you want to delete this skill?")) return;
try {
await deleteSkill(id);
fetchSkills();
} catch (err) {
alert("Error deleting skill");
}
};
const isAdmin = user?.role === 'admin';
const context = {
user,
Icon,
loading,
error,
searchQuery,
setSearchQuery,
activeFilter,
setActiveFilter,
showSystemSkills,
setShowSystemSkills,
viewingDoc,
setViewingDoc,
showRawDoc,
setShowRawDoc,
isModalOpen,
openModal,
closeModal,
handleClone,
handleSave,
handleDelete,
isAdmin,
filteredSkills,
stats,
editingSkill,
formData,
setFormData,
showAdvanced,
setShowAdvanced
};
return <SkillsPageContent context={context} />;
}