refactor: strip AppShell+Sidebar wrappers from all page components
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,9 +1,6 @@
|
||||
import { useNavigate, useLocation } from 'react-router-dom'
|
||||
import { AppShell } from '../../design-system/layout/AppShell/AppShell'
|
||||
import { Sidebar } from '../../design-system/layout/Sidebar/Sidebar'
|
||||
import { TopBar } from '../../design-system/layout/TopBar/TopBar'
|
||||
import { Tabs } from '../../design-system/composites/Tabs/Tabs'
|
||||
import { SIDEBAR_APPS } from '../../mocks/sidebar'
|
||||
import styles from './Admin.module.css'
|
||||
import type { ReactNode } from 'react'
|
||||
|
||||
@@ -23,7 +20,7 @@ export function AdminLayout({ title, children }: AdminLayoutProps) {
|
||||
const location = useLocation()
|
||||
|
||||
return (
|
||||
<AppShell sidebar={<Sidebar apps={SIDEBAR_APPS} />}>
|
||||
<>
|
||||
<TopBar
|
||||
breadcrumb={[
|
||||
{ label: 'Admin', href: '/admin' },
|
||||
@@ -40,6 +37,6 @@ export function AdminLayout({ title, children }: AdminLayoutProps) {
|
||||
<div className={styles.adminContent}>
|
||||
{children}
|
||||
</div>
|
||||
</AppShell>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@ import { ChevronRight } from 'lucide-react'
|
||||
import styles from './AgentHealth.module.css'
|
||||
|
||||
// Layout
|
||||
import { AppShell } from '../../design-system/layout/AppShell/AppShell'
|
||||
import { Sidebar } from '../../design-system/layout/Sidebar/Sidebar'
|
||||
import { TopBar } from '../../design-system/layout/TopBar/TopBar'
|
||||
|
||||
// Composites
|
||||
@@ -28,7 +26,6 @@ import { useGlobalFilters } from '../../design-system/providers/GlobalFilterProv
|
||||
|
||||
// Mock data
|
||||
import { agents, type AgentHealth as AgentHealthData } from '../../mocks/agents'
|
||||
import { SIDEBAR_APPS } from '../../mocks/sidebar'
|
||||
import { agentEvents } from '../../mocks/agentEvents'
|
||||
|
||||
// ── URL scope parsing ────────────────────────────────────────────────────────
|
||||
@@ -317,19 +314,7 @@ export function AgentHealth() {
|
||||
const isFullWidth = scope.level !== 'all'
|
||||
|
||||
return (
|
||||
<AppShell
|
||||
sidebar={<Sidebar apps={SIDEBAR_APPS} />}
|
||||
detail={
|
||||
selectedInstance ? (
|
||||
<DetailPanel
|
||||
open={panelOpen}
|
||||
onClose={() => setPanelOpen(false)}
|
||||
title={selectedInstance.name}
|
||||
tabs={detailTabs}
|
||||
/>
|
||||
) : undefined
|
||||
}
|
||||
>
|
||||
<>
|
||||
<TopBar
|
||||
breadcrumb={buildBreadcrumb(scope)}
|
||||
environment="PRODUCTION"
|
||||
@@ -454,6 +439,16 @@ export function AgentHealth() {
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</AppShell>
|
||||
|
||||
{/* Detail panel (portals itself) */}
|
||||
{selectedInstance && (
|
||||
<DetailPanel
|
||||
open={panelOpen}
|
||||
onClose={() => setPanelOpen(false)}
|
||||
title={selectedInstance.name}
|
||||
tabs={detailTabs}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@ import { ChevronRight } from 'lucide-react'
|
||||
import styles from './AgentInstance.module.css'
|
||||
|
||||
// Layout
|
||||
import { AppShell } from '../../design-system/layout/AppShell/AppShell'
|
||||
import { Sidebar } from '../../design-system/layout/Sidebar/Sidebar'
|
||||
import { TopBar } from '../../design-system/layout/TopBar/TopBar'
|
||||
|
||||
// Composites
|
||||
@@ -28,7 +26,6 @@ import { useGlobalFilters } from '../../design-system/providers/GlobalFilterProv
|
||||
|
||||
// Data
|
||||
import { agents } from '../../mocks/agents'
|
||||
import { SIDEBAR_APPS } from '../../mocks/sidebar'
|
||||
import { agentEvents } from '../../mocks/agentEvents'
|
||||
|
||||
import { useState } from 'react'
|
||||
@@ -127,12 +124,12 @@ export function AgentInstance() {
|
||||
|
||||
if (!agent) {
|
||||
return (
|
||||
<AppShell sidebar={<Sidebar apps={SIDEBAR_APPS} />}>
|
||||
<>
|
||||
<TopBar breadcrumb={[{ label: 'Agents', href: '/agents' }, { label: 'Not Found' }]} environment="PRODUCTION" user={{ name: 'hendrik' }} />
|
||||
<div className={styles.content}>
|
||||
<div className={styles.notFound}>Agent instance not found.</div>
|
||||
</div>
|
||||
</AppShell>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -153,7 +150,7 @@ export function AgentInstance() {
|
||||
const statusColor = agent.status === 'live' ? 'success' : agent.status === 'stale' ? 'warning' : 'error'
|
||||
|
||||
return (
|
||||
<AppShell sidebar={<Sidebar apps={SIDEBAR_APPS} />}>
|
||||
<>
|
||||
<TopBar
|
||||
breadcrumb={[
|
||||
{ label: 'Applications', href: '/apps' },
|
||||
@@ -302,6 +299,6 @@ export function AgentInstance() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</AppShell>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
import { AppShell } from '../../design-system/layout/AppShell/AppShell'
|
||||
import { Sidebar } from '../../design-system/layout/Sidebar/Sidebar'
|
||||
import { TopBar } from '../../design-system/layout/TopBar/TopBar'
|
||||
import { EmptyState } from '../../design-system/primitives/EmptyState/EmptyState'
|
||||
import { SIDEBAR_APPS } from '../../mocks/sidebar'
|
||||
|
||||
export function ApiDocs() {
|
||||
return (
|
||||
<AppShell sidebar={<Sidebar apps={SIDEBAR_APPS} />}>
|
||||
<>
|
||||
<TopBar
|
||||
breadcrumb={[{ label: 'API Documentation' }]}
|
||||
environment="PRODUCTION"
|
||||
@@ -17,6 +14,6 @@ export function ApiDocs() {
|
||||
title="API Documentation"
|
||||
description="API documentation coming soon."
|
||||
/>
|
||||
</AppShell>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
import { useParams } from 'react-router-dom'
|
||||
import { AppShell } from '../../design-system/layout/AppShell/AppShell'
|
||||
import { Sidebar } from '../../design-system/layout/Sidebar/Sidebar'
|
||||
import { TopBar } from '../../design-system/layout/TopBar/TopBar'
|
||||
import { EmptyState } from '../../design-system/primitives/EmptyState/EmptyState'
|
||||
import { SIDEBAR_APPS } from '../../mocks/sidebar'
|
||||
|
||||
export function AppDetail() {
|
||||
const { id } = useParams<{ id: string }>()
|
||||
|
||||
return (
|
||||
<AppShell sidebar={<Sidebar apps={SIDEBAR_APPS} />}>
|
||||
<>
|
||||
<TopBar
|
||||
breadcrumb={[
|
||||
{ label: 'Applications', href: '/apps' },
|
||||
@@ -23,6 +20,6 @@ export function AppDetail() {
|
||||
title="Application Detail"
|
||||
description="Application detail view coming soon."
|
||||
/>
|
||||
</AppShell>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@ import { TrendingUp, TrendingDown, ArrowRight, ExternalLink, AlertTriangle } fro
|
||||
import styles from './Dashboard.module.css'
|
||||
|
||||
// Layout
|
||||
import { AppShell } from '../../design-system/layout/AppShell/AppShell'
|
||||
import { Sidebar } from '../../design-system/layout/Sidebar/Sidebar'
|
||||
import { TopBar } from '../../design-system/layout/TopBar/TopBar'
|
||||
|
||||
// Composites
|
||||
@@ -287,106 +285,7 @@ export function Dashboard() {
|
||||
const totalErrors = processorErrors.length + (hasExchangeError && processorErrors.length === 0 ? 1 : 0)
|
||||
|
||||
return (
|
||||
<AppShell
|
||||
sidebar={
|
||||
<Sidebar apps={SIDEBAR_APPS} />
|
||||
}
|
||||
detail={
|
||||
selectedExchange ? (
|
||||
<DetailPanel
|
||||
open={panelOpen}
|
||||
onClose={() => setPanelOpen(false)}
|
||||
title={`${selectedExchange.orderId} — ${selectedExchange.route}`}
|
||||
>
|
||||
{/* Link to full detail page */}
|
||||
<div className={styles.panelSection}>
|
||||
<button
|
||||
className={styles.openDetailLink}
|
||||
onClick={() => navigate(`/exchanges/${selectedExchange.id}`)}
|
||||
>
|
||||
Open full details <ArrowRight size={14} style={{ verticalAlign: 'middle' }} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Overview */}
|
||||
<div className={styles.panelSection}>
|
||||
<div className={styles.panelSectionTitle}>Overview</div>
|
||||
<div className={styles.overviewGrid}>
|
||||
<div className={styles.overviewRow}>
|
||||
<span className={styles.overviewLabel}>Status</span>
|
||||
<span className={styles.statusCell}>
|
||||
<StatusDot variant={statusToVariant(selectedExchange.status)} />
|
||||
<span>{statusLabel(selectedExchange.status)}</span>
|
||||
</span>
|
||||
</div>
|
||||
<div className={styles.overviewRow}>
|
||||
<span className={styles.overviewLabel}>Duration</span>
|
||||
<MonoText size="sm">{formatDuration(selectedExchange.durationMs)}</MonoText>
|
||||
</div>
|
||||
<div className={styles.overviewRow}>
|
||||
<span className={styles.overviewLabel}>Route</span>
|
||||
<span>{selectedExchange.route}</span>
|
||||
</div>
|
||||
<div className={styles.overviewRow}>
|
||||
<span className={styles.overviewLabel}>Customer</span>
|
||||
<MonoText size="sm">{selectedExchange.customer}</MonoText>
|
||||
</div>
|
||||
<div className={styles.overviewRow}>
|
||||
<span className={styles.overviewLabel}>Agent</span>
|
||||
<MonoText size="sm">{selectedExchange.agent}</MonoText>
|
||||
</div>
|
||||
<div className={styles.overviewRow}>
|
||||
<span className={styles.overviewLabel}>Correlation</span>
|
||||
<MonoText size="xs">{selectedExchange.correlationId}</MonoText>
|
||||
</div>
|
||||
<div className={styles.overviewRow}>
|
||||
<span className={styles.overviewLabel}>Timestamp</span>
|
||||
<MonoText size="xs">{selectedExchange.timestamp.toISOString()}</MonoText>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Errors */}
|
||||
{totalErrors > 0 && (
|
||||
<div className={styles.panelSection}>
|
||||
<div className={styles.panelSectionTitle}>
|
||||
Errors
|
||||
{totalErrors > 1 && (
|
||||
<Badge label={`+${totalErrors - 1} more`} color="error" variant="outlined" />
|
||||
)}
|
||||
</div>
|
||||
<div className={styles.errorBlock}>
|
||||
<div className={styles.errorClass}>
|
||||
{selectedExchange.errorClass ?? processorErrors[0]?.name}
|
||||
</div>
|
||||
<div className={styles.errorMessage}>
|
||||
{selectedExchange.errorMessage ?? `Failed at processor: ${processorErrors[0]?.name}`}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Route Flow */}
|
||||
<div className={styles.panelSection}>
|
||||
<div className={styles.panelSectionTitle}>Route Flow</div>
|
||||
<RouteFlow nodes={routeNodes} />
|
||||
</div>
|
||||
|
||||
{/* Processor Timeline */}
|
||||
<div className={styles.panelSection}>
|
||||
<div className={styles.panelSectionTitle}>
|
||||
Processor Timeline
|
||||
<span className={styles.panelSectionMeta}>{formatDuration(selectedExchange.durationMs)}</span>
|
||||
</div>
|
||||
<ProcessorTimeline
|
||||
processors={selectedExchange.processors}
|
||||
totalMs={selectedExchange.durationMs}
|
||||
/>
|
||||
</div>
|
||||
</DetailPanel>
|
||||
) : undefined
|
||||
}
|
||||
>
|
||||
<>
|
||||
{/* Top bar */}
|
||||
<TopBar
|
||||
breadcrumb={
|
||||
@@ -444,6 +343,101 @@ export function Dashboard() {
|
||||
|
||||
{/* Shortcuts bar */}
|
||||
<ShortcutsBar shortcuts={SHORTCUTS} />
|
||||
</AppShell>
|
||||
|
||||
{/* Detail panel (portals itself) */}
|
||||
{selectedExchange && (
|
||||
<DetailPanel
|
||||
open={panelOpen}
|
||||
onClose={() => setPanelOpen(false)}
|
||||
title={`${selectedExchange.orderId} — ${selectedExchange.route}`}
|
||||
>
|
||||
{/* Link to full detail page */}
|
||||
<div className={styles.panelSection}>
|
||||
<button
|
||||
className={styles.openDetailLink}
|
||||
onClick={() => navigate(`/exchanges/${selectedExchange.id}`)}
|
||||
>
|
||||
Open full details <ArrowRight size={14} style={{ verticalAlign: 'middle' }} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Overview */}
|
||||
<div className={styles.panelSection}>
|
||||
<div className={styles.panelSectionTitle}>Overview</div>
|
||||
<div className={styles.overviewGrid}>
|
||||
<div className={styles.overviewRow}>
|
||||
<span className={styles.overviewLabel}>Status</span>
|
||||
<span className={styles.statusCell}>
|
||||
<StatusDot variant={statusToVariant(selectedExchange.status)} />
|
||||
<span>{statusLabel(selectedExchange.status)}</span>
|
||||
</span>
|
||||
</div>
|
||||
<div className={styles.overviewRow}>
|
||||
<span className={styles.overviewLabel}>Duration</span>
|
||||
<MonoText size="sm">{formatDuration(selectedExchange.durationMs)}</MonoText>
|
||||
</div>
|
||||
<div className={styles.overviewRow}>
|
||||
<span className={styles.overviewLabel}>Route</span>
|
||||
<span>{selectedExchange.route}</span>
|
||||
</div>
|
||||
<div className={styles.overviewRow}>
|
||||
<span className={styles.overviewLabel}>Customer</span>
|
||||
<MonoText size="sm">{selectedExchange.customer}</MonoText>
|
||||
</div>
|
||||
<div className={styles.overviewRow}>
|
||||
<span className={styles.overviewLabel}>Agent</span>
|
||||
<MonoText size="sm">{selectedExchange.agent}</MonoText>
|
||||
</div>
|
||||
<div className={styles.overviewRow}>
|
||||
<span className={styles.overviewLabel}>Correlation</span>
|
||||
<MonoText size="xs">{selectedExchange.correlationId}</MonoText>
|
||||
</div>
|
||||
<div className={styles.overviewRow}>
|
||||
<span className={styles.overviewLabel}>Timestamp</span>
|
||||
<MonoText size="xs">{selectedExchange.timestamp.toISOString()}</MonoText>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Errors */}
|
||||
{totalErrors > 0 && (
|
||||
<div className={styles.panelSection}>
|
||||
<div className={styles.panelSectionTitle}>
|
||||
Errors
|
||||
{totalErrors > 1 && (
|
||||
<Badge label={`+${totalErrors - 1} more`} color="error" variant="outlined" />
|
||||
)}
|
||||
</div>
|
||||
<div className={styles.errorBlock}>
|
||||
<div className={styles.errorClass}>
|
||||
{selectedExchange.errorClass ?? processorErrors[0]?.name}
|
||||
</div>
|
||||
<div className={styles.errorMessage}>
|
||||
{selectedExchange.errorMessage ?? `Failed at processor: ${processorErrors[0]?.name}`}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Route Flow */}
|
||||
<div className={styles.panelSection}>
|
||||
<div className={styles.panelSectionTitle}>Route Flow</div>
|
||||
<RouteFlow nodes={routeNodes} />
|
||||
</div>
|
||||
|
||||
{/* Processor Timeline */}
|
||||
<div className={styles.panelSection}>
|
||||
<div className={styles.panelSectionTitle}>
|
||||
Processor Timeline
|
||||
<span className={styles.panelSectionMeta}>{formatDuration(selectedExchange.durationMs)}</span>
|
||||
</div>
|
||||
<ProcessorTimeline
|
||||
processors={selectedExchange.processors}
|
||||
totalMs={selectedExchange.durationMs}
|
||||
/>
|
||||
</div>
|
||||
</DetailPanel>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3,8 +3,6 @@ import { useParams, useNavigate } from 'react-router-dom'
|
||||
import styles from './ExchangeDetail.module.css'
|
||||
|
||||
// Layout
|
||||
import { AppShell } from '../../design-system/layout/AppShell/AppShell'
|
||||
import { Sidebar } from '../../design-system/layout/Sidebar/Sidebar'
|
||||
import { TopBar } from '../../design-system/layout/TopBar/TopBar'
|
||||
|
||||
// Composites
|
||||
@@ -22,7 +20,7 @@ import { InfoCallout } from '../../design-system/primitives/InfoCallout/InfoCall
|
||||
|
||||
// Mock data
|
||||
import { exchanges } from '../../mocks/exchanges'
|
||||
import { SIDEBAR_APPS, buildRouteToAppMap } from '../../mocks/sidebar'
|
||||
import { buildRouteToAppMap } from '../../mocks/sidebar'
|
||||
|
||||
const ROUTE_TO_APP = buildRouteToAppMap()
|
||||
|
||||
@@ -196,11 +194,7 @@ export function ExchangeDetail() {
|
||||
// Not found state
|
||||
if (!exchange) {
|
||||
return (
|
||||
<AppShell
|
||||
sidebar={
|
||||
<Sidebar apps={SIDEBAR_APPS} />
|
||||
}
|
||||
>
|
||||
<>
|
||||
<TopBar
|
||||
breadcrumb={[
|
||||
{ label: 'Applications', href: '/apps' },
|
||||
@@ -213,7 +207,7 @@ export function ExchangeDetail() {
|
||||
<div className={styles.content}>
|
||||
<InfoCallout variant="warning">Exchange "{id}" not found in mock data.</InfoCallout>
|
||||
</div>
|
||||
</AppShell>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -229,11 +223,7 @@ export function ExchangeDetail() {
|
||||
const isSelectedFailed = selectedProc?.status === 'fail'
|
||||
|
||||
return (
|
||||
<AppShell
|
||||
sidebar={
|
||||
<Sidebar apps={SIDEBAR_APPS} />
|
||||
}
|
||||
>
|
||||
<>
|
||||
{/* Top bar */}
|
||||
<TopBar
|
||||
breadcrumb={[
|
||||
@@ -454,6 +444,6 @@ export function ExchangeDetail() {
|
||||
)}
|
||||
|
||||
</div>
|
||||
</AppShell>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3,8 +3,6 @@ import { useNavigate, useParams } from 'react-router-dom'
|
||||
import styles from './Routes.module.css'
|
||||
|
||||
// Layout
|
||||
import { AppShell } from '../../design-system/layout/AppShell/AppShell'
|
||||
import { Sidebar } from '../../design-system/layout/Sidebar/Sidebar'
|
||||
import { TopBar } from '../../design-system/layout/TopBar/TopBar'
|
||||
|
||||
// Composites
|
||||
@@ -33,7 +31,7 @@ import {
|
||||
type RouteMetricRow,
|
||||
} from '../../mocks/metrics'
|
||||
import { routes } from '../../mocks/routes'
|
||||
import { SIDEBAR_APPS, buildRouteToAppMap } from '../../mocks/sidebar'
|
||||
import { buildRouteToAppMap } from '../../mocks/sidebar'
|
||||
|
||||
const ROUTE_TO_APP = buildRouteToAppMap()
|
||||
|
||||
@@ -410,7 +408,7 @@ export function Routes() {
|
||||
// ── Route detail view ───────────────────────────────────────────────────────
|
||||
if (routeId && appId && routeDef) {
|
||||
return (
|
||||
<AppShell sidebar={<Sidebar apps={SIDEBAR_APPS} />}>
|
||||
<>
|
||||
<TopBar
|
||||
breadcrumb={breadcrumb}
|
||||
environment="PRODUCTION"
|
||||
@@ -448,13 +446,13 @@ export function Routes() {
|
||||
<RouteFlow nodes={routeFlowNodes} />
|
||||
</div>
|
||||
</div>
|
||||
</AppShell>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
// ── Top level / Application level view ──────────────────────────────────────
|
||||
return (
|
||||
<AppShell sidebar={<Sidebar apps={SIDEBAR_APPS} />}>
|
||||
<>
|
||||
<TopBar
|
||||
breadcrumb={breadcrumb}
|
||||
environment="PRODUCTION"
|
||||
@@ -533,6 +531,6 @@ export function Routes() {
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</AppShell>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user