refactor(ui): unify operational alert banners
This commit is contained in:
parent
3951767ab1
commit
d4846b73cc
@ -7,7 +7,7 @@ import {
|
|||||||
import { useCanonicalLifecycle } from '../hooks/useCanonicalLifecycle';
|
import { useCanonicalLifecycle } from '../hooks/useCanonicalLifecycle';
|
||||||
import { fetchTradeHistory } from '../lib/tradeHistoryApi';
|
import { fetchTradeHistory } from '../lib/tradeHistoryApi';
|
||||||
import { fetchPositionsBootstrap } from '../lib/positionsApi';
|
import { fetchPositionsBootstrap } from '../lib/positionsApi';
|
||||||
import { Badge, Button, Input, Select } from '../components/ui/Primitives';
|
import { AlertBanner, Badge, Button, Input, Select } from '../components/ui/Primitives';
|
||||||
|
|
||||||
|
|
||||||
interface TradeRecord {
|
interface TradeRecord {
|
||||||
@ -438,15 +438,15 @@ export const HistoryTab = ({ botState }: HistoryTabProps) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{!hasCanonicalLifecycle && (
|
{!hasCanonicalLifecycle && (
|
||||||
<div className="rounded-xl border border-amber-500/30 bg-amber-500/10 text-amber-300 text-xs px-3 py-2">
|
<AlertBanner tone="warning" title="Canonical lifecycle unavailable">
|
||||||
Canonical lifecycle is unavailable{canonicalLoading ? ' (loading)' : ''}. History is using fallback ledger sources.
|
History is using fallback ledger sources{canonicalLoading ? ' while loading' : ''}.
|
||||||
{canonicalError ? ` ${canonicalError}` : ''}
|
{canonicalError ? ` ${canonicalError}` : ''}
|
||||||
</div>
|
</AlertBanner>
|
||||||
)}
|
)}
|
||||||
{canonicalSnapshot?.diagnostics?.truncated && (
|
{canonicalSnapshot?.diagnostics?.truncated && (
|
||||||
<div className="rounded-xl border border-red-500/30 bg-red-500/10 text-red-300 text-xs px-3 py-2">
|
<AlertBanner tone="error" title="Lifecycle snapshot truncated">
|
||||||
Canonical lifecycle snapshot is truncated ({canonicalSnapshot.diagnostics.orderRows} rows). Review a narrower scope for exact audit totals.
|
{canonicalSnapshot.diagnostics.orderRows} rows were returned. Review a narrower scope for exact audit totals.
|
||||||
</div>
|
</AlertBanner>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Performance Metrics Bar */}
|
{/* Performance Metrics Bar */}
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import { createRequestId } from '../../../shared/request-id.js';
|
|||||||
import { Layers, ListFilter, Link2, GitBranch, AlertTriangle, Lock, RefreshCw, CheckCircle, XCircle } from 'lucide-react';
|
import { Layers, ListFilter, Link2, GitBranch, AlertTriangle, Lock, RefreshCw, CheckCircle, XCircle } from 'lucide-react';
|
||||||
import { useCanonicalLifecycle } from '../hooks/useCanonicalLifecycle';
|
import { useCanonicalLifecycle } from '../hooks/useCanonicalLifecycle';
|
||||||
import { fetchPositionsBootstrap } from '../lib/positionsApi';
|
import { fetchPositionsBootstrap } from '../lib/positionsApi';
|
||||||
import { Badge, Button, Input, Select } from '../components/ui/Primitives';
|
import { AlertBanner, Badge, Button, Input, Select } from '../components/ui/Primitives';
|
||||||
|
|
||||||
interface PositionsTabProps {
|
interface PositionsTabProps {
|
||||||
botState: BotState;
|
botState: BotState;
|
||||||
@ -1343,66 +1343,45 @@ export const PositionsTab = ({ botState, onManageHolding }: PositionsTabProps) =
|
|||||||
</header>
|
</header>
|
||||||
|
|
||||||
{!hasCanonicalLifecycle && (
|
{!hasCanonicalLifecycle && (
|
||||||
<div className="rounded-xl border border-amber-500/30 bg-amber-500/10 text-amber-300 text-xs px-3 py-2">
|
<AlertBanner tone="warning" title="Canonical lifecycle unavailable">
|
||||||
Canonical lifecycle is unavailable{canonicalLoading ? ' (loading)' : ''}. Truth labels are in fallback mode (DB/runtime-derived).
|
Truth labels are in fallback mode (DB/runtime-derived){canonicalLoading ? ' while loading' : ''}.
|
||||||
{canonicalError ? ` ${canonicalError}` : ''}
|
{canonicalError ? ` ${canonicalError}` : ''}
|
||||||
</div>
|
</AlertBanner>
|
||||||
)}
|
)}
|
||||||
{canonicalSnapshot?.diagnostics?.truncated && (
|
{canonicalSnapshot?.diagnostics?.truncated && (
|
||||||
<div className="rounded-xl border border-red-500/30 bg-red-500/10 text-red-300 text-xs px-3 py-2">
|
<AlertBanner tone="error" title="Lifecycle snapshot truncated">
|
||||||
Canonical lifecycle snapshot is truncated ({canonicalSnapshot.diagnostics.orderRows} rows). Narrow profile scope before operational decisions.
|
{canonicalSnapshot.diagnostics.orderRows} rows were returned. Narrow profile scope before operational decisions.
|
||||||
</div>
|
</AlertBanner>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Stale Orders Warning Banner */}
|
{/* Stale Orders Warning Banner */}
|
||||||
{staleWarningOrders.length > 0 && (
|
{staleWarningOrders.length > 0 && (
|
||||||
<div className="bg-yellow-500/10 border border-yellow-500/30 rounded-lg p-4 flex items-start gap-3">
|
<AlertBanner tone="warning" title={`${staleWarningOrders.length} Stale Order${staleWarningOrders.length > 1 ? 's' : ''} Detected`}>
|
||||||
<span className="text-yellow-400 text-xl">⚠️</span>
|
Some orders have remained in <code className="rounded bg-black/10 px-1">pending_new</code> for more than 5 minutes
|
||||||
<div className="flex-1">
|
without stronger fill or position evidence. The background sync service is re-checking their exchange status.
|
||||||
<h4 className="text-yellow-400 font-bold text-sm mb-1">
|
</AlertBanner>
|
||||||
{staleWarningOrders.length} Stale Order{staleWarningOrders.length > 1 ? 's' : ''} Detected
|
)}
|
||||||
</h4>
|
|
||||||
<p className="text-gray-400 text-xs">
|
{positionMismatches.length > 0 && (
|
||||||
Some orders have remained in <code className="bg-black/30 px-1 rounded">pending_new</code> for more than 5 minutes
|
<AlertBanner tone="error" title={`Lifecycle Mismatch Diagnostics (${positionMismatches.length})`}>
|
||||||
without stronger fill or position evidence. The background sync service is re-checking their exchange status.
|
<p className="mb-3">
|
||||||
</p>
|
One or more open positions do not have a clean entry-order lineage by profile and trade ID.
|
||||||
</div>
|
</p>
|
||||||
</div>
|
<div className="space-y-2">
|
||||||
|
{positionMismatches.map((issue) => (
|
||||||
|
<div key={issue.id} className="flex flex-wrap items-center gap-2 rounded-lg border border-[var(--border)] bg-[var(--card)] px-2 py-1 text-[10px]">
|
||||||
|
<Badge variant={issue.severity === 'critical' ? 'danger' : 'warning'} size="sm">
|
||||||
|
{issue.severity}
|
||||||
|
</Badge>
|
||||||
|
<span className="font-semibold text-[var(--foreground)]">{issue.profileName}</span>
|
||||||
|
<span className="font-mono text-[var(--foreground)]">{issue.symbol}</span>
|
||||||
|
<span className="font-mono text-[var(--muted-foreground)]">{issue.tradeId}</span>
|
||||||
|
<span className="text-[var(--muted-foreground)]">{issue.reason}</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</AlertBanner>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{positionMismatches.length > 0 && (
|
|
||||||
<div className="bg-red-500/10 border border-red-500/30 rounded-lg p-4">
|
|
||||||
<div className="flex items-start gap-3">
|
|
||||||
<AlertTriangle className="text-red-400 mt-0.5" size={18} />
|
|
||||||
<div className="flex-1 space-y-3">
|
|
||||||
<div>
|
|
||||||
<h4 className="text-red-400 font-bold text-sm">
|
|
||||||
Lifecycle Mismatch Diagnostics ({positionMismatches.length})
|
|
||||||
</h4>
|
|
||||||
<p className="text-gray-400 text-xs">
|
|
||||||
One or more open positions do not have a clean entry-order lineage by profile and trade ID.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div className="space-y-2">
|
|
||||||
{positionMismatches.map((issue) => (
|
|
||||||
<div key={issue.id} className="flex flex-wrap items-center gap-2 text-[10px] border border-white/10 rounded px-2 py-1">
|
|
||||||
<span className={`px-1.5 py-0.5 rounded font-bold uppercase tracking-wider ${issue.severity === 'critical'
|
|
||||||
? 'bg-red-500/20 text-red-300 border border-red-500/20'
|
|
||||||
: 'bg-yellow-500/20 text-yellow-300 border border-yellow-500/20'
|
|
||||||
}`}>
|
|
||||||
{issue.severity}
|
|
||||||
</span>
|
|
||||||
<span className="text-gray-300 font-semibold">{issue.profileName}</span>
|
|
||||||
<span className="text-white font-mono">{issue.symbol}</span>
|
|
||||||
<span className="text-zinc-500 font-mono">{issue.tradeId}</span>
|
|
||||||
<span className="text-zinc-400">{issue.reason}</span>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<section className="positions-section">
|
<section className="positions-section">
|
||||||
<div className="flex items-center gap-2 mb-4">
|
<div className="flex items-center gap-2 mb-4">
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user