diff --git a/components/settings/RoleBuilderTab.tsx b/components/settings/RoleBuilderTab.tsx new file mode 100644 index 0000000..c315b92 --- /dev/null +++ b/components/settings/RoleBuilderTab.tsx @@ -0,0 +1,732 @@ +import React, { useState, useEffect } from 'react'; +import { + WorkflowSchemaProfile, + ConfigurableRole, + RoleTypeSchema, + RoleFieldSchema +} from '../../types/roleSchema'; +import { RoleSchemaService } from '../../services/roleSchemaService'; + +interface RoleBuilderTabProps { + disabled?: boolean; +} + +const RoleBuilderTab: React.FC = ({ disabled = false }) => { + const [profiles, setProfiles] = useState([]); + const [selectedProfile, setSelectedProfile] = useState(null); + const [editingProfile, setEditingProfile] = useState(null); + const [editingRole, setEditingRole] = useState(null); + const [roleTypeSchemas] = useState(() => + RoleSchemaService.getInstance().getRoleTypeSchemas() + ); + const [showRoleModal, setShowRoleModal] = useState(false); + const [error, setError] = useState(null); + const [showImportModal, setShowImportModal] = useState(false); + const [importData, setImportData] = useState(''); + + const service = RoleSchemaService.getInstance(); + + useEffect(() => { + loadProfiles(); + }, []); + + const loadProfiles = () => { + try { + const loadedProfiles = service.getAllProfiles(); + setProfiles(loadedProfiles); + if (!selectedProfile && loadedProfiles.length > 0) { + setSelectedProfile(loadedProfiles[0]); + } + setError(null); + } catch (err) { + setError(err instanceof Error ? err.message : 'Failed to load profiles'); + } + }; + + const handleCreateProfile = () => { + const newProfile: WorkflowSchemaProfile = { + id: `profile-${Date.now()}`, + name: 'New Workflow Profile', + description: 'Custom workflow profile', + version: '1.0.0', + roles: [], + executionOrder: [], + globalSettings: { + maxTotalIterations: 15, + timeoutMinutes: 30, + allowParallelReviews: false + }, + metadata: { + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + author: 'User', + tags: [] + } + }; + setEditingProfile(newProfile); + }; + + const handleEditProfile = (profile: WorkflowSchemaProfile) => { + setEditingProfile({ ...profile }); + }; + + const handleSaveProfile = () => { + if (!editingProfile) return; + + try { + if (profiles.some(p => p.id === editingProfile.id && p !== selectedProfile)) { + service.addProfile(editingProfile); + } else { + service.updateProfile(editingProfile.id, editingProfile); + } + loadProfiles(); + setSelectedProfile(editingProfile); + setEditingProfile(null); + setError(null); + } catch (err) { + setError(err instanceof Error ? err.message : 'Failed to save profile'); + } + }; + + const handleDeleteProfile = (profileId: string) => { + try { + service.deleteProfile(profileId); + loadProfiles(); + if (selectedProfile?.id === profileId) { + setSelectedProfile(profiles.find(p => p.id !== profileId) || null); + } + setError(null); + } catch (err) { + setError(err instanceof Error ? err.message : 'Failed to delete profile'); + } + }; + + const handleAddRole = (typeId: string) => { + if (!editingProfile) return; + + const schema = roleTypeSchemas.find(s => s.id === typeId); + if (!schema) return; + + const newRole: ConfigurableRole = { + id: `role-${Date.now()}`, + typeId, + name: schema.name, + description: schema.description, + configuration: getDefaultConfiguration(schema), + executionSettings: { + enabled: true, + ...(schema.defaultSettings || {}), + maxLoops: schema.category === 'reviewer' ? 2 : undefined + } + }; + + setEditingRole(newRole); + setShowRoleModal(true); + }; + + const handleEditRole = (role: ConfigurableRole) => { + setEditingRole({ ...role }); + setShowRoleModal(true); + }; + + const handleSaveRole = () => { + if (!editingProfile || !editingRole) return; + + try { + const validation = service.validateRoleConfiguration(editingRole.typeId, editingRole.configuration); + if (!validation.isValid) { + setError(`Role configuration errors: ${validation.errors.join(', ')}`); + return; + } + + const existingIndex = editingProfile.roles.findIndex(r => r.id === editingRole.id); + if (existingIndex >= 0) { + editingProfile.roles[existingIndex] = editingRole; + } else { + editingProfile.roles.push(editingRole); + editingProfile.executionOrder.push(editingRole.id); + } + + setEditingProfile({ ...editingProfile }); + setShowRoleModal(false); + setEditingRole(null); + setError(null); + } catch (err) { + setError(err instanceof Error ? err.message : 'Failed to save role'); + } + }; + + const handleRemoveRole = (roleId: string) => { + if (!editingProfile) return; + + setEditingProfile({ + ...editingProfile, + roles: editingProfile.roles.filter(r => r.id !== roleId), + executionOrder: editingProfile.executionOrder.filter(id => id !== roleId) + }); + }; + + const getDefaultConfiguration = (schema: RoleTypeSchema): Record => { + const config: Record = {}; + schema.fields.forEach(field => { + if (field.defaultValue !== undefined) { + config[field.id] = field.defaultValue; + } + }); + return config; + }; + + const renderRoleField = (field: RoleFieldSchema, value: any, onChange: (value: any) => void) => { + const fieldId = `field-${field.id}`; + + switch (field.type) { + case 'text': + return ( + onChange(e.target.value)} + placeholder={field.placeholder} + className="w-full px-3 py-2 border border-theme rounded-md bg-theme-elevated text-theme-primary text-sm" + disabled={disabled} + /> + ); + + case 'textarea': + return ( +