diff --git a/package.json b/package.json
index a3c1c45..87f2e33 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@cameleer/design-system",
- "version": "0.1.48",
+ "version": "0.1.49",
"type": "module",
"main": "./dist/index.es.js",
"module": "./dist/index.es.js",
diff --git a/src/design-system/composites/LogViewer/LogViewer.module.css b/src/design-system/composites/LogViewer/LogViewer.module.css
index c1eb349..ae1d8ef 100644
--- a/src/design-system/composites/LogViewer/LogViewer.module.css
+++ b/src/design-system/composites/LogViewer/LogViewer.module.css
@@ -61,6 +61,38 @@
background: color-mix(in srgb, var(--text-faint) 8%, transparent);
}
+.sourceBadge {
+ flex-shrink: 0;
+ font-size: 9px;
+ font-family: var(--font-mono);
+ padding: 1px 6px;
+ border-radius: 3px;
+ line-height: 1.5;
+ white-space: nowrap;
+ min-width: 48px;
+ text-align: center;
+}
+
+.sourceContainer {
+ color: var(--text-muted);
+ background: color-mix(in srgb, var(--text-muted) 10%, transparent);
+}
+
+.sourceApp {
+ color: var(--running);
+ background: color-mix(in srgb, var(--running) 10%, transparent);
+}
+
+.sourceAgent {
+ color: var(--warning);
+ background: color-mix(in srgb, var(--warning) 10%, transparent);
+}
+
+.sourceDefault {
+ color: var(--text-muted);
+ background: color-mix(in srgb, var(--text-muted) 8%, transparent);
+}
+
.message {
font-size: 12px;
font-family: var(--font-mono);
diff --git a/src/design-system/composites/LogViewer/LogViewer.test.tsx b/src/design-system/composites/LogViewer/LogViewer.test.tsx
index 4aa25c5..5ed058e 100644
--- a/src/design-system/composites/LogViewer/LogViewer.test.tsx
+++ b/src/design-system/composites/LogViewer/LogViewer.test.tsx
@@ -3,9 +3,9 @@ import { render, screen } from '@testing-library/react'
import { LogViewer, type LogEntry } from './LogViewer'
const entries: LogEntry[] = [
- { timestamp: '2024-01-15T10:30:00Z', level: 'info', message: 'Server started' },
- { timestamp: '2024-01-15T10:30:05Z', level: 'warn', message: 'High memory usage' },
- { timestamp: '2024-01-15T10:30:10Z', level: 'error', message: 'Connection failed' },
+ { timestamp: '2024-01-15T10:30:00Z', level: 'info', message: 'Server started', source: 'app' },
+ { timestamp: '2024-01-15T10:30:05Z', level: 'warn', message: 'High memory usage', source: 'container' },
+ { timestamp: '2024-01-15T10:30:10Z', level: 'error', message: 'Connection failed', source: 'agent' },
{ timestamp: '2024-01-15T10:30:15Z', level: 'debug', message: 'Query executed in 3ms' },
{ timestamp: '2024-01-15T10:30:20Z', level: 'trace', message: 'Entering handleRequest()' },
]
@@ -52,6 +52,23 @@ describe('LogViewer', () => {
expect(el.classList.contains('custom-class')).toBe(true)
})
+ it('renders source badges when source is provided', () => {
+ render()
+ expect(screen.getByText('app')).toBeInTheDocument()
+ expect(screen.getByText('container')).toBeInTheDocument()
+ expect(screen.getByText('agent')).toBeInTheDocument()
+ })
+
+ it('omits source badge when source is not provided', () => {
+ const noSourceEntries: LogEntry[] = [
+ { timestamp: '2024-01-15T10:30:00Z', level: 'info', message: 'No source here' },
+ ]
+ render()
+ expect(screen.getByText('No source here')).toBeInTheDocument()
+ expect(screen.queryByText('app')).not.toBeInTheDocument()
+ expect(screen.queryByText('container')).not.toBeInTheDocument()
+ })
+
it('has role="log" for accessibility', () => {
render()
expect(screen.getByRole('log')).toBeInTheDocument()
diff --git a/src/design-system/composites/LogViewer/LogViewer.tsx b/src/design-system/composites/LogViewer/LogViewer.tsx
index 6400fff..0059036 100644
--- a/src/design-system/composites/LogViewer/LogViewer.tsx
+++ b/src/design-system/composites/LogViewer/LogViewer.tsx
@@ -5,6 +5,7 @@ export interface LogEntry {
timestamp: string
level: 'info' | 'warn' | 'error' | 'debug' | 'trace'
message: string
+ source?: string
}
export interface LogViewerProps {
@@ -21,6 +22,12 @@ const LEVEL_CLASS: Record = {
trace: styles.levelTrace,
}
+const SOURCE_CLASS: Record = {
+ container: styles.sourceContainer,
+ app: styles.sourceApp,
+ agent: styles.sourceAgent,
+}
+
function formatTime(iso: string): string {
try {
return new Date(iso).toLocaleTimeString('en-GB', {
@@ -67,6 +74,11 @@ export function LogViewer({ entries, maxHeight = 400, className }: LogViewerProp
{entry.level.toUpperCase()}
+ {entry.source && (
+
+ {entry.source}
+
+ )}
{entry.message}
))}