feat: add BreadcrumbProvider and e2e test suite
All checks were successful
Build & Publish / publish (push) Successful in 53s

Add BreadcrumbProvider context so pages can override TopBar breadcrumbs
dynamically. Add Playwright e2e tests for dashboard, agents, routes,
exchanges, and admin pages.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-03-26 11:33:55 +01:00
parent 19303eefad
commit 2a020c1e15
11 changed files with 547 additions and 7 deletions

View File

@@ -7,5 +7,7 @@ export * from './layout'
export * from './providers/ThemeProvider'
export * from './providers/CommandPaletteProvider'
export * from './providers/GlobalFilterProvider'
export { BreadcrumbProvider, useBreadcrumb } from './providers/BreadcrumbProvider'
export type { BreadcrumbItem } from './providers/BreadcrumbProvider'
export * from './utils/hashColor'
export * from './utils/timePresets'

View File

@@ -8,11 +8,8 @@ import { TimeRangeDropdown } from '../../primitives/TimeRangeDropdown/TimeRangeD
import { useGlobalFilters } from '../../providers/GlobalFilterProvider'
import { useCommandPalette } from '../../providers/CommandPaletteProvider'
import { useTheme } from '../../providers/ThemeProvider'
interface BreadcrumbItem {
label: string
href?: string
}
import { useBreadcrumbOverride } from '../../providers/BreadcrumbProvider'
import type { BreadcrumbItem } from '../../providers/BreadcrumbProvider'
interface TopBarProps {
breadcrumb: BreadcrumbItem[]
@@ -39,11 +36,12 @@ export function TopBar({
const globalFilters = useGlobalFilters()
const commandPalette = useCommandPalette()
const { theme, toggleTheme } = useTheme()
const breadcrumbOverride = useBreadcrumbOverride()
return (
<header className={`${styles.topbar} ${className ?? ''}`}>
{/* Left: Breadcrumb */}
<Breadcrumb items={breadcrumb} className={styles.breadcrumb} />
<Breadcrumb items={breadcrumbOverride ?? breadcrumb} className={styles.breadcrumb} />
{/* Search trigger */}
<button

View File

@@ -0,0 +1,44 @@
import { createContext, useContext, useState, useEffect } from 'react'
import type { ReactNode } from 'react'
export interface BreadcrumbItem {
label: string
href?: string
}
interface BreadcrumbContextValue {
override: BreadcrumbItem[] | null
setOverride: (items: BreadcrumbItem[] | null) => void
}
const BreadcrumbContext = createContext<BreadcrumbContextValue>({
override: null,
setOverride: () => {},
})
export function BreadcrumbProvider({ children }: { children: ReactNode }) {
const [override, setOverride] = useState<BreadcrumbItem[] | null>(null)
return (
<BreadcrumbContext.Provider value={{ override, setOverride }}>
{children}
</BreadcrumbContext.Provider>
)
}
/**
* Override the TopBar breadcrumb with page-specific semantic items.
* Pass `null` to clear (or let unmount handle it).
* Callers should `useMemo` the items array to avoid unnecessary re-renders.
*/
export function useBreadcrumb(items: BreadcrumbItem[] | null) {
const { setOverride } = useContext(BreadcrumbContext)
useEffect(() => {
setOverride(items)
return () => setOverride(null)
}, [items, setOverride])
}
/** Internal — used by TopBar to read the current override. */
export function useBreadcrumbOverride(): BreadcrumbItem[] | null {
return useContext(BreadcrumbContext).override
}