Fix Demo enterprise

This commit is contained in:
Urtzi Alfaro
2025-12-17 13:03:52 +01:00
parent 0bbfa010bf
commit 8bfe4f2dd7
111 changed files with 26200 additions and 2245 deletions

View File

@@ -27,6 +27,8 @@ interface ProductionStatusBlockProps {
runningBatches?: any[];
pendingBatches?: any[];
alerts?: any[]; // Add alerts prop for production-related alerts
equipmentAlerts?: any[]; // Equipment-specific alerts
productionAlerts?: any[]; // Production alerts (non-equipment)
onStartBatch?: (batchId: string) => Promise<void>;
onViewBatch?: (batchId: string) => void;
loading?: boolean;
@@ -37,6 +39,8 @@ export function ProductionStatusBlock({
runningBatches = [],
pendingBatches = [],
alerts = [],
equipmentAlerts = [],
productionAlerts = [],
onStartBatch,
onViewBatch,
loading,
@@ -46,13 +50,35 @@ export function ProductionStatusBlock({
const [processingId, setProcessingId] = useState<string | null>(null);
// Filter production-related alerts and deduplicate by ID
const productionAlerts = React.useMemo(() => {
// Also filter out alerts for batches already shown in late/running/pending sections
const filteredProductionAlerts = React.useMemo(() => {
const filtered = alerts.filter((alert: any) => {
const eventType = alert.event_type || '';
return eventType.includes('production.') ||
eventType.includes('equipment_maintenance') ||
eventType.includes('production_delay') ||
eventType.includes('batch_start_delayed');
// First filter by event type
const isProductionAlert = eventType.includes('production.') ||
eventType.includes('equipment_maintenance') ||
eventType.includes('production_delay') ||
eventType.includes('batch_start_delayed');
if (!isProductionAlert) return false;
// Get batch ID from alert
const batchId = alert.event_metadata?.batch_id || alert.entity_links?.production_batch;
// Filter out alerts for batches already shown in UI sections
if (batchId) {
const isLateBatch = lateToStartBatches.some(batch => batch.id === batchId);
const isRunningBatch = runningBatches.some(batch => batch.id === batchId);
const isPendingBatch = pendingBatches.some(batch => batch.id === batchId);
// If this alert is about a batch already shown, filter it out to prevent duplication
if (isLateBatch || isRunningBatch || isPendingBatch) {
return false;
}
}
return true;
});
// Deduplicate by alert ID to prevent duplicates from API + SSE
@@ -65,7 +91,7 @@ export function ProductionStatusBlock({
});
return Array.from(uniqueAlerts.values());
}, [alerts]);
}, [alerts, lateToStartBatches, runningBatches, pendingBatches]);
if (loading) {
return (
@@ -88,12 +114,14 @@ export function ProductionStatusBlock({
const hasLate = lateToStartBatches.length > 0;
const hasRunning = runningBatches.length > 0;
const hasPending = pendingBatches.length > 0;
const hasAlerts = productionAlerts.length > 0;
const hasEquipmentAlerts = equipmentAlerts.length > 0;
const hasProductionAlerts = filteredProductionAlerts.length > 0;
const hasAlerts = hasEquipmentAlerts || hasProductionAlerts;
const hasAnyProduction = hasLate || hasRunning || hasPending || hasAlerts;
const totalCount = lateToStartBatches.length + runningBatches.length + pendingBatches.length;
// Determine header status - prioritize alerts and late batches
const status = hasAlerts || hasLate ? 'error' : hasRunning ? 'info' : hasPending ? 'warning' : 'success';
// Determine header status - prioritize equipment alerts, then production alerts, then late batches
const status = hasEquipmentAlerts ? 'error' : hasProductionAlerts || hasLate ? 'warning' : hasRunning ? 'info' : hasPending ? 'warning' : 'success';
const statusStyles = {
success: {
@@ -718,17 +746,32 @@ export function ProductionStatusBlock({
{/* Content */}
{hasAnyProduction ? (
<div className="border-t border-[var(--border-primary)]">
{/* Production Alerts Section */}
{hasAlerts && (
{/* Equipment Alerts Section */}
{equipmentAlerts.length > 0 && (
<div className="bg-[var(--color-error-50)]">
<div className="px-6 py-3 border-b border-[var(--color-error-100)]">
<h3 className="text-sm font-semibold text-[var(--color-error-700)] flex items-center gap-2">
<AlertTriangle className="w-4 h-4" />
{t('dashboard:new_dashboard.production_status.alerts_section')}
{t('dashboard:new_dashboard.production_status.equipment_alerts')}
</h3>
</div>
{productionAlerts.map((alert, index) =>
renderAlertItem(alert, index, productionAlerts.length)
{equipmentAlerts.map((alert, index) =>
renderAlertItem(alert, index, equipmentAlerts.length)
)}
</div>
)}
{/* Production Alerts Section */}
{filteredProductionAlerts.length > 0 && (
<div className="bg-[var(--color-warning-50)]">
<div className="px-6 py-3 border-b border-[var(--color-warning-100)]">
<h3 className="text-sm font-semibold text-[var(--color-warning-700)] flex items-center gap-2">
<AlertTriangle className="w-4 h-4" />
{t('dashboard:new_dashboard.production_status.production_alerts')}
</h3>
</div>
{filteredProductionAlerts.map((alert, index) =>
renderAlertItem(alert, index, filteredProductionAlerts.length)
)}
</div>
)}

View File

@@ -21,10 +21,10 @@ import {
Sparkles,
TrendingUp,
} from 'lucide-react';
import type { DashboardData, OrchestrationSummary } from '../../../api/hooks/useDashboardData';
import type { ControlPanelData, OrchestrationSummary } from '../../../api/hooks/useControlPanelData';
interface SystemStatusBlockProps {
data: DashboardData | undefined;
data: ControlPanelData | undefined;
loading?: boolean;
}
@@ -137,8 +137,8 @@ export function SystemStatusBlock({ data, loading }: SystemStatusBlockProps) {
</span>
</div>
{/* Issues Prevented by AI */}
<div className="flex items-center gap-2 px-3 py-2 rounded-lg bg-[var(--bg-primary)] border border-[var(--border-primary)]">
{/* Issues Prevented by AI - Show specific issue types */}
<div className="flex items-center gap-2 px-3 py-2 rounded-lg bg-[var(--bg-primary)] border border-[var(--border-primary)] group relative">
<Bot className="w-5 h-5 text-[var(--color-primary)]" />
<span className="text-sm font-medium text-[var(--text-primary)]">
{issuesPreventedByAI}
@@ -146,6 +146,32 @@ export function SystemStatusBlock({ data, loading }: SystemStatusBlockProps) {
<span className="text-sm text-[var(--text-secondary)]">
{t('dashboard:new_dashboard.system_status.ai_prevented_label')}
</span>
{/* Show specific issue types on hover */}
{preventedIssues.length > 0 && (
<div className="absolute left-0 bottom-full mb-2 hidden group-hover:block z-10">
<div className="bg-[var(--bg-primary)] border border-[var(--border-primary)] rounded-lg shadow-lg p-3 min-w-[200px]">
<p className="text-sm font-semibold text-[var(--text-primary)] mb-2">
{t('dashboard:new_dashboard.system_status.prevented_issues_types')}
</p>
<div className="space-y-1 max-h-[150px] overflow-y-auto">
{preventedIssues.slice(0, 3).map((issue: any, index: number) => (
<div key={index} className="flex items-start gap-2 text-xs">
<CheckCircle2 className="w-3 h-3 text-[var(--color-success-500)] mt-0.5 flex-shrink-0" />
<span className="text-[var(--text-secondary)] truncate">
{issue.title || issue.event_type || issue.message || t('dashboard:new_dashboard.system_status.issue_prevented')}
</span>
</div>
))}
{preventedIssues.length > 3 && (
<div className="text-xs text-[var(--text-tertiary)] mt-1">
+{preventedIssues.length - 3} {t('common:more')}
</div>
)}
</div>
</div>
</div>
)}
</div>
{/* Last Run */}