refactor(ui): standardize operations table badges
This commit is contained in:
parent
c51544aa29
commit
3951767ab1
@ -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 { Button, Input, Select } from '../components/ui/Primitives';
|
import { Badge, Button, Input, Select } from '../components/ui/Primitives';
|
||||||
|
|
||||||
|
|
||||||
interface TradeRecord {
|
interface TradeRecord {
|
||||||
@ -53,6 +53,9 @@ interface HistoryTabProps {
|
|||||||
botState?: any;
|
botState?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const historySourceBadgeVariant = (source?: 'BOT' | 'MANUAL') => source === 'BOT' ? 'accent' : 'warning';
|
||||||
|
const historySideBadgeVariant = (side: string) => side === 'BUY' ? 'success' : side === 'SELL' ? 'danger' : 'neutral';
|
||||||
|
|
||||||
export interface HistoryDateBounds {
|
export interface HistoryDateBounds {
|
||||||
from: number | null;
|
from: number | null;
|
||||||
to: number | null;
|
to: number | null;
|
||||||
@ -587,11 +590,11 @@ export const HistoryTab = ({ botState }: HistoryTabProps) => {
|
|||||||
className={`${isLoss ? 'bg-red-500/[0.06] border-l-2 border-l-red-500/50' : ''} hover:bg-white/[0.02] transition-colors`}
|
className={`${isLoss ? 'bg-red-500/[0.06] border-l-2 border-l-red-500/50' : ''} hover:bg-white/[0.02] transition-colors`}
|
||||||
>
|
>
|
||||||
<td className="px-6 py-4">
|
<td className="px-6 py-4">
|
||||||
<span className={`px-2 py-0.5 rounded text-[10px] font-black tracking-tighter ${t.source === 'BOT' ? 'bg-purple-500/20 text-purple-400 border border-purple-500/20' : 'bg-orange-500/20 text-orange-400 border border-orange-500/20'}`}>
|
<Badge variant={historySourceBadgeVariant(t.source)} size="sm">
|
||||||
{t.source === 'BOT'
|
{t.source === 'BOT'
|
||||||
? (t.profile_id ? (profiles.find(p => p.id === t.profile_id)?.name || 'BOT') : 'BOT')
|
? (t.profile_id ? (profiles.find(p => p.id === t.profile_id)?.name || 'BOT') : 'BOT')
|
||||||
: 'MANUAL'}
|
: 'MANUAL'}
|
||||||
</span>
|
</Badge>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-4 text-[10px] text-gray-500 font-mono">
|
<td className="px-6 py-4 text-[10px] text-gray-500 font-mono">
|
||||||
{(t.timestamp || t.created_at) ? new Date(t.timestamp || t.created_at!).toLocaleString([], { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }) : '-'}
|
{(t.timestamp || t.created_at) ? new Date(t.timestamp || t.created_at!).toLocaleString([], { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }) : '-'}
|
||||||
@ -604,9 +607,9 @@ export const HistoryTab = ({ botState }: HistoryTabProps) => {
|
|||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-4 font-mono font-bold text-white">{t.symbol}</td>
|
<td className="px-6 py-4 font-mono font-bold text-white">{t.symbol}</td>
|
||||||
<td className="px-6 py-4">
|
<td className="px-6 py-4">
|
||||||
<span className={`text-[10px] font-black ${t.side === 'BUY' ? 'text-green-400' : t.side === 'SELL' ? 'text-red-400' : 'text-gray-400'}`}>
|
<Badge variant={historySideBadgeVariant(t.side)} size="sm">
|
||||||
{t.side}
|
{t.side}
|
||||||
</span>
|
</Badge>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-4 text-right text-xs font-mono text-cyan-300">
|
<td className="px-6 py-4 text-right text-xs font-mono text-cyan-300">
|
||||||
{capitalUsed !== null
|
{capitalUsed !== null
|
||||||
@ -630,9 +633,9 @@ export const HistoryTab = ({ botState }: HistoryTabProps) => {
|
|||||||
${pnlValue.toFixed(2)}
|
${pnlValue.toFixed(2)}
|
||||||
</div>
|
</div>
|
||||||
{isLoss && (
|
{isLoss && (
|
||||||
<div className="mt-1 inline-flex items-center px-1.5 py-0.5 rounded border border-red-500/40 bg-red-500/20 text-[8px] font-black uppercase tracking-wider text-red-200">
|
<Badge variant="danger" size="sm" className="mt-1 text-[10px]">
|
||||||
Loss Alert
|
Loss Alert
|
||||||
</div>
|
</Badge>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@ -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 { Button, Input, Select } from '../components/ui/Primitives';
|
import { Badge, Button, Input, Select } from '../components/ui/Primitives';
|
||||||
|
|
||||||
interface PositionsTabProps {
|
interface PositionsTabProps {
|
||||||
botState: BotState;
|
botState: BotState;
|
||||||
@ -274,7 +274,7 @@ export const normalizeOrder = (record: RawOrderRecord, fallbackSource?: OrderSou
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const SourceTruthVariants: Record<'exchange' | 'db' | 'reconciled' | 'unknown', { label: string; className: string }> = {
|
const SourceTruthVariants: Record<'exchange' | 'db' | 'reconciled' | 'unknown', { label: string; className: string }> = {
|
||||||
exchange: { label: 'Exchange', className: 'truth-pill exchange' },
|
exchange: { label: 'Exchange', className: 'truth-pill exchange' },
|
||||||
db: { label: 'DB', className: 'truth-pill db' },
|
db: { label: 'DB', className: 'truth-pill db' },
|
||||||
reconciled: { label: 'Reconciled', className: 'truth-pill reconciled' },
|
reconciled: { label: 'Reconciled', className: 'truth-pill reconciled' },
|
||||||
@ -293,6 +293,25 @@ const getTruthSourceForPosition = (entryOrder?: NormalizedOrder, canonicalAvaila
|
|||||||
return SourceTruthVariants.reconciled;
|
return SourceTruthVariants.reconciled;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const sourceBadgeVariant = (source: 'BOT' | 'MANUAL') => source === 'BOT' ? 'accent' : 'warning';
|
||||||
|
const sideBadgeVariant = (side: 'BUY' | 'SELL') => side === 'BUY' ? 'success' : 'danger';
|
||||||
|
const actionBadgeVariant = (action: OrderAction) => action === 'ENTRY' ? 'info' : 'warning';
|
||||||
|
const orderStatusBadgeVariant = (status: string, stale = false) => {
|
||||||
|
if (stale) return 'warning';
|
||||||
|
if (status === 'filled') return 'success';
|
||||||
|
if (status === 'expired') return 'warning';
|
||||||
|
if (status === 'unknown') return 'neutral';
|
||||||
|
if (status.includes('reject') || status.includes('fail') || status.includes('cancel')) return 'danger';
|
||||||
|
if (status.includes('pending') || status.includes('new')) return 'info';
|
||||||
|
return 'neutral';
|
||||||
|
};
|
||||||
|
const lifecycleStateBadgeVariant = (state: string) => {
|
||||||
|
if (state === 'CLOSED') return 'success';
|
||||||
|
if (state === 'PARTIAL_EXIT' || state === 'EXIT_PENDING') return 'warning';
|
||||||
|
if (state === 'ORPHAN_EXIT') return 'danger';
|
||||||
|
return 'info';
|
||||||
|
};
|
||||||
|
|
||||||
const getTruthSourceForOrder = (order: NormalizedOrder, historyKeys: Set<string>, canonicalAvailable: boolean = true) => {
|
const getTruthSourceForOrder = (order: NormalizedOrder, historyKeys: Set<string>, canonicalAvailable: boolean = true) => {
|
||||||
const status = order.status || '';
|
const status = order.status || '';
|
||||||
if (status.includes('pending') || status.includes('new') || status.includes('accepted')) {
|
if (status.includes('pending') || status.includes('new') || status.includes('accepted')) {
|
||||||
@ -1436,11 +1455,11 @@ export const PositionsTab = ({ botState, onManageHolding }: PositionsTabProps) =
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<tr key={pos.id} className="hover:bg-white/[0.02] transition-colors">
|
<tr key={pos.id} className="hover:bg-white/[0.02] transition-colors">
|
||||||
<td className="px-6 py-4">
|
<td className="px-6 py-4">
|
||||||
<span className={`px-2 py-0.5 rounded text-[10px] font-black tracking-tighter ${pos.source === 'BOT' ? 'bg-purple-500/20 text-purple-400 border border-purple-500/20' : 'bg-orange-500/20 text-orange-400 border border-orange-500/20'}`}>
|
<Badge variant={sourceBadgeVariant(pos.source)} size="sm">
|
||||||
{pos.source === 'BOT' ? (pos.profileName || profiles.find(pr => pr.id === pos.profileId)?.name || 'BOT') : 'MANUAL'}
|
{pos.source === 'BOT' ? (pos.profileName || profiles.find(pr => pr.id === pos.profileId)?.name || 'BOT') : 'MANUAL'}
|
||||||
</span>
|
</Badge>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-4">
|
<td className="px-6 py-4">
|
||||||
<span className={positionTruth.className}>{positionTruth.label}</span>
|
<span className={positionTruth.className}>{positionTruth.label}</span>
|
||||||
</td>
|
</td>
|
||||||
@ -1458,16 +1477,12 @@ export const PositionsTab = ({ botState, onManageHolding }: PositionsTabProps) =
|
|||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-4 font-mono font-bold text-white">{pos.symbol}</td>
|
<td className="px-6 py-4 font-mono font-bold text-white">{pos.symbol}</td>
|
||||||
<td className="px-6 py-4">
|
<td className="px-6 py-4">
|
||||||
<span className={`text-[10px] font-black ${pos.side === 'BUY' ? 'text-green-400' : 'text-red-400'}`}>{pos.side}</span>
|
<Badge variant={sideBadgeVariant(pos.side)} size="sm">{pos.side}</Badge>
|
||||||
{pos.planMode ? (
|
{pos.planMode ? (
|
||||||
<div className="mt-1 flex flex-wrap gap-1">
|
<div className="mt-1 flex flex-wrap gap-1">
|
||||||
<span className={`px-1.5 py-0.5 rounded text-[9px] font-black uppercase tracking-wider border ${
|
<Badge variant={pos.planMode === 'long_term' ? 'warning' : 'info'} size="sm" className="text-[10px]">
|
||||||
pos.planMode === 'long_term'
|
|
||||||
? 'bg-amber-500/10 text-amber-300 border-amber-500/20'
|
|
||||||
: 'bg-sky-500/10 text-sky-300 border-sky-500/20'
|
|
||||||
}`}>
|
|
||||||
{pos.planMode === 'long_term' ? 'Long-term hold' : 'Short-term managed'}
|
{pos.planMode === 'long_term' ? 'Long-term hold' : 'Short-term managed'}
|
||||||
</span>
|
</Badge>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</td>
|
</td>
|
||||||
@ -1479,14 +1494,14 @@ export const PositionsTab = ({ botState, onManageHolding }: PositionsTabProps) =
|
|||||||
{currentPrice !== null ? `$${currentPrice.toLocaleString()}` : '-'}
|
{currentPrice !== null ? `$${currentPrice.toLocaleString()}` : '-'}
|
||||||
<div className="mt-1 flex flex-wrap gap-1">
|
<div className="mt-1 flex flex-wrap gap-1">
|
||||||
{slBreached && (
|
{slBreached && (
|
||||||
<span className="px-1.5 py-0.5 rounded text-[9px] font-black uppercase tracking-wider bg-red-500/20 text-red-300 border border-red-500/20">
|
<Badge variant="danger" size="sm" className="text-[10px]">
|
||||||
SL breached
|
SL breached
|
||||||
</span>
|
</Badge>
|
||||||
)}
|
)}
|
||||||
{!slBreached && tpHit && (
|
{!slBreached && tpHit && (
|
||||||
<span className="px-1.5 py-0.5 rounded text-[9px] font-black uppercase tracking-wider bg-green-500/20 text-green-300 border border-green-500/20">
|
<Badge variant="success" size="sm" className="text-[10px]">
|
||||||
TP hit
|
TP hit
|
||||||
</span>
|
</Badge>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
@ -1704,9 +1719,9 @@ export const PositionsTab = ({ botState, onManageHolding }: PositionsTabProps) =
|
|||||||
)}
|
)}
|
||||||
</td>
|
</td>
|
||||||
<td className="px-4 py-4">
|
<td className="px-4 py-4">
|
||||||
<span className={`px-2 py-0.5 rounded text-[10px] font-black tracking-tighter ${order.source === 'BOT' ? 'bg-purple-500/20 text-purple-400 border border-purple-500/20' : 'bg-orange-500/20 text-orange-400 border border-orange-500/20'}`}>
|
<Badge variant={sourceBadgeVariant(order.source)} size="sm">
|
||||||
{order.profileId ? (profiles.find(pr => pr.id === order.profileId)?.name || 'BOT') : 'MANUAL'}
|
{order.profileId ? (profiles.find(pr => pr.id === order.profileId)?.name || 'BOT') : 'MANUAL'}
|
||||||
</span>
|
</Badge>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-4 py-4">
|
<td className="px-4 py-4">
|
||||||
<span className={truthSource.className}>{truthSource.label}</span>
|
<span className={truthSource.className}>{truthSource.label}</span>
|
||||||
@ -1715,21 +1730,18 @@ export const PositionsTab = ({ botState, onManageHolding }: PositionsTabProps) =
|
|||||||
{order.timestamp ? new Date(order.timestamp).toLocaleString([], { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }) : '-'}
|
{order.timestamp ? new Date(order.timestamp).toLocaleString([], { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }) : '-'}
|
||||||
</td>
|
</td>
|
||||||
<td className="px-4 py-4 font-mono font-bold text-white text-xs">{order.symbol}</td>
|
<td className="px-4 py-4 font-mono font-bold text-white text-xs">{order.symbol}</td>
|
||||||
<td className="px-4 py-4">
|
<td className="px-4 py-4">
|
||||||
{resolvedAction ? (
|
{resolvedAction ? (
|
||||||
<span className={`flex items-center gap-1 px-2 py-0.5 rounded text-[9px] font-bold uppercase tracking-wider w-fit ${isEntry
|
<Badge variant={actionBadgeVariant(resolvedAction)} size="sm">
|
||||||
? 'bg-blue-500/10 text-blue-400 border border-blue-500/20'
|
{isEntry ? 'ENTRY' : 'EXIT'}
|
||||||
: 'bg-amber-500/10 text-amber-400 border border-amber-500/20'
|
</Badge>
|
||||||
}`}>
|
) : (
|
||||||
{isEntry ? 'ENTRY' : 'EXIT'}
|
<span className="text-[10px] text-gray-500 uppercase">{order.type}</span>
|
||||||
</span>
|
)}
|
||||||
) : (
|
</td>
|
||||||
<span className="text-[10px] text-gray-500 uppercase">{order.type}</span>
|
<td className="px-4 py-4">
|
||||||
)}
|
<Badge variant={sideBadgeVariant(order.side)} size="sm">{order.side}</Badge>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-4 py-4">
|
|
||||||
<span className={`text-[10px] font-black ${order.side === 'BUY' ? 'text-green-400' : 'text-red-400'}`}>{order.side}</span>
|
|
||||||
</td>
|
|
||||||
<td className="px-4 py-4 text-xs font-mono text-gray-300">{Number(order.qty || 0).toFixed(4)}</td>
|
<td className="px-4 py-4 text-xs font-mono text-gray-300">{Number(order.qty || 0).toFixed(4)}</td>
|
||||||
<td className="px-4 py-4 text-xs font-mono text-gray-400">${Number(order.price).toLocaleString()}</td>
|
<td className="px-4 py-4 text-xs font-mono text-gray-400">${Number(order.price).toLocaleString()}</td>
|
||||||
<td className="px-4 py-4 text-right">
|
<td className="px-4 py-4 text-right">
|
||||||
@ -1746,30 +1758,21 @@ export const PositionsTab = ({ botState, onManageHolding }: PositionsTabProps) =
|
|||||||
const orderAge = order.timestamp ? Date.now() - order.timestamp : 0;
|
const orderAge = order.timestamp ? Date.now() - order.timestamp : 0;
|
||||||
const isStale = isPendingNew && orderAge > 5 * 60 * 1000;
|
const isStale = isPendingNew && orderAge > 5 * 60 * 1000;
|
||||||
|
|
||||||
let badgeClass = 'bg-white/10 text-gray-400';
|
let tooltip = '';
|
||||||
let tooltip = '';
|
|
||||||
|
if (isStale) {
|
||||||
if (order.status === 'filled') {
|
tooltip = 'Order pending for >5 min - sync in progress';
|
||||||
badgeClass = 'bg-green-500/20 text-green-400 border border-green-500/20';
|
} else if (isExpired) {
|
||||||
} else if (isStale) {
|
tooltip = 'Order not found on exchange - likely never executed';
|
||||||
badgeClass = 'bg-yellow-500/20 text-yellow-400 border border-yellow-500/20';
|
} else if (isUnknown) {
|
||||||
tooltip = 'Order pending for >5 min - sync in progress';
|
tooltip = 'Order status could not be verified';
|
||||||
} else if (isExpired) {
|
}
|
||||||
badgeClass = 'bg-orange-500/20 text-orange-400 border border-orange-500/20';
|
|
||||||
tooltip = 'Order not found on exchange - likely never executed';
|
return (
|
||||||
} else if (isUnknown) {
|
<div className="flex items-center gap-1">
|
||||||
badgeClass = 'bg-gray-500/20 text-gray-400 border border-gray-500/20';
|
<Badge variant={orderStatusBadgeVariant(order.status, isStale)} size="sm" title={tooltip}>
|
||||||
tooltip = 'Order status could not be verified';
|
{order.status}
|
||||||
}
|
</Badge>
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex items-center gap-1">
|
|
||||||
<span
|
|
||||||
className={`px-2 py-0.5 rounded text-[9px] font-black uppercase tracking-tighter ${badgeClass}`}
|
|
||||||
title={tooltip}
|
|
||||||
>
|
|
||||||
{order.status}
|
|
||||||
</span>
|
|
||||||
{isStale && (
|
{isStale && (
|
||||||
<span className="text-[8px] text-yellow-400" title="Order may be stale - sync in progress">!</span>
|
<span className="text-[8px] text-yellow-400" title="Order may be stale - sync in progress">!</span>
|
||||||
)}
|
)}
|
||||||
@ -1940,14 +1943,11 @@ export const PositionsTab = ({ botState, onManageHolding }: PositionsTabProps) =
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-4 py-4">
|
<td className="px-4 py-4">
|
||||||
<span className={`px-2 py-0.5 rounded text-[10px] font-black tracking-tighter ${trace.source === 'BOT'
|
<Badge variant={sourceBadgeVariant(trace.source)} size="sm">
|
||||||
? 'bg-purple-500/20 text-purple-400 border border-purple-500/20'
|
{trace.profileName}
|
||||||
: 'bg-orange-500/20 text-orange-400 border border-orange-500/20'
|
</Badge>
|
||||||
}`}>
|
</td>
|
||||||
{trace.profileName}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td className="px-4 py-4 text-xs font-mono font-bold text-white">
|
<td className="px-4 py-4 text-xs font-mono font-bold text-white">
|
||||||
{trace.symbol}
|
{trace.symbol}
|
||||||
</td>
|
</td>
|
||||||
@ -1955,14 +1955,11 @@ export const PositionsTab = ({ botState, onManageHolding }: PositionsTabProps) =
|
|||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
{trace.orderedEvents.map((event) => {
|
{trace.orderedEvents.map((event) => {
|
||||||
const actionLabel: OrderAction = event.action === 'EXIT' ? 'EXIT' : 'ENTRY';
|
const actionLabel: OrderAction = event.action === 'EXIT' ? 'EXIT' : 'ENTRY';
|
||||||
const actionClass = actionLabel === 'ENTRY'
|
return (
|
||||||
? 'bg-blue-500/10 text-blue-300 border border-blue-500/20'
|
<div key={`${trace.tradeId}-${event.id}-${event.timestamp}`} className="flex flex-wrap items-center gap-2 text-[9px]">
|
||||||
: 'bg-amber-500/10 text-amber-300 border border-amber-500/20';
|
<Badge variant={actionBadgeVariant(actionLabel)} size="sm">
|
||||||
return (
|
{actionLabel}
|
||||||
<div key={`${trace.tradeId}-${event.id}-${event.timestamp}`} className="flex flex-wrap items-center gap-2 text-[9px]">
|
</Badge>
|
||||||
<span className={`px-1.5 py-0.5 rounded font-bold ${actionClass}`}>
|
|
||||||
{actionLabel}
|
|
||||||
</span>
|
|
||||||
<span className="text-zinc-500 font-mono">
|
<span className="text-zinc-500 font-mono">
|
||||||
{event.timestamp ? new Date(event.timestamp).toLocaleString([], { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }) : '-'}
|
{event.timestamp ? new Date(event.timestamp).toLocaleString([], { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }) : '-'}
|
||||||
</span>
|
</span>
|
||||||
@ -1986,18 +1983,9 @@ export const PositionsTab = ({ botState, onManageHolding }: PositionsTabProps) =
|
|||||||
</td>
|
</td>
|
||||||
<td className="px-4 py-4 text-right">
|
<td className="px-4 py-4 text-right">
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<span className={`px-2 py-0.5 rounded text-[9px] font-black uppercase tracking-wider ${trace.state === 'CLOSED'
|
<Badge variant={lifecycleStateBadgeVariant(trace.state)} size="sm">
|
||||||
? 'bg-green-500/20 text-green-300 border border-green-500/20'
|
{trace.state}
|
||||||
: trace.state === 'PARTIAL_EXIT'
|
</Badge>
|
||||||
? 'bg-amber-500/20 text-amber-300 border border-amber-500/20'
|
|
||||||
: trace.state === 'ORPHAN_EXIT'
|
|
||||||
? 'bg-red-500/20 text-red-300 border border-red-500/20'
|
|
||||||
: trace.state === 'EXIT_PENDING'
|
|
||||||
? 'bg-yellow-500/20 text-yellow-300 border border-yellow-500/20'
|
|
||||||
: 'bg-blue-500/20 text-blue-300 border border-blue-500/20'
|
|
||||||
}`}>
|
|
||||||
{trace.state}
|
|
||||||
</span>
|
|
||||||
<div className="text-[9px] text-zinc-500 leading-tight text-right max-w-[240px] ml-auto">
|
<div className="text-[9px] text-zinc-500 leading-tight text-right max-w-[240px] ml-auto">
|
||||||
{trace.stateReason}
|
{trace.stateReason}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user