feat: implement v0.4.0 - Reports, Charts, Comparison, Dark Mode, E2E Testing
Backend (@backend-dev): - Add ReportService with PDF/CSV generation (reportlab, pandas) - Implement Report API endpoints (POST, GET, DELETE, download) - Add ReportRepository and schemas - Configure storage with auto-cleanup (30 days) - Rate limiting: 10 downloads/minute - Professional PDF templates with charts support Frontend (@frontend-dev): - Integrate Recharts for data visualization - Add CostBreakdown, TimeSeries, ComparisonBar charts - Implement scenario comparison page with multi-select - Add dark/light mode toggle with ThemeProvider - Create Reports page with generation form and list - Add new UI components: checkbox, dialog, tabs, label, skeleton - Implement useComparison and useReports hooks QA (@qa-engineer): - Setup Playwright E2E testing framework - Create 7 test spec files with 94 test cases - Add visual regression testing with baselines - Configure multi-browser testing (Chrome, Firefox, WebKit) - Add mobile responsive tests - Create test fixtures and helpers - Setup GitHub Actions CI workflow Documentation (@spec-architect): - Create detailed kanban-v0.4.0.md with 27 tasks - Update progress.md with v0.4.0 tracking - Create v0.4.0 planning prompt Features: ✅ PDF/CSV Report Generation ✅ Interactive Charts (Pie, Area, Bar) ✅ Scenario Comparison (2-4 scenarios) ✅ Dark/Light Mode Toggle ✅ E2E Test Suite (94 tests) Dependencies added: - Backend: reportlab, pandas, slowapi - Frontend: recharts, date-fns, @radix-ui/react-checkbox/dialog/tabs - Testing: @playwright/test 27 tasks completed, 100% v0.4.0 implementation
This commit is contained in:
87
frontend/src/components/charts/ChartContainer.tsx
Normal file
87
frontend/src/components/charts/ChartContainer.tsx
Normal file
@@ -0,0 +1,87 @@
|
||||
import type { ReactNode } from 'react';
|
||||
import {
|
||||
ResponsiveContainer,
|
||||
type ResponsiveContainerProps,
|
||||
} from 'recharts';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
interface ChartContainerProps extends Omit<ResponsiveContainerProps, 'children'> {
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
title?: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export function ChartContainer({
|
||||
children,
|
||||
className,
|
||||
title,
|
||||
description,
|
||||
...props
|
||||
}: ChartContainerProps) {
|
||||
return (
|
||||
<div className={cn('w-full', className)}>
|
||||
{(title || description) && (
|
||||
<div className="mb-4">
|
||||
{title && <h3 className="text-lg font-semibold">{title}</h3>}
|
||||
{description && (
|
||||
<p className="text-sm text-muted-foreground">{description}</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div className="w-full overflow-hidden rounded-lg border bg-card p-4">
|
||||
<ResponsiveContainer {...props}>
|
||||
{children}
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Chart colors matching Tailwind/shadcn theme
|
||||
export const CHART_COLORS = {
|
||||
primary: 'hsl(var(--primary))',
|
||||
secondary: 'hsl(var(--secondary))',
|
||||
accent: 'hsl(var(--accent))',
|
||||
muted: 'hsl(var(--muted))',
|
||||
destructive: 'hsl(var(--destructive))',
|
||||
// Service-specific colors
|
||||
sqs: '#FF9900', // AWS Orange
|
||||
lambda: '#F97316', // Orange-500
|
||||
bedrock: '#8B5CF6', // Violet-500
|
||||
// Additional chart colors
|
||||
blue: '#3B82F6',
|
||||
green: '#10B981',
|
||||
yellow: '#F59E0B',
|
||||
red: '#EF4444',
|
||||
purple: '#8B5CF6',
|
||||
pink: '#EC4899',
|
||||
cyan: '#06B6D4',
|
||||
};
|
||||
|
||||
// Chart color palette for multiple series
|
||||
export const CHART_PALETTE = [
|
||||
CHART_COLORS.sqs,
|
||||
CHART_COLORS.lambda,
|
||||
CHART_COLORS.bedrock,
|
||||
CHART_COLORS.blue,
|
||||
CHART_COLORS.green,
|
||||
CHART_COLORS.purple,
|
||||
CHART_COLORS.pink,
|
||||
CHART_COLORS.cyan,
|
||||
];
|
||||
|
||||
// Format currency for tooltips
|
||||
export function formatCurrency(value: number): string {
|
||||
return new Intl.NumberFormat('en-US', {
|
||||
style: 'currency',
|
||||
currency: 'USD',
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 4,
|
||||
}).format(value);
|
||||
}
|
||||
|
||||
// Format number for tooltips
|
||||
export function formatNumber(value: number): string {
|
||||
return new Intl.NumberFormat('en-US').format(value);
|
||||
}
|
||||
Reference in New Issue
Block a user