Improve the frontend modals

This commit is contained in:
Urtzi Alfaro
2025-10-27 16:33:26 +01:00
parent 61376b7a9f
commit 858d985c92
143 changed files with 9289 additions and 2306 deletions

View File

@@ -1,6 +1,6 @@
import React, { useState, useMemo } from 'react';
import { Brain, TrendingUp, AlertCircle, Play, RotateCcw, Eye, Loader, CheckCircle } from 'lucide-react';
import { Button, Badge, Modal, Table, Select, StatsGrid, StatusCard, SearchAndFilter, type FilterConfig, Card } from '../../../../components/ui';
import { Button, Badge, Modal, Table, Select, StatsGrid, StatusCard, SearchAndFilter, type FilterConfig, Card, EmptyState } from '../../../../components/ui';
import { PageHeader } from '../../../../components/layout';
import { useToast } from '../../../../hooks/ui/useToast';
import { useCurrentTenant } from '../../../../stores/tenant.store';
@@ -116,7 +116,7 @@ const ModelsConfigPage: React.FC = () => {
hasModel: !!model,
model,
isTraining,
lastTrainingDate: model?.created_at,
lastTrainingDate: model?.created_at || undefined,
accuracy: model ?
(model.training_metrics?.mape !== undefined ? (100 - model.training_metrics.mape) :
(model as any).mape !== undefined ? (100 - (model as any).mape) :
@@ -209,13 +209,12 @@ const ModelsConfigPage: React.FC = () => {
}
return (
<div className="p-6 space-y-6">
<div className="space-y-6">
<PageHeader
title="Configuración de Modelos IA"
description="Gestiona el entrenamiento y configuración de modelos de predicción para cada ingrediente"
/>
{/* Statistics Cards */}
<StatsGrid
stats={[
@@ -232,39 +231,33 @@ const ModelsConfigPage: React.FC = () => {
variant: 'warning',
},
{
title: 'Modelos Huérfanos',
value: orphanedModels.length,
icon: AlertCircle,
variant: 'info',
title: 'Modelos Activos',
value: modelStatuses.filter(s => s.status === 'active').length,
icon: CheckCircle,
variant: 'success',
},
{
title: 'Precisión Promedio',
value: statsError ? 'N/A' : (statistics?.average_accuracy ? `${(100 - statistics.average_accuracy).toFixed(1)}%` : 'N/A'),
value: statsError ? 'N/A' : (statistics?.average_accuracy ? `${Number(statistics.average_accuracy).toFixed(1)}%` : 'N/A'),
icon: TrendingUp,
variant: 'success',
},
{
title: 'Total Modelos',
value: modelStatuses.length,
icon: Brain,
variant: 'info',
},
{
title: 'Modelos Huérfanos',
value: orphanedModels.length,
icon: AlertCircle,
variant: 'error',
},
]}
columns={4}
columns={3}
/>
{/* Orphaned Models Warning */}
{orphanedModels.length > 0 && (
<Card className="p-4 bg-orange-50 border-orange-200">
<div className="flex items-start gap-3">
<AlertCircle className="w-5 h-5 text-orange-600 mt-0.5" />
<div>
<h4 className="font-medium text-orange-900 mb-1">
Modelos Huérfanos Detectados
</h4>
<p className="text-sm text-orange-700">
Se encontraron {orphanedModels.length} modelos entrenados para ingredientes que ya no existen en el inventario.
Estos modelos pueden ser eliminados para optimizar el espacio de almacenamiento.
</p>
</div>
</div>
</Card>
)}
{/* Search and Filter Controls */}
<SearchAndFilter
searchValue={searchTerm}
@@ -289,18 +282,16 @@ const ModelsConfigPage: React.FC = () => {
/>
{/* Models Grid */}
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{filteredStatuses.length === 0 ? (
<div className="flex flex-col items-center justify-center py-12 col-span-full">
<Brain className="w-12 h-12 text-[var(--color-secondary)] mb-4" />
<h3 className="text-lg font-medium text-[var(--text-primary)] mb-2">
No se encontraron ingredientes
</h3>
<p className="text-[var(--text-secondary)] text-center">
No hay ingredientes que coincidan con los filtros aplicados.
</p>
</div>
) : (
{filteredStatuses.length === 0 ? (
<EmptyState
icon={Brain}
title="No se encontraron ingredientes"
description="No hay ingredientes que coincidan con los filtros aplicados."
className="col-span-full"
/>
) : (
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{(
filteredStatuses.map((status) => {
// Get status configuration for the StatusCard
const statusConfig = {
@@ -335,7 +326,7 @@ const ModelsConfigPage: React.FC = () => {
id={status.ingredient.id}
statusIndicator={statusConfig}
title={status.ingredient.name}
subtitle={status.ingredient.category}
subtitle={status.ingredient.category || undefined}
primaryValue={status.accuracy ? status.accuracy.toFixed(1) : 'N/A'}
primaryValueLabel="Precisión"
secondaryInfo={status.lastTrainingDate ? {
@@ -371,7 +362,8 @@ const ModelsConfigPage: React.FC = () => {
);
})
)}
</div>
</div>
)}
{/* Training Modal */}
<Modal
@@ -463,4 +455,4 @@ const ModelsConfigPage: React.FC = () => {
);
};
export default ModelsConfigPage;
export default ModelsConfigPage;