import 'package:flutter/material.dart'; import 'package:iconsax/iconsax.dart'; import 'package:animate_do/animate_do.dart'; import 'package:getwidget/getwidget.dart'; import '../api/api.dart'; import '../dialogs/create_agent_dialog.dart'; /// Agents management page /// /// Displays all AI agents with ability to create, view, edit, and delete agents. /// Integrates with backend CQRS API for agent management. class AgentsPage extends StatefulWidget { const AgentsPage({super.key}); @override State createState() => _AgentsPageState(); } class _AgentsPageState extends State { final CqrsApiClient _apiClient = CqrsApiClient( config: ApiClientConfig.development, ); List? _agents; bool _isLoading = true; String? _errorMessage; @override void initState() { super.initState(); _loadAgents(); } @override void dispose() { _apiClient.dispose(); super.dispose(); } Future _loadAgents() async { setState(() { _isLoading = true; _errorMessage = null; }); // TODO: Implement list agents endpoint when available // For now, show empty state await Future.delayed(const Duration(milliseconds: 500)); setState(() { _agents = []; _isLoading = false; }); } Future _createAgent(CreateAgentCommand command) async { final Result result = await _apiClient.createAgent(command); result.when( success: (_) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Agent "${command.name}" created successfully'), backgroundColor: Theme.of(context).colorScheme.primary, ), ); _loadAgents(); } }, error: (ApiErrorInfo error) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Failed to create agent: ${error.message}'), backgroundColor: Theme.of(context).colorScheme.error, ), ); } }, ); } @override Widget build(BuildContext context) { final ColorScheme colorScheme = Theme.of(context).colorScheme; return Container( padding: const EdgeInsets.all(24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Header Section _buildHeader(colorScheme), const SizedBox(height: 24), // Content Section Expanded( child: _buildContent(colorScheme), ), ], ), ); } Widget _buildHeader(ColorScheme colorScheme) { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ // Title & Description Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'AI Agents', style: TextStyle( fontSize: 28, fontWeight: FontWeight.bold, color: colorScheme.onSurface, ), ), const SizedBox(height: 4), Text( 'Manage your AI agents and their configurations', style: TextStyle( fontSize: 14, color: colorScheme.onSurfaceVariant, ), ), ], ), // Create Agent Button FadeInRight( duration: const Duration(milliseconds: 400), child: ElevatedButton.icon( onPressed: () => _showCreateAgentDialog(), icon: const Icon(Iconsax.add, size: 20), label: const Text('Create Agent'), style: ElevatedButton.styleFrom( backgroundColor: colorScheme.primary, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), ), ), ], ); } Widget _buildContent(ColorScheme colorScheme) { if (_isLoading) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ CircularProgressIndicator( valueColor: AlwaysStoppedAnimation(colorScheme.primary), ), const SizedBox(height: 16), Text( 'Loading agents...', style: TextStyle( color: colorScheme.onSurfaceVariant, fontSize: 14, ), ), ], ), ); } if (_errorMessage != null) { return _buildErrorState(colorScheme); } if (_agents == null || _agents!.isEmpty) { return _buildEmptyState(colorScheme); } return _buildAgentsList(colorScheme); } Widget _buildEmptyState(ColorScheme colorScheme) { return Center( child: FadeIn( duration: const Duration(milliseconds: 600), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Iconsax.cpu, size: 80, color: colorScheme.onSurfaceVariant.withValues(alpha: 0.5), ), const SizedBox(height: 24), Text( 'No Agents Yet', style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: colorScheme.onSurface, ), ), const SizedBox(height: 12), Text( 'Create your first AI agent to get started', style: TextStyle( fontSize: 14, color: colorScheme.onSurfaceVariant, ), textAlign: TextAlign.center, ), const SizedBox(height: 32), ElevatedButton.icon( onPressed: () => _showCreateAgentDialog(), icon: const Icon(Iconsax.add), label: const Text('Create Your First Agent'), style: ElevatedButton.styleFrom( backgroundColor: colorScheme.primary, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric( horizontal: 32, vertical: 16, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), ), ], ), ), ); } Widget _buildErrorState(ColorScheme colorScheme) { return Center( child: FadeIn( duration: const Duration(milliseconds: 400), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Iconsax.danger, size: 64, color: colorScheme.error, ), const SizedBox(height: 16), Text( 'Error Loading Agents', style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: colorScheme.onSurface, ), ), const SizedBox(height: 8), Text( _errorMessage ?? 'Unknown error', style: TextStyle( fontSize: 14, color: colorScheme.onSurfaceVariant, ), textAlign: TextAlign.center, ), const SizedBox(height: 24), ElevatedButton.icon( onPressed: _loadAgents, icon: const Icon(Iconsax.refresh), label: const Text('Retry'), style: ElevatedButton.styleFrom( backgroundColor: colorScheme.primary, foregroundColor: Colors.white, ), ), ], ), ), ); } Widget _buildAgentsList(ColorScheme colorScheme) { return GridView.builder( gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: 400, childAspectRatio: 1.5, crossAxisSpacing: 16, mainAxisSpacing: 16, ), itemCount: _agents!.length, itemBuilder: (BuildContext context, int index) { return FadeInUp( duration: Duration(milliseconds: 300 + (index * 100)), child: _buildAgentCard(_agents![index], colorScheme), ); }, ); } Widget _buildAgentCard(AgentDto agent, ColorScheme colorScheme) { return Card( elevation: 0, color: colorScheme.surfaceContainerLow, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), side: BorderSide( color: colorScheme.outline.withValues(alpha: 0.2), width: 1, ), ), child: InkWell( onTap: () => _showAgentDetails(agent), borderRadius: BorderRadius.circular(16), child: Padding( padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Header Row Row( children: [ // Agent Type Icon Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: colorScheme.primary.withValues(alpha: 0.2), borderRadius: BorderRadius.circular(12), ), child: Icon( _getAgentTypeIcon(agent.type), color: colorScheme.primary, size: 24, ), ), const SizedBox(width: 12), // Agent Name & Status Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( agent.name, style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: colorScheme.onSurface, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), const SizedBox(height: 4), _buildStatusBadge(agent.status, colorScheme), ], ), ), // More Options IconButton( icon: Icon( Iconsax.more, color: colorScheme.onSurfaceVariant, ), onPressed: () => _showAgentMenu(agent), ), ], ), const SizedBox(height: 16), // Description Text( agent.description, style: TextStyle( fontSize: 13, color: colorScheme.onSurfaceVariant, ), maxLines: 2, overflow: TextOverflow.ellipsis, ), const Spacer(), // Footer Row( children: [ Icon( Iconsax.cpu, size: 14, color: colorScheme.onSurfaceVariant, ), const SizedBox(width: 6), Expanded( child: Text( '${agent.modelProvider}/${agent.modelName}', style: TextStyle( fontSize: 12, color: colorScheme.onSurfaceVariant, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), ), ], ), ], ), ), ), ); } Widget _buildStatusBadge(AgentStatus status, ColorScheme colorScheme) { Color badgeColor; IconData icon; switch (status) { case AgentStatus.active: badgeColor = Colors.green; icon = Iconsax.tick_circle5; case AgentStatus.inactive: badgeColor = Colors.orange; icon = Iconsax.pause_circle5; case AgentStatus.error: badgeColor = colorScheme.error; icon = Iconsax.danger5; } return Row( mainAxisSize: MainAxisSize.min, children: [ Icon(icon, size: 12, color: badgeColor), const SizedBox(width: 4), Text( status.value, style: TextStyle( fontSize: 11, color: badgeColor, fontWeight: FontWeight.w500, ), ), ], ); } IconData _getAgentTypeIcon(AgentType type) { switch (type) { case AgentType.codeGenerator: return Iconsax.code; case AgentType.codeReviewer: return Iconsax.search_zoom_in; case AgentType.debugger: return Iconsax.shield_search; case AgentType.documenter: return Iconsax.document_text; case AgentType.custom: return Iconsax.setting_2; } } void _showCreateAgentDialog() { showDialog( context: context, builder: (BuildContext context) { return CreateAgentDialog( onCreateAgent: _createAgent, ); }, ); } void _showAgentDetails(AgentDto agent) { // TODO: Implement agent details view ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Viewing agent: ${agent.name}'), ), ); } void _showAgentMenu(AgentDto agent) { // TODO: Implement agent menu (edit, delete, etc.) ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Agent menu for: ${agent.name}'), ), ); } }