diff --git a/ui/src/components/AlertStateChip.test.tsx b/ui/src/components/AlertStateChip.test.tsx new file mode 100644 index 00000000..dbdc0785 --- /dev/null +++ b/ui/src/components/AlertStateChip.test.tsx @@ -0,0 +1,25 @@ +import { describe, it, expect } from 'vitest'; +import { render, screen } from '@testing-library/react'; +import { ThemeProvider } from '@cameleer/design-system'; +import { AlertStateChip } from './AlertStateChip'; + +function renderWithTheme(ui: React.ReactElement) { + return render({ui}); +} + +describe('AlertStateChip', () => { + it.each([ + ['PENDING', /pending/i], + ['FIRING', /firing/i], + ['ACKNOWLEDGED', /acknowledged/i], + ['RESOLVED', /resolved/i], + ] as const)('renders %s label', (state, pattern) => { + renderWithTheme(); + expect(screen.getByText(pattern)).toBeInTheDocument(); + }); + + it('shows silenced suffix when silenced=true', () => { + renderWithTheme(); + expect(screen.getByText(/silenced/i)).toBeInTheDocument(); + }); +}); diff --git a/ui/src/components/AlertStateChip.tsx b/ui/src/components/AlertStateChip.tsx new file mode 100644 index 00000000..a81548f0 --- /dev/null +++ b/ui/src/components/AlertStateChip.tsx @@ -0,0 +1,27 @@ +import { Badge } from '@cameleer/design-system'; +import type { AlertDto } from '../api/queries/alerts'; + +type State = NonNullable; + +const LABELS: Record = { + PENDING: 'Pending', + FIRING: 'Firing', + ACKNOWLEDGED: 'Acknowledged', + RESOLVED: 'Resolved', +}; + +const COLORS: Record = { + PENDING: 'warning', + FIRING: 'error', + ACKNOWLEDGED: 'warning', + RESOLVED: 'success', +}; + +export function AlertStateChip({ state, silenced }: { state: State; silenced?: boolean }) { + return ( + + + {silenced && } + + ); +} diff --git a/ui/src/components/SeverityBadge.test.tsx b/ui/src/components/SeverityBadge.test.tsx new file mode 100644 index 00000000..a685fe12 --- /dev/null +++ b/ui/src/components/SeverityBadge.test.tsx @@ -0,0 +1,19 @@ +import { describe, it, expect } from 'vitest'; +import { render, screen } from '@testing-library/react'; +import { ThemeProvider } from '@cameleer/design-system'; +import { SeverityBadge } from './SeverityBadge'; + +function renderWithTheme(ui: React.ReactElement) { + return render({ui}); +} + +describe('SeverityBadge', () => { + it.each([ + ['CRITICAL', /critical/i], + ['WARNING', /warning/i], + ['INFO', /info/i], + ] as const)('renders %s', (severity, pattern) => { + renderWithTheme(); + expect(screen.getByText(pattern)).toBeInTheDocument(); + }); +}); diff --git a/ui/src/components/SeverityBadge.tsx b/ui/src/components/SeverityBadge.tsx new file mode 100644 index 00000000..b4d712ac --- /dev/null +++ b/ui/src/components/SeverityBadge.tsx @@ -0,0 +1,20 @@ +import { Badge } from '@cameleer/design-system'; +import type { AlertDto } from '../api/queries/alerts'; + +type Severity = NonNullable; + +const LABELS: Record = { + CRITICAL: 'Critical', + WARNING: 'Warning', + INFO: 'Info', +}; + +const COLORS: Record = { + CRITICAL: 'error', + WARNING: 'warning', + INFO: 'auto', +}; + +export function SeverityBadge({ severity }: { severity: Severity }) { + return ; +}