style: add CSS modules to all pages matching design system mock layouts
Replace inline styles with semantic CSS module classes for proper visual structure: card wrappers with borders/shadows, grid layouts for stat strips and charts, section headers, and typography classes. Pages updated: Dashboard, ExchangeDetail, RoutesMetrics, AgentHealth, AgentInstance. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
92
ui/src/pages/AgentInstance/AgentInstance.module.css
Normal file
92
ui/src/pages/AgentInstance/AgentInstance.module.css
Normal file
@@ -0,0 +1,92 @@
|
||||
.statStrip {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 10px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.agentHeader {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
.agentHeader h2 {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.routeBadges {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.chartsGrid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 14px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.chartCard {
|
||||
background: var(--bg-surface);
|
||||
border: 1px solid var(--border-subtle);
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: var(--shadow-card);
|
||||
padding: 16px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.chartHeader {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.chartTitle {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.sectionTitle {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.eventCard {
|
||||
background: var(--bg-surface);
|
||||
border: 1px solid var(--border-subtle);
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: var(--shadow-card);
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-height: 420px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.eventCardHeader {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 10px 16px;
|
||||
border-bottom: 1px solid var(--border-subtle);
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.infoCard {
|
||||
background: var(--bg-surface);
|
||||
border: 1px solid var(--border-subtle);
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: var(--shadow-card);
|
||||
padding: 16px;
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useParams } from 'react-router';
|
||||
import {
|
||||
StatCard, StatusDot, Badge, MonoText, Card,
|
||||
StatCard, StatusDot, Badge,
|
||||
LineChart, AreaChart, EventFeed, Breadcrumb, Spinner,
|
||||
SectionHeader, CodeBlock,
|
||||
CodeBlock,
|
||||
} from '@cameleer/design-system';
|
||||
import styles from './AgentInstance.module.css';
|
||||
import { useAgents, useAgentEvents } from '../../api/queries/agents';
|
||||
import { useStatsTimeseries } from '../../api/queries/executions';
|
||||
import { useGlobalFilters } from '@cameleer/design-system';
|
||||
@@ -59,21 +60,21 @@ export default function AgentInstance() {
|
||||
|
||||
{agent && (
|
||||
<>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: '0.75rem', margin: '1rem 0' }}>
|
||||
<div className={styles.agentHeader}>
|
||||
<StatusDot variant={agent.status === 'LIVE' ? 'live' : agent.status === 'STALE' ? 'stale' : 'dead'} />
|
||||
<h2>{agent.name}</h2>
|
||||
<Badge label={agent.status} color={agent.status === 'LIVE' ? 'success' : agent.status === 'STALE' ? 'warning' : 'error'} />
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', gap: '1rem', marginBottom: '1.5rem', flexWrap: 'wrap' }}>
|
||||
<div className={styles.statStrip}>
|
||||
<StatCard label="TPS" value={agent.tps?.toFixed(1) ?? '0'} />
|
||||
<StatCard label="Error Rate" value={agent.errorRate ? `${(agent.errorRate * 100).toFixed(1)}%` : '0%'} accent={agent.errorRate > 0.05 ? 'error' : undefined} />
|
||||
<StatCard label="Active Routes" value={`${agent.activeRoutes ?? 0}/${agent.totalRoutes ?? 0}`} />
|
||||
<StatCard label="Uptime" value={formatUptime(agent.uptimeSeconds ?? 0)} />
|
||||
</div>
|
||||
|
||||
<SectionHeader>Routes</SectionHeader>
|
||||
<div style={{ display: 'flex', gap: '0.5rem', flexWrap: 'wrap', marginBottom: '1.5rem' }}>
|
||||
<div className={styles.sectionTitle}>Routes</div>
|
||||
<div className={styles.routeBadges}>
|
||||
{(agent.routeIds || []).map((r: string) => (
|
||||
<Badge key={r} label={r} color="auto" />
|
||||
))}
|
||||
@@ -83,36 +84,40 @@ export default function AgentInstance() {
|
||||
|
||||
{chartData.length > 0 && (
|
||||
<>
|
||||
<SectionHeader>Performance</SectionHeader>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '1rem', marginBottom: '1.5rem' }}>
|
||||
<AreaChart series={[{ label: 'Throughput', data: chartData.map((d: any, i: number) => ({ x: i, y: d.throughput })) }]} height={200} />
|
||||
<LineChart series={[{ label: 'Latency', data: chartData.map((d: any, i: number) => ({ x: i, y: d.latency })) }]} height={200} />
|
||||
<div className={styles.sectionTitle}>Performance</div>
|
||||
<div className={styles.chartsGrid}>
|
||||
<div className={styles.chartCard}>
|
||||
<div className={styles.chartHeader}><div className={styles.chartTitle}>Throughput</div></div>
|
||||
<AreaChart series={[{ label: 'Throughput', data: chartData.map((d: any, i: number) => ({ x: i, y: d.throughput })) }]} height={200} />
|
||||
</div>
|
||||
<div className={styles.chartCard}>
|
||||
<div className={styles.chartHeader}><div className={styles.chartTitle}>Latency</div></div>
|
||||
<LineChart series={[{ label: 'Latency', data: chartData.map((d: any, i: number) => ({ x: i, y: d.latency })) }]} height={200} />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{feedEvents.length > 0 && (
|
||||
<>
|
||||
<SectionHeader>Events</SectionHeader>
|
||||
<div className={styles.eventCard}>
|
||||
<div className={styles.eventCardHeader}>Events</div>
|
||||
<EventFeed events={feedEvents} maxItems={50} />
|
||||
</>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{agent && (
|
||||
<>
|
||||
<SectionHeader>Agent Info</SectionHeader>
|
||||
<Card>
|
||||
<div style={{ padding: '1rem' }}>
|
||||
<CodeBlock content={JSON.stringify({
|
||||
id: agent.id,
|
||||
name: agent.name,
|
||||
group: agent.group,
|
||||
registeredAt: agent.registeredAt,
|
||||
lastHeartbeat: agent.lastHeartbeat,
|
||||
routeIds: agent.routeIds,
|
||||
}, null, 2)} />
|
||||
</div>
|
||||
</Card>
|
||||
<div className={styles.sectionTitle}>Agent Info</div>
|
||||
<div className={styles.infoCard}>
|
||||
<CodeBlock content={JSON.stringify({
|
||||
id: agent.id,
|
||||
name: agent.name,
|
||||
group: agent.group,
|
||||
registeredAt: agent.registeredAt,
|
||||
lastHeartbeat: agent.lastHeartbeat,
|
||||
routeIds: agent.routeIds,
|
||||
}, null, 2)} />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user