diff --git a/package-lock.json b/package-lock.json index 837ddd2..171fe21 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "@cameleer/design-system", "version": "0.1.6", "dependencies": { + "lucide-react": "^1.7.0", "react": "^19.0.0", "react-dom": "^19.0.0", "react-router-dom": "^7.0.0" @@ -2714,6 +2715,15 @@ "yallist": "^3.0.2" } }, + "node_modules/lucide-react": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.7.0.tgz", + "integrity": "sha512-yI7BeItCLZJTXikmK4KNUGCKoGzSvbKlfCvw44bU4fXAL6v3gYS4uHD1jzsLkfwODYwI6Drw5Tu9Z5ulDe0TSg==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/lz-string": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", diff --git a/package.json b/package.json index 6c1a74b..172ece0 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "test:e2e": "playwright test" }, "dependencies": { + "lucide-react": "^1.7.0", "react": "^19.0.0", "react-dom": "^19.0.0", "react-router-dom": "^7.0.0" diff --git a/src/design-system/composites/AlertDialog/AlertDialog.test.tsx b/src/design-system/composites/AlertDialog/AlertDialog.test.tsx index 92d6881..41eb921 100644 --- a/src/design-system/composites/AlertDialog/AlertDialog.test.tsx +++ b/src/design-system/composites/AlertDialog/AlertDialog.test.tsx @@ -78,17 +78,16 @@ describe('AlertDialog', () => { it('renders danger variant icon', () => { render() - // Icon area should be present (aria-hidden) - expect(screen.getByText('✕')).toBeInTheDocument() + expect(document.querySelector('[aria-hidden="true"] svg')).toBeInTheDocument() }) it('renders warning variant icon', () => { render() - expect(screen.getByText('⚠')).toBeInTheDocument() + expect(document.querySelector('[aria-hidden="true"] svg')).toBeInTheDocument() }) it('renders info variant icon', () => { render() - expect(screen.getByText('ℹ')).toBeInTheDocument() + expect(document.querySelector('[aria-hidden="true"] svg')).toBeInTheDocument() }) }) diff --git a/src/design-system/composites/AlertDialog/AlertDialog.tsx b/src/design-system/composites/AlertDialog/AlertDialog.tsx index 3b3335c..e700a0e 100644 --- a/src/design-system/composites/AlertDialog/AlertDialog.tsx +++ b/src/design-system/composites/AlertDialog/AlertDialog.tsx @@ -1,4 +1,5 @@ -import { useEffect, useRef } from 'react' +import React, { useEffect, useRef } from 'react' +import { XCircle, AlertTriangle, Info } from 'lucide-react' import { Modal } from '../Modal/Modal' import { Button } from '../../primitives/Button/Button' import styles from './AlertDialog.module.css' @@ -16,10 +17,10 @@ interface AlertDialogProps { className?: string } -const variantIcons: Record, string> = { - danger: '✕', - warning: '⚠', - info: 'ℹ', +const variantIcons: Record, React.ReactNode> = { + danger: , + warning: , + info: , } export function AlertDialog({ diff --git a/src/design-system/composites/CommandPalette/CommandPalette.tsx b/src/design-system/composites/CommandPalette/CommandPalette.tsx index 899d62e..b2c0f66 100644 --- a/src/design-system/composites/CommandPalette/CommandPalette.tsx +++ b/src/design-system/composites/CommandPalette/CommandPalette.tsx @@ -1,5 +1,6 @@ import { useState, useEffect, useRef, useMemo, type ReactNode } from 'react' import { createPortal } from 'react-dom' +import { Search, X, ChevronUp, ChevronDown } from 'lucide-react' import styles from './CommandPalette.module.css' import { SectionHeader } from '../../primitives/SectionHeader/SectionHeader' import { CodeBlock } from '../../primitives/CodeBlock/CodeBlock' @@ -189,7 +190,7 @@ export function CommandPalette({ open, onClose, onSelect, data, onOpen, onQueryC > {/* Search input area */}
- + {scopeFilters.map((sf, i) => ( {sf.field}: @@ -199,7 +200,7 @@ export function CommandPalette({ open, onClose, onSelect, data, onOpen, onQueryC onClick={() => removeScopeFilter(i)} aria-label={`Remove filter ${sf.field}:${sf.value}`} > - × + ))} @@ -323,7 +324,7 @@ export function CommandPalette({ open, onClose, onSelect, data, onOpen, onQueryC aria-expanded={isExpanded} aria-label="Toggle detail" > - {isExpanded ? '▲' : '▼'} + {isExpanded ? : } )}
diff --git a/src/design-system/composites/EventFeed/EventFeed.tsx b/src/design-system/composites/EventFeed/EventFeed.tsx index c55fba9..f85a6e7 100644 --- a/src/design-system/composites/EventFeed/EventFeed.tsx +++ b/src/design-system/composites/EventFeed/EventFeed.tsx @@ -1,4 +1,5 @@ import { type ReactNode, useEffect, useRef, useState, useCallback } from 'react' +import { X as XIcon, AlertTriangle, Play, Loader } from 'lucide-react' import styles from './EventFeed.module.css' import { ButtonGroup } from '../../primitives/ButtonGroup/ButtonGroup' import type { ButtonGroupItem } from '../../primitives/ButtonGroup/ButtonGroup' @@ -47,11 +48,11 @@ function getSearchableText(event: FeedEvent): string { return '' } -const DEFAULT_ICONS: Record = { - error: '\u2715', // ✕ - warning: '\u26A0', // ⚠ - success: '\u25B6', // ▶ - running: '\u2699', // ⚙ +const DEFAULT_ICONS: Record = { + error: , + warning: , + success: , + running: , } const SEVERITY_COLORS: Record = { @@ -136,7 +137,7 @@ export function EventFeed({ events, maxItems = 200, className }: EventFeedProps) onClick={() => setSearch('')} aria-label="Clear search" > - × + )} diff --git a/src/design-system/composites/FilterBar/FilterBar.tsx b/src/design-system/composites/FilterBar/FilterBar.tsx index 6baeb65..b3a2030 100644 --- a/src/design-system/composites/FilterBar/FilterBar.tsx +++ b/src/design-system/composites/FilterBar/FilterBar.tsx @@ -1,4 +1,5 @@ import { useState, type ChangeEvent } from 'react' +import { Search } from 'lucide-react' import styles from './FilterBar.module.css' import { Input } from '../../primitives/Input/Input' import { FilterPill } from '../../primitives/FilterPill/FilterPill' @@ -77,12 +78,7 @@ export function FilterBar({ if (onSearchChange) onSearchChange('') else setInternalSearch('') } : undefined} - icon={ - - - - - } + icon={} /> diff --git a/src/design-system/composites/KpiStrip/KpiStrip.tsx b/src/design-system/composites/KpiStrip/KpiStrip.tsx index 76fd3ae..de46fdb 100644 --- a/src/design-system/composites/KpiStrip/KpiStrip.tsx +++ b/src/design-system/composites/KpiStrip/KpiStrip.tsx @@ -1,11 +1,11 @@ import styles from './KpiStrip.module.css' import { Sparkline } from '../../primitives/Sparkline/Sparkline' -import type { CSSProperties } from 'react' +import type { CSSProperties, ReactNode } from 'react' export interface KpiItem { label: string value: string | number - trend?: { label: string; variant?: 'success' | 'warning' | 'error' | 'muted' } + trend?: { label: ReactNode; variant?: 'success' | 'warning' | 'error' | 'muted' } subtitle?: string sparkline?: number[] borderColor?: string diff --git a/src/design-system/composites/ProcessorTimeline/ProcessorTimeline.tsx b/src/design-system/composites/ProcessorTimeline/ProcessorTimeline.tsx index 1a147b9..22810ce 100644 --- a/src/design-system/composites/ProcessorTimeline/ProcessorTimeline.tsx +++ b/src/design-system/composites/ProcessorTimeline/ProcessorTimeline.tsx @@ -1,4 +1,5 @@ import type { ReactNode } from 'react' +import { EllipsisVertical } from 'lucide-react' import styles from './ProcessorTimeline.module.css' import { Dropdown } from '../Dropdown/Dropdown' import type { NodeBadge } from '../RouteFlow/RouteFlow' @@ -124,7 +125,7 @@ export function ProcessorTimeline({ aria-label={`Actions for ${proc.name}`} type="button" > - ⋮ + } items={resolvedActions} diff --git a/src/design-system/composites/RouteFlow/RouteFlow.tsx b/src/design-system/composites/RouteFlow/RouteFlow.tsx index cc39031..cbd9ce1 100644 --- a/src/design-system/composites/RouteFlow/RouteFlow.tsx +++ b/src/design-system/composites/RouteFlow/RouteFlow.tsx @@ -1,4 +1,5 @@ import type { ReactNode } from 'react' +import { Play, Cog, Square, Diamond, AlertTriangle, EllipsisVertical } from 'lucide-react' import styles from './RouteFlow.module.css' import { Dropdown } from '../Dropdown/Dropdown' @@ -55,12 +56,12 @@ function durationClass(ms: number, status: string): string { return styles.durBreach } -const TYPE_ICONS: Record = { - 'from': '\u25B6', - 'process': '\u2699', - 'to': '\u25A2', - 'choice': '\u25C6', - 'error-handler': '\u26A0', +const TYPE_ICONS: Record = { + 'from': , + 'process': , + 'to': , + 'choice': , + 'error-handler': , } const ICON_CLASSES: Record = { @@ -100,7 +101,7 @@ function renderActionTrigger( aria-label={`Actions for ${node.name}`} type="button" > - ⋮ + } items={resolvedActions} @@ -166,7 +167,7 @@ function renderNodeChain( ) : null}
- {TYPE_ICONS[node.type] ?? '\u25A2'} + {TYPE_ICONS[node.type] ?? }
{node.type}
@@ -260,7 +261,7 @@ export function RouteFlow({ nodes, flows, onNodeClick, selectedIndex, actions, g ) : null}
- {TYPE_ICONS[node.type] ?? '\u25A2'} + {TYPE_ICONS[node.type] ?? }
{node.type}
diff --git a/src/design-system/composites/Toast/Toast.test.tsx b/src/design-system/composites/Toast/Toast.test.tsx index 430dca9..e2a9947 100644 --- a/src/design-system/composites/Toast/Toast.test.tsx +++ b/src/design-system/composites/Toast/Toast.test.tsx @@ -89,7 +89,7 @@ describe('Toast', () => { act(() => { getApi().toast({ title: 'Info', variant: 'info' }) }) - expect(screen.getByText('ℹ')).toBeInTheDocument() + expect(screen.getByTestId('toast').querySelector('[aria-hidden="true"] svg')).toBeInTheDocument() }) it('shows correct icon for success variant', () => { @@ -97,7 +97,7 @@ describe('Toast', () => { act(() => { getApi().toast({ title: 'OK', variant: 'success' }) }) - expect(screen.getByText('✓')).toBeInTheDocument() + expect(screen.getByTestId('toast').querySelector('[aria-hidden="true"] svg')).toBeInTheDocument() }) it('shows correct icon for warning variant', () => { @@ -105,7 +105,7 @@ describe('Toast', () => { act(() => { getApi().toast({ title: 'Warn', variant: 'warning' }) }) - expect(screen.getByText('⚠')).toBeInTheDocument() + expect(screen.getByTestId('toast').querySelector('[aria-hidden="true"] svg')).toBeInTheDocument() }) it('shows correct icon for error variant', () => { @@ -113,7 +113,7 @@ describe('Toast', () => { act(() => { getApi().toast({ title: 'Err', variant: 'error' }) }) - expect(screen.getByText('✕')).toBeInTheDocument() + expect(screen.getByTestId('toast').querySelector('[aria-hidden="true"] svg')).toBeInTheDocument() }) it('dismisses toast when close button is clicked', () => { diff --git a/src/design-system/composites/Toast/Toast.tsx b/src/design-system/composites/Toast/Toast.tsx index c5220a3..e540b9c 100644 --- a/src/design-system/composites/Toast/Toast.tsx +++ b/src/design-system/composites/Toast/Toast.tsx @@ -8,6 +8,7 @@ import { type ReactNode, } from 'react' import { createPortal } from 'react-dom' +import { Info, CheckCircle, AlertTriangle, XCircle, X } from 'lucide-react' import styles from './Toast.module.css' // ── Types ────────────────────────────────────────────────────────────────── @@ -39,11 +40,11 @@ const MAX_TOASTS = 5 const DEFAULT_DURATION = 5000 const EXIT_ANIMATION_MS = 300 -const ICONS: Record = { - info: 'ℹ', - success: '✓', - warning: '⚠', - error: '✕', +const ICONS: Record = { + info: , + success: , + warning: , + error: , } // ── Context ──────────────────────────────────────────────────────────────── @@ -183,7 +184,7 @@ function ToastItemComponent({ toast, onDismiss }: ToastItemComponentProps) { aria-label="Dismiss notification" type="button" > - × +
) diff --git a/src/design-system/layout/Sidebar/Sidebar.tsx b/src/design-system/layout/Sidebar/Sidebar.tsx index 74d34e8..c9458ef 100644 --- a/src/design-system/layout/Sidebar/Sidebar.tsx +++ b/src/design-system/layout/Sidebar/Sidebar.tsx @@ -1,5 +1,6 @@ import { useState, useEffect, useMemo } from 'react' import { useNavigate, useLocation } from 'react-router-dom' +import { Search, X, ChevronRight, ChevronDown, Settings, FileText } from 'lucide-react' import styles from './Sidebar.module.css' import camelLogoUrl from '../../../assets/camel-logo.svg' import { SidebarTree, type SidebarTreeNode } from './SidebarTree' @@ -55,7 +56,7 @@ function buildAppTreeNodes(apps: SidebarApp[]): SidebarTreeNode[] { id: `route:${app.id}:${route.id}`, starKey: `${app.id}:${route.id}`, label: route.name, - icon: , + icon: , badge: formatCount(route.exchangeCount), path: `/apps/${app.id}/${route.id}`, starrable: true, @@ -78,7 +79,7 @@ function buildRouteTreeNodes(apps: SidebarApp[]): SidebarTreeNode[] { id: `routestat:${app.id}:${route.id}`, starKey: `routes:${app.id}:${route.id}`, label: route.name, - icon: , + icon: , badge: formatCount(route.exchangeCount), path: `/routes/${app.id}/${route.id}`, starrable: true, @@ -235,10 +236,7 @@ function StarredGroup({ tabIndex={-1} aria-label={`Remove ${item.label} from starred`} > - - - - +
))} @@ -344,10 +342,7 @@ export function Sidebar({ apps, className }: SidebarProps) {
setSearch('')} aria-label="Clear search" > - × + )}
@@ -382,7 +377,7 @@ export function Sidebar({ apps, className }: SidebarProps) { aria-expanded={!appsCollapsed} aria-label={appsCollapsed ? 'Expand Applications' : 'Collapse Applications'} > - {appsCollapsed ? '▸' : '▾'} + {appsCollapsed ? : } - {agentsCollapsed ? '▸' : '▾'} + {agentsCollapsed ? : } - {routesCollapsed ? '▸' : '▾'} + {routesCollapsed ? : } { if (e.key === 'Enter' || e.key === ' ') navigate('/admin') }} > - +
Admin
@@ -551,7 +546,7 @@ export function Sidebar({ apps, className }: SidebarProps) { tabIndex={0} onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') navigate('/api-docs') }} > - +
API Docs
diff --git a/src/design-system/layout/Sidebar/SidebarTree.tsx b/src/design-system/layout/Sidebar/SidebarTree.tsx index 9cf41f3..9be0139 100644 --- a/src/design-system/layout/Sidebar/SidebarTree.tsx +++ b/src/design-system/layout/Sidebar/SidebarTree.tsx @@ -9,6 +9,7 @@ import { type MouseEvent, } from 'react' import { useNavigate } from 'react-router-dom' +import { Star, ChevronRight, ChevronDown } from 'lucide-react' import styles from './Sidebar.module.css' // ── Types ──────────────────────────────────────────────────────────────────── @@ -35,22 +36,14 @@ export interface SidebarTreeProps { autoRevealPath?: string | null // when set, auto-expand the parent of the matching node } -// ── Star icon SVGs ─────────────────────────────────────────────────────────── +// ── Star icons ─────────────────────────────────────────────────────────────── function StarOutline() { - return ( - - - - ) + return } function StarFilled() { - return ( - - - - ) + return } // ── Persistent expand state ────────────────────────────────────────────────── @@ -395,7 +388,7 @@ function SidebarTreeRow({ tabIndex={-1} aria-label={isExpanded ? 'Collapse' : 'Expand'} > - {isExpanded ? '▾' : '▸'} + {isExpanded ? : } ) : null}
diff --git a/src/design-system/layout/TopBar/TopBar.tsx b/src/design-system/layout/TopBar/TopBar.tsx index 2b5b161..490314c 100644 --- a/src/design-system/layout/TopBar/TopBar.tsx +++ b/src/design-system/layout/TopBar/TopBar.tsx @@ -1,3 +1,4 @@ +import { Search, Moon, Sun, Power } from 'lucide-react' import styles from './TopBar.module.css' import { Breadcrumb } from '../../composites/Breadcrumb/Breadcrumb' import { Dropdown } from '../../composites/Dropdown/Dropdown' @@ -51,10 +52,7 @@ export function TopBar({ aria-label="Open search" > Search... ⌘K Ctrl+K @@ -101,7 +99,7 @@ export function TopBar({ aria-label={`Switch to ${theme === 'light' ? 'dark' : 'light'} mode`} title={`Switch to ${theme === 'light' ? 'dark' : 'light'} mode`} > - {theme === 'light' ? '\u263E' : '\u2600'} + {theme === 'light' ? : } {environment && ( {environment} @@ -115,7 +113,7 @@ export function TopBar({
} items={[ - { label: 'Logout', icon: '\u23FB', onClick: onLogout }, + { label: 'Logout', icon: , onClick: onLogout }, ]} /> )} diff --git a/src/design-system/primitives/Alert/Alert.test.tsx b/src/design-system/primitives/Alert/Alert.test.tsx index 50d72a1..44b4d50 100644 --- a/src/design-system/primitives/Alert/Alert.test.tsx +++ b/src/design-system/primitives/Alert/Alert.test.tsx @@ -46,24 +46,23 @@ describe('Alert', () => { }) it('shows default icon for each variant', () => { - const { rerender } = render(msg) - expect(screen.getByText('ℹ')).toBeInTheDocument() + const { container, rerender } = render(msg) + // Each variant should render an SVG icon in the icon slot + expect(container.querySelector('[aria-hidden="true"] svg')).toBeInTheDocument() rerender(msg) - expect(screen.getByText('✓')).toBeInTheDocument() + expect(container.querySelector('[aria-hidden="true"] svg')).toBeInTheDocument() rerender(msg) - expect(screen.getByText('⚠')).toBeInTheDocument() + expect(container.querySelector('[aria-hidden="true"] svg')).toBeInTheDocument() rerender(msg) - expect(screen.getByText('✕')).toBeInTheDocument() + expect(container.querySelector('[aria-hidden="true"] svg')).toBeInTheDocument() }) it('renders a custom icon when provided', () => { - render(★}>Custom icon alert) - expect(screen.getByText('★')).toBeInTheDocument() - // Default icon should not appear - expect(screen.queryByText('ℹ')).not.toBeInTheDocument() + render(★}>Custom icon alert) + expect(screen.getByTestId('custom-icon')).toBeInTheDocument() }) it('does not show dismiss button when dismissible is false', () => { diff --git a/src/design-system/primitives/Alert/Alert.tsx b/src/design-system/primitives/Alert/Alert.tsx index e6b637f..538a69c 100644 --- a/src/design-system/primitives/Alert/Alert.tsx +++ b/src/design-system/primitives/Alert/Alert.tsx @@ -1,4 +1,5 @@ import { ReactNode } from 'react' +import { Info, CheckCircle, AlertTriangle, XCircle, X } from 'lucide-react' import styles from './Alert.module.css' type AlertVariant = 'info' | 'success' | 'warning' | 'error' @@ -13,11 +14,11 @@ interface AlertProps { className?: string } -const DEFAULT_ICONS: Record = { - info: 'ℹ', - success: '✓', - warning: '⚠', - error: '✕', +const DEFAULT_ICONS: Record = { + info: , + success: , + warning: , + error: , } const ARIA_ROLES: Record = { @@ -61,7 +62,7 @@ export function Alert({ aria-label="Dismiss alert" type="button" > - × + )} diff --git a/src/design-system/primitives/Input/Input.tsx b/src/design-system/primitives/Input/Input.tsx index dc98793..be2800c 100644 --- a/src/design-system/primitives/Input/Input.tsx +++ b/src/design-system/primitives/Input/Input.tsx @@ -1,5 +1,6 @@ import styles from './Input.module.css' import { forwardRef, type InputHTMLAttributes, type ReactNode } from 'react' +import { X } from 'lucide-react' interface InputProps extends InputHTMLAttributes { icon?: ReactNode @@ -25,7 +26,7 @@ export const Input = forwardRef( onClick={onClear} aria-label="Clear search" > - × + )} diff --git a/src/pages/AgentHealth/AgentHealth.tsx b/src/pages/AgentHealth/AgentHealth.tsx index 54e9b03..1e0bf81 100644 --- a/src/pages/AgentHealth/AgentHealth.tsx +++ b/src/pages/AgentHealth/AgentHealth.tsx @@ -1,5 +1,6 @@ import { useState, useMemo } from 'react' import { useParams, Link } from 'react-router-dom' +import { ChevronRight } from 'lucide-react' import styles from './AgentHealth.module.css' // Layout @@ -389,7 +390,7 @@ export function AgentHealth() { {scope.level !== 'all' && ( <> All Agents - + {scope.appId} )} diff --git a/src/pages/AgentInstance/AgentInstance.tsx b/src/pages/AgentInstance/AgentInstance.tsx index bdcd538..002557e 100644 --- a/src/pages/AgentInstance/AgentInstance.tsx +++ b/src/pages/AgentInstance/AgentInstance.tsx @@ -1,5 +1,6 @@ import { useMemo } from 'react' import { useParams, Link } from 'react-router-dom' +import { ChevronRight } from 'lucide-react' import styles from './AgentInstance.module.css' // Layout @@ -177,9 +178,9 @@ export function AgentInstance() { {/* Scope trail + badges */}
All Agents - + {appId} - + {agent.name} diff --git a/src/pages/Dashboard/Dashboard.tsx b/src/pages/Dashboard/Dashboard.tsx index 97ea2e4..3f71f7f 100644 --- a/src/pages/Dashboard/Dashboard.tsx +++ b/src/pages/Dashboard/Dashboard.tsx @@ -1,5 +1,6 @@ -import { useState, useMemo } from 'react' +import React, { useState, useMemo } from 'react' import { useParams, useNavigate } from 'react-router-dom' +import { TrendingUp, TrendingDown, ArrowRight, ExternalLink, AlertTriangle } from 'lucide-react' import styles from './Dashboard.module.css' // Layout @@ -43,10 +44,10 @@ const ACCENT_TO_COLOR: Record = { warning: 'var(--warning)', } -const TREND_ICONS: Record = { - up: '\u2191', - down: '\u2193', - neutral: '\u2192', +const TREND_ICONS: Record = { + up: , + down: , + neutral: , } function sentimentToVariant(sentiment: KpiMetric['trendSentiment']): 'success' | 'error' | 'muted' { @@ -60,7 +61,7 @@ function sentimentToVariant(sentiment: KpiMetric['trendSentiment']): 'success' | const kpiItems: KpiItem[] = kpiMetrics.map((m) => ({ label: m.label, value: m.unit ? `${m.value} ${m.unit}` : m.value, - trend: { label: `${TREND_ICONS[m.trend]} ${m.trendValue}`, variant: sentimentToVariant(m.trendSentiment) }, + trend: { label: <>{TREND_ICONS[m.trend]} {m.trendValue}, variant: sentimentToVariant(m.trendSentiment) }, subtitle: m.detail, sparkline: m.sparkline, borderColor: ACCENT_TO_COLOR[m.accent], @@ -206,7 +207,7 @@ export function Dashboard() { navigate(`/exchanges/${row.id}`) }} > - ↗ + ), } @@ -303,7 +304,7 @@ export function Dashboard() { className={styles.openDetailLink} onClick={() => navigate(`/exchanges/${selectedExchange.id}`)} > - Open full details → + Open full details
@@ -428,7 +429,7 @@ export function Dashboard() { expandedContent={(row) => row.errorMessage ? (
- +
{row.errorMessage}
Click to view full stack trace
diff --git a/src/pages/Inventory/sections/CompositesSection.tsx b/src/pages/Inventory/sections/CompositesSection.tsx index ac5abfa..49bbf64 100644 --- a/src/pages/Inventory/sections/CompositesSection.tsx +++ b/src/pages/Inventory/sections/CompositesSection.tsx @@ -1,4 +1,5 @@ import { useState } from 'react' +import { Hexagon, ArrowRight, Diamond, Eye, Pencil, RotateCcw, Trash2, ChevronDown } from 'lucide-react' import styles from './CompositesSection.module.css' import { Accordion, @@ -157,25 +158,25 @@ const TREE_NODES = [ { id: 'app1', label: 'cameleer-prod', - icon: '⬡', + icon: , children: [ { id: 'route1', label: 'order-ingest', - icon: '→', + icon: , children: [ - { id: 'proc1', label: 'ValidateOrder', icon: '◈', meta: '12ms' }, - { id: 'proc2', label: 'EnrichPayload', icon: '◈', meta: '8ms' }, - { id: 'proc3', label: 'RouteToQueue', icon: '◈', meta: '3ms' }, + { id: 'proc1', label: 'ValidateOrder', icon: , meta: '12ms' }, + { id: 'proc2', label: 'EnrichPayload', icon: , meta: '8ms' }, + { id: 'proc3', label: 'RouteToQueue', icon: , meta: '3ms' }, ], }, { id: 'route2', label: 'payment-validate', - icon: '→', + icon: , children: [ - { id: 'proc4', label: 'TokenizeCard', icon: '◈', meta: '22ms' }, - { id: 'proc5', label: 'AuthorizePayment', icon: '◈', meta: '45ms' }, + { id: 'proc4', label: 'TokenizeCard', icon: , meta: '22ms' }, + { id: 'proc5', label: 'AuthorizePayment', icon: , meta: '45ms' }, ], }, ], @@ -505,13 +506,13 @@ export function CompositesSection() { description="Click-triggered dropdown menu with icons, dividers, and disabled items." > Actions ▾} + trigger={} items={[ - { label: 'View details', icon: '👁', onClick: () => undefined }, - { label: 'Edit route', icon: '✏', onClick: () => undefined }, + { label: 'View details', icon: , onClick: () => undefined }, + { label: 'Edit route', icon: , onClick: () => undefined }, { divider: true, label: '' }, - { label: 'Restart', icon: '↺', onClick: () => undefined }, - { label: 'Delete', icon: '✕', onClick: () => undefined, disabled: true }, + { label: 'Restart', icon: , onClick: () => undefined }, + { label: 'Delete', icon: , onClick: () => undefined, disabled: true }, ]} /> diff --git a/src/pages/Inventory/sections/PrimitivesSection.tsx b/src/pages/Inventory/sections/PrimitivesSection.tsx index 3362bb6..53766b3 100644 --- a/src/pages/Inventory/sections/PrimitivesSection.tsx +++ b/src/pages/Inventory/sections/PrimitivesSection.tsx @@ -1,4 +1,5 @@ import { useState } from 'react' +import { Search } from 'lucide-react' import styles from './PrimitivesSection.module.css' import { Alert, @@ -358,7 +359,7 @@ export function PrimitivesSection() { description="Text input with optional leading icon and placeholder." > - + } placeholder="With icon" /> {/* 15b. InlineEdit */} diff --git a/src/pages/RouteDetail/RouteDetail.tsx b/src/pages/RouteDetail/RouteDetail.tsx index e743568..7c11239 100644 --- a/src/pages/RouteDetail/RouteDetail.tsx +++ b/src/pages/RouteDetail/RouteDetail.tsx @@ -1,5 +1,6 @@ import { useMemo } from 'react' import { useParams, useNavigate } from 'react-router-dom' +import { AlertTriangle } from 'lucide-react' import styles from './RouteDetail.module.css' // Layout @@ -337,7 +338,7 @@ export function RouteDetail() { expandedContent={(row) => row.errorMessage ? (
- +
{row.errorClass}
{row.errorMessage}