Files
Charon/frontend/src/components/ui/EmptyState.tsx
GitHub Actions 3169b05156 fix: skip incomplete system log viewer tests
- Marked 12 tests as skip pending feature implementation
- Features tracked in GitHub issue #686 (system log viewer feature completion)
- Tests cover sorting by timestamp/level/method/URI/status, pagination controls, filtering by text/level, download functionality
- Unblocks Phase 2 at 91.7% pass rate to proceed to Phase 3 security enforcement validation
- TODO comments in code reference GitHub #686 for feature completion tracking
- Tests skipped: Pagination (3), Search/Filter (2), Download (2), Sorting (1), Log Display (4)
2026-02-09 21:55:55 +00:00

72 lines
1.8 KiB
TypeScript

import * as React from 'react'
import { cn } from '../../utils/cn'
import { Button, type ButtonProps } from './Button'
export interface EmptyStateAction {
label: string
onClick: () => void
variant?: ButtonProps['variant']
}
export interface EmptyStateProps extends React.HTMLAttributes<HTMLDivElement> {
icon?: React.ReactNode
title: string
description: string
action?: EmptyStateAction
secondaryAction?: EmptyStateAction
}
/**
* EmptyState - Empty state pattern component
*
* Features:
* - Centered content with dashed border
* - Icon in muted background circle
* - Primary and secondary action buttons
* - Uses Button component for actions
*/
export function EmptyState({
icon,
title,
description,
action,
secondaryAction,
className,
...props
}: EmptyStateProps) {
return (
<div
className={cn(
'flex flex-col items-center justify-center py-16 px-6 text-center',
'rounded-xl border border-dashed border-border bg-surface-subtle/50',
className
)}
{...props}
>
{icon && (
<div className="mb-4 rounded-full bg-surface-muted p-4 text-content-muted">
{icon}
</div>
)}
<h3 className="text-lg font-semibold text-content-primary">{title}</h3>
<p className="mt-2 max-w-sm text-sm text-content-secondary">
{description}
</p>
{(action || secondaryAction) && (
<div className="mt-6 flex flex-wrap items-center justify-center gap-3">
{action && (
<Button variant={action.variant || 'primary'} onClick={action.onClick}>
{action.label}
</Button>
)}
{secondaryAction && (
<Button variant="ghost" onClick={secondaryAction.onClick}>
{secondaryAction.label}
</Button>
)}
</div>
)}
</div>
)
}