Files
syndarix/frontend/src/app/[locale]/(authenticated)/agents/[id]/page.tsx
Felipe Cardoso 8623eb56f5 feat(agents): add sorting by sort_order and include category & display fields in agent actions
- Implemented sorting of agent types by `sort_order` in Agents page.
- Added support for category, icon, color, sort_order, typical_tasks, and collaboration_hints fields in agent creation and update actions.
2026-01-06 18:20:04 +01:00

206 lines
6.6 KiB
TypeScript

/**
* Agent Type Detail/Edit Page
*
* Displays agent type details with options to edit, duplicate, or deactivate.
* Handles 'new' as a special ID to show the create form.
*/
'use client';
import { useCallback, useState } from 'react';
import { useParams } from 'next/navigation';
import { useRouter } from '@/lib/i18n/routing';
import { toast } from 'sonner';
import { AgentTypeDetail, AgentTypeForm } from '@/components/agents';
import {
useAgentType,
useCreateAgentType,
useUpdateAgentType,
useDeactivateAgentType,
useDuplicateAgentType,
} from '@/lib/api/hooks/useAgentTypes';
import type { AgentTypeCreateFormValues } from '@/lib/validations/agentType';
type ViewMode = 'detail' | 'edit' | 'create';
export default function AgentTypeDetailPage() {
const router = useRouter();
const params = useParams();
const id = params.id as string;
// Determine initial view mode
const isNew = id === 'new';
const [viewMode, setViewMode] = useState<ViewMode>(isNew ? 'create' : 'detail');
// Fetch agent type data (skip if creating new)
const { data: agentType, isLoading, error } = useAgentType(isNew ? null : id);
// Mutations
const createMutation = useCreateAgentType();
const updateMutation = useUpdateAgentType();
const deactivateMutation = useDeactivateAgentType();
const duplicateMutation = useDuplicateAgentType();
// Handle navigation back to list
const handleBack = useCallback(() => {
if (viewMode === 'edit') {
setViewMode('detail');
} else {
router.push('/agents');
}
}, [router, viewMode]);
// Handle edit button click
const handleEdit = useCallback(() => {
setViewMode('edit');
}, []);
// Handle form submission for create/update
const handleSubmit = useCallback(
async (data: AgentTypeCreateFormValues) => {
try {
if (isNew || viewMode === 'create') {
// Create new agent type
const result = await createMutation.mutateAsync({
name: data.name,
slug: data.slug,
description: data.description,
expertise: data.expertise,
personality_prompt: data.personality_prompt,
primary_model: data.primary_model,
fallback_models: data.fallback_models,
model_params: data.model_params,
mcp_servers: data.mcp_servers,
tool_permissions: data.tool_permissions,
is_active: data.is_active,
// Category and display fields
category: data.category,
icon: data.icon,
color: data.color,
sort_order: data.sort_order,
typical_tasks: data.typical_tasks,
collaboration_hints: data.collaboration_hints,
});
toast.success('Agent type created', {
description: `${result.name} has been created successfully`,
});
router.push(`/agents/${result.id}`);
} else {
// Update existing agent type
const result = await updateMutation.mutateAsync({
id,
data: {
name: data.name,
slug: data.slug,
description: data.description,
expertise: data.expertise,
personality_prompt: data.personality_prompt,
primary_model: data.primary_model,
fallback_models: data.fallback_models,
model_params: data.model_params,
mcp_servers: data.mcp_servers,
tool_permissions: data.tool_permissions,
is_active: data.is_active,
// Category and display fields
category: data.category,
icon: data.icon,
color: data.color,
sort_order: data.sort_order,
typical_tasks: data.typical_tasks,
collaboration_hints: data.collaboration_hints,
},
});
toast.success('Agent type updated', {
description: `${result.name} has been updated successfully`,
});
setViewMode('detail');
}
} catch (err) {
const message = err instanceof Error ? err.message : 'An error occurred';
toast.error('Failed to save agent type', { description: message });
}
},
[id, isNew, viewMode, createMutation, updateMutation, router]
);
// Handle duplicate
const handleDuplicate = useCallback(async () => {
if (!agentType) return;
try {
const result = await duplicateMutation.mutateAsync(agentType);
toast.success('Agent type duplicated', {
description: `${result.name} has been created`,
});
router.push(`/agents/${result.id}`);
} catch (err) {
const message = err instanceof Error ? err.message : 'An error occurred';
toast.error('Failed to duplicate agent type', { description: message });
}
}, [agentType, duplicateMutation, router]);
// Handle deactivate
const handleDeactivate = useCallback(async () => {
try {
await deactivateMutation.mutateAsync(id);
toast.success('Agent type deactivated', {
description: 'The agent type has been deactivated',
});
router.push('/agents');
} catch (err) {
const message = err instanceof Error ? err.message : 'An error occurred';
toast.error('Failed to deactivate agent type', { description: message });
}
}, [id, deactivateMutation, router]);
// Handle cancel from form
const handleCancel = useCallback(() => {
if (isNew) {
router.push('/agents');
} else {
setViewMode('detail');
}
}, [isNew, router]);
// Show error state
if (error && !isNew) {
return (
<div className="container mx-auto px-4 py-6">
<AgentTypeDetail
agentType={null}
onBack={handleBack}
onEdit={handleEdit}
onDuplicate={handleDuplicate}
onDeactivate={handleDeactivate}
/>
</div>
);
}
// Render based on view mode
return (
<div className="container mx-auto px-4 py-6">
{(viewMode === 'create' || viewMode === 'edit') && (
<AgentTypeForm
agentType={viewMode === 'edit' ? (agentType ?? undefined) : undefined}
onSubmit={handleSubmit}
onCancel={handleCancel}
isSubmitting={createMutation.isPending || updateMutation.isPending}
/>
)}
{viewMode === 'detail' && (
<AgentTypeDetail
agentType={agentType ?? null}
isLoading={isLoading}
onBack={handleBack}
onEdit={handleEdit}
onDuplicate={handleDuplicate}
onDeactivate={handleDeactivate}
isDeactivating={deactivateMutation.isPending}
/>
)}
</div>
);
}