Fix Demo enterprise
This commit is contained in:
@@ -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>
|
||||
)}
|
||||
|
||||
@@ -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 */}
|
||||
|
||||
Reference in New Issue
Block a user