@wakastellar/ui 2.3.4 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/blocks/dashboard/index.d.ts +4 -1
- package/dist/blocks/empty-states/index.d.ts +4 -1
- package/dist/blocks/error-pages/index.d.ts +4 -1
- package/dist/blocks/index.d.ts +1 -1
- package/dist/blocks/landing/index.d.ts +4 -1
- package/dist/blocks/pricing/index.d.ts +5 -1
- package/dist/blocks/sidebar/index.d.ts +5 -1
- package/dist/index.cjs.js +130 -130
- package/dist/index.d.ts +1 -0
- package/dist/index.es.js +7905 -7856
- package/dist/stories/Button.d.ts +14 -0
- package/dist/stories/Button.stories.d.ts +8 -0
- package/dist/stories/Header.d.ts +11 -0
- package/dist/stories/Header.stories.d.ts +6 -0
- package/dist/stories/Page.d.ts +2 -0
- package/dist/stories/Page.stories.d.ts +6 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/link.d.ts +23 -0
- package/package.json +11 -3
- package/src/blocks/activity-timeline/ActivityTimeline.stories.tsx +460 -0
- package/src/blocks/apm-overview/APMOverview.stories.tsx +435 -0
- package/src/blocks/auth-2fa/Auth2FA.stories.tsx +308 -0
- package/src/blocks/calendar-view/CalendarView.stories.tsx +398 -0
- package/src/blocks/chat/Chat.stories.tsx +466 -0
- package/src/blocks/chat-interface/ChatInterface.stories.tsx +412 -0
- package/src/blocks/checkout-flow/CheckoutFlow.stories.tsx +408 -0
- package/src/blocks/cicd-builder/CICDBuilder.stories.tsx +499 -0
- package/src/blocks/cloud-cost-dashboard/CloudCostDashboard.stories.tsx +356 -0
- package/src/blocks/container-orchestrator/ContainerOrchestrator.stories.tsx +461 -0
- package/src/blocks/dashboard/Dashboard.stories.tsx +559 -0
- package/src/blocks/dashboard/index.tsx +68 -27
- package/src/blocks/dashboard-kpi/DashboardKPI.stories.tsx +422 -0
- package/src/blocks/database-admin/DatabaseAdmin.stories.tsx +393 -0
- package/src/blocks/deployment-dashboard/DeploymentDashboard.stories.tsx +457 -0
- package/src/blocks/empty-states/EmptyStates.stories.tsx +467 -0
- package/src/blocks/empty-states/index.tsx +26 -8
- package/src/blocks/error-pages/ErrorPages.stories.tsx +401 -0
- package/src/blocks/error-pages/index.tsx +26 -8
- package/src/blocks/faq/FAQ.stories.tsx +416 -0
- package/src/blocks/file-manager/FileManager.stories.tsx +413 -0
- package/src/blocks/footer/Footer.stories.tsx +328 -0
- package/src/blocks/gitops-sync-status/GitOpsSyncStatus.stories.tsx +529 -0
- package/src/blocks/header/WakaHeader.stories.tsx +455 -0
- package/src/blocks/headtab/Headtab.stories.tsx +369 -0
- package/src/blocks/i18n-editor/I18nEditor.stories.tsx +451 -0
- package/src/blocks/incident-manager/IncidentManager.stories.tsx +464 -0
- package/src/blocks/index.ts +1 -1
- package/src/blocks/infrastructure-map/InfrastructureMap.stories.tsx +533 -0
- package/src/blocks/kanban-board/KanbanBoard.stories.tsx +494 -0
- package/src/blocks/landing/WakaLanding.stories.tsx +449 -0
- package/src/blocks/landing/index.tsx +125 -66
- package/src/blocks/language-selector/LanguageSelector.stories.tsx +345 -0
- package/src/blocks/layout/Layout.stories.tsx +373 -0
- package/src/blocks/login/Login.stories.tsx +443 -0
- package/src/blocks/on-call-schedule/OnCallSchedule.stories.tsx +381 -0
- package/src/blocks/player-profile/PlayerProfile.stories.tsx +316 -0
- package/src/blocks/pricing/WakaPricing.stories.tsx +530 -0
- package/src/blocks/pricing/index.tsx +38 -4
- package/src/blocks/profile/Profile.stories.tsx +371 -0
- package/src/blocks/release-notes/ReleaseNotes.stories.tsx +431 -0
- package/src/blocks/settings/Settings.stories.tsx +520 -0
- package/src/blocks/sidebar/WakaSidebar.stories.tsx +513 -0
- package/src/blocks/sidebar/index.tsx +49 -20
- package/src/blocks/theme-creator-block/ThemeCreatorBlock.stories.tsx +370 -0
- package/src/blocks/user-management/UserManagement.stories.tsx +411 -0
- package/src/blocks/wizard/Wizard.stories.tsx +683 -0
- package/src/components/accordion/Accordion.stories.tsx +93 -0
- package/src/components/alert/Alert.stories.tsx +95 -0
- package/src/components/alert-dialog/AlertDialog.stories.tsx +126 -0
- package/src/components/aspect-ratio/AspectRatio.stories.tsx +118 -0
- package/src/components/avatar/Avatar.stories.tsx +104 -0
- package/src/components/button/Button.stories.tsx +12 -1
- package/src/components/calendar/Calendar.stories.tsx +102 -0
- package/src/components/card/Card.stories.tsx +125 -0
- package/src/components/checkbox/Checkbox.stories.tsx +100 -0
- package/src/components/code/Code.stories.tsx +402 -0
- package/src/components/collapsible/Collapsible.stories.tsx +123 -0
- package/src/components/command/Command.stories.tsx +207 -0
- package/src/components/context-menu/ContextMenu.stories.tsx +220 -0
- package/src/components/dialog/Dialog.stories.tsx +157 -0
- package/src/components/dropdown-menu/DropdownMenu.stories.tsx +225 -0
- package/src/components/form/Form.stories.tsx +413 -0
- package/src/components/hover-card/HoverCard.stories.tsx +148 -0
- package/src/components/input-otp/InputOTP.stories.tsx +255 -0
- package/src/components/label/Label.stories.tsx +68 -0
- package/src/components/menubar/Menubar.stories.tsx +278 -0
- package/src/components/navigation-menu/NavigationMenu.stories.tsx +202 -0
- package/src/components/popover/Popover.stories.tsx +199 -0
- package/src/components/progress/Progress.stories.tsx +104 -0
- package/src/components/radio-group/RadioGroup.stories.tsx +138 -0
- package/src/components/scroll-area/ScrollArea.stories.tsx +153 -0
- package/src/components/select/Select.stories.tsx +146 -0
- package/src/components/separator/Separator.stories.tsx +117 -0
- package/src/components/sheet/Sheet.stories.tsx +195 -0
- package/src/components/skeleton/Skeleton.stories.tsx +114 -0
- package/src/components/slider/Slider.stories.tsx +157 -0
- package/src/components/switch/Switch.stories.tsx +114 -0
- package/src/components/table/Table.stories.tsx +153 -0
- package/src/components/tabs/Tabs.stories.tsx +155 -0
- package/src/components/textarea/Textarea.stories.tsx +116 -0
- package/src/components/toast/Toast.stories.tsx +160 -0
- package/src/components/toggle/Toggle.stories.tsx +125 -0
- package/src/components/tooltip/Tooltip.stories.tsx +133 -0
- package/src/components/typography/Typography.stories.tsx +207 -0
- package/src/components/waka-3d-pie-chart/Waka3DPieChart.stories.tsx +308 -0
- package/src/components/waka-achievement-unlock/WakaAchievementUnlock.stories.tsx +353 -0
- package/src/components/waka-artifact-list/WakaArtifactList.stories.tsx +258 -0
- package/src/components/waka-autocomplete/WakaAutocomplete.stories.tsx +224 -0
- package/src/components/waka-badge-showcase/WakaBadgeShowcase.stories.tsx +269 -0
- package/src/components/waka-barcode/WakaBarcode.stories.tsx +227 -0
- package/src/components/waka-bottom-sheet/WakaBottomSheet.stories.tsx +408 -0
- package/src/components/waka-breadcrumb/WakaBreadcrumb.stories.tsx +237 -0
- package/src/components/waka-build-matrix/WakaBuildMatrix.stories.tsx +328 -0
- package/src/components/waka-carousel/WakaCarousel.stories.tsx +296 -0
- package/src/components/waka-charts/WakaCharts.stories.tsx +519 -0
- package/src/components/waka-color-picker/WakaColorPicker.stories.tsx +200 -0
- package/src/components/waka-combobox/WakaCombobox.stories.tsx +250 -0
- package/src/components/waka-container-list/WakaContainerList.stories.tsx +315 -0
- package/src/components/waka-contribution-graph/WakaContributionGraph.stories.tsx +354 -0
- package/src/components/waka-cost-breakdown/WakaCostBreakdown.stories.tsx +348 -0
- package/src/components/waka-daily-reward/WakaDailyReward.stories.tsx +365 -0
- package/src/components/waka-database-card/WakaDatabaseCard.stories.tsx +306 -0
- package/src/components/waka-date-range-picker/WakaDateRangePicker.stories.tsx +339 -0
- package/src/components/waka-datetime-picker/WakaDateTimePicker.stories.tsx +317 -0
- package/src/components/waka-deployment-lane/WakaDeploymentLane.stories.tsx +292 -0
- package/src/components/waka-dock/WakaDock.stories.tsx +332 -0
- package/src/components/waka-drawer/WakaDrawer.stories.tsx +437 -0
- package/src/components/waka-env-var-editor/WakaEnvVarEditor.stories.tsx +263 -0
- package/src/components/waka-error-shake/WakaErrorShake.stories.tsx +410 -0
- package/src/components/waka-file-upload/WakaFileUpload.stories.tsx +239 -0
- package/src/components/waka-flow-diagram/WakaFlowDiagram.stories.tsx +365 -0
- package/src/components/waka-funnel-chart/WakaFunnelChart.stories.tsx +281 -0
- package/src/components/waka-glow-card/WakaGlowCard.stories.tsx +274 -0
- package/src/components/waka-haptic-button/WakaHapticButton.stories.tsx +349 -0
- package/src/components/waka-health-pulse/WakaHealthPulse.stories.tsx +293 -0
- package/src/components/waka-heatmap/WakaHeatmap.stories.tsx +376 -0
- package/src/components/waka-image/WakaImage.stories.tsx +255 -0
- package/src/components/waka-incident-timeline/WakaIncidentTimeline.stories.tsx +300 -0
- package/src/components/waka-kanban/WakaKanban.stories.tsx +399 -0
- package/src/components/waka-kubernetes-overview/WakaKubernetesOverview.stories.tsx +281 -0
- package/src/components/waka-leaderboard/WakaLeaderboard.stories.tsx +300 -0
- package/src/components/waka-level-progress/WakaLevelProgress.stories.tsx +313 -0
- package/src/components/waka-loading-orbit/WakaLoadingOrbit.stories.tsx +413 -0
- package/src/components/waka-log-viewer/WakaLogViewer.stories.tsx +312 -0
- package/src/components/waka-loot-box/WakaLootBox.stories.tsx +374 -0
- package/src/components/waka-metric-sparkline/WakaMetricSparkline.stories.tsx +312 -0
- package/src/components/waka-migration-list/WakaMigrationList.stories.tsx +289 -0
- package/src/components/waka-modal/WakaModal.stories.tsx +434 -0
- package/src/components/waka-morph-button/WakaMorphButton.stories.tsx +405 -0
- package/src/components/waka-network-topology/WakaNetworkTopology.stories.tsx +364 -0
- package/src/components/waka-notifications/WakaNotifications.stories.tsx +290 -0
- package/src/components/waka-number-input/WakaNumberInput.stories.tsx +282 -0
- package/src/components/waka-pagination/WakaPagination.stories.tsx +328 -0
- package/src/components/waka-password-strength/WakaPasswordStrength.stories.tsx +318 -0
- package/src/components/waka-pipeline-view/WakaPipelineView.stories.tsx +386 -0
- package/src/components/waka-player-card/WakaPlayerCard.stories.tsx +333 -0
- package/src/components/waka-pod-card/WakaPodCard.stories.tsx +435 -0
- package/src/components/waka-qrcode/WakaQRCode.stories.tsx +232 -0
- package/src/components/waka-query-explain/WakaQueryExplain.stories.tsx +407 -0
- package/src/components/waka-quest-card/WakaQuestCard.stories.tsx +394 -0
- package/src/components/waka-quota-bar/WakaQuotaBar.stories.tsx +435 -0
- package/src/components/waka-radar-score/WakaRadarScore.stories.tsx +372 -0
- package/src/components/waka-resource-gauge/WakaResourceGauge.stories.tsx +366 -0
- package/src/components/waka-rich-text-editor/WakaRichTextEditor.stories.tsx +238 -0
- package/src/components/waka-sankey-diagram/WakaSankeyDiagram.stories.tsx +389 -0
- package/src/components/waka-scratch-card/WakaScratchCard.stories.tsx +388 -0
- package/src/components/waka-secret-card/WakaSecretCard.stories.tsx +314 -0
- package/src/components/waka-segmented-control/WakaSegmentedControl.stories.tsx +309 -0
- package/src/components/waka-server-rack/WakaServerRack.stories.tsx +382 -0
- package/src/components/waka-service-graph/WakaServiceGraph.stories.tsx +262 -0
- package/src/components/waka-skeleton-wave/WakaSkeletonWave.stories.tsx +321 -0
- package/src/components/waka-skill-tree/WakaSkillTree.stories.tsx +308 -0
- package/src/components/waka-spin-wheel/WakaSpinWheel.stories.tsx +368 -0
- package/src/components/waka-spinner/WakaSpinner.stories.tsx +156 -0
- package/src/components/waka-stat/WakaStat.stories.tsx +334 -0
- package/src/components/waka-status-matrix/WakaStatusMatrix.stories.tsx +331 -0
- package/src/components/waka-stepper/WakaStepper.stories.tsx +468 -0
- package/src/components/waka-streak-counter/WakaStreakCounter.stories.tsx +235 -0
- package/src/components/waka-success-explosion/WakaSuccessExplosion.stories.tsx +389 -0
- package/src/components/waka-tabs-morph/WakaTabsMorph.stories.tsx +471 -0
- package/src/components/waka-terminal-output/WakaTerminalOutput.stories.tsx +351 -0
- package/src/components/waka-test-report/WakaTestReport.stories.tsx +322 -0
- package/src/components/waka-tilt-card/WakaTiltCard.stories.tsx +300 -0
- package/src/components/waka-time-picker/WakaTimePicker.stories.tsx +227 -0
- package/src/components/waka-timeline/WakaTimeline.stories.tsx +383 -0
- package/src/components/waka-tournament-bracket/WakaTournamentBracket.stories.tsx +375 -0
- package/src/components/waka-trace-viewer/WakaTraceViewer.stories.tsx +445 -0
- package/src/components/waka-tree/WakaTree.stories.tsx +359 -0
- package/src/components/waka-treemap-chart/WakaTreemapChart.stories.tsx +378 -0
- package/src/components/waka-typewriter/WakaTypewriter.stories.tsx +366 -0
- package/src/components/waka-versus-card/WakaVersusCard.stories.tsx +530 -0
- package/src/components/waka-video/WakaVideo.stories.tsx +203 -0
- package/src/components/waka-virtual-list/WakaVirtualList.stories.tsx +273 -0
- package/src/components/waka-xp-bar/WakaXPBar.stories.tsx +305 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react'
|
|
2
|
+
import { WakaTerminalOutput, useTerminalOutput } from './index'
|
|
3
|
+
import type { LogLine, LogLevel } from './index'
|
|
4
|
+
import * as React from 'react'
|
|
5
|
+
|
|
6
|
+
const sampleLogs: LogLine[] = [
|
|
7
|
+
{ content: '[2024-01-15 10:30:45] INFO Starting application server...', level: 'info', timestamp: new Date('2024-01-15T10:30:45') },
|
|
8
|
+
{ content: '[2024-01-15 10:30:46] DEBUG Loading configuration from /etc/app/config.yaml', level: 'debug', timestamp: new Date('2024-01-15T10:30:46') },
|
|
9
|
+
{ content: '[2024-01-15 10:30:47] INFO Database connection established', level: 'info', timestamp: new Date('2024-01-15T10:30:47') },
|
|
10
|
+
{ content: '[2024-01-15 10:30:48] WARN High memory usage detected: 85%', level: 'warn', timestamp: new Date('2024-01-15T10:30:48') },
|
|
11
|
+
{ content: '[2024-01-15 10:30:49] INFO HTTP server listening on port 3000', level: 'info', timestamp: new Date('2024-01-15T10:30:49') },
|
|
12
|
+
{ content: '[2024-01-15 10:30:50] DEBUG Request: GET /api/health - 200 OK (12ms)', level: 'debug', timestamp: new Date('2024-01-15T10:30:50') },
|
|
13
|
+
{ content: '[2024-01-15 10:30:51] ERROR Connection refused to redis://localhost:6379', level: 'error', timestamp: new Date('2024-01-15T10:30:51') },
|
|
14
|
+
{ content: '[2024-01-15 10:30:52] INFO Retrying connection in 5 seconds...', level: 'info', timestamp: new Date('2024-01-15T10:30:52') },
|
|
15
|
+
{ content: '[2024-01-15 10:30:57] INFO Redis connection restored', level: 'info', timestamp: new Date('2024-01-15T10:30:57') },
|
|
16
|
+
{ content: '[2024-01-15 10:30:58] DEBUG Cache hit for key: user:12345', level: 'debug', timestamp: new Date('2024-01-15T10:30:58') },
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
const ansiLogs: LogLine[] = [
|
|
20
|
+
{ content: '\x1b[32m✓\x1b[0m All tests passed', level: 'info' },
|
|
21
|
+
{ content: '\x1b[34mINFO\x1b[0m Compiling TypeScript...', level: 'info' },
|
|
22
|
+
{ content: '\x1b[33mWARN\x1b[0m Deprecated API usage detected', level: 'warn' },
|
|
23
|
+
{ content: '\x1b[31mERROR\x1b[0m Failed to load module: \x1b[1m@app/utils\x1b[0m', level: 'error' },
|
|
24
|
+
{ content: '\x1b[90mDEBUG\x1b[0m Memory: \x1b[36m256MB\x1b[0m / \x1b[36m512MB\x1b[0m', level: 'debug' },
|
|
25
|
+
{ content: '\x1b[32m✓\x1b[0m Build completed in \x1b[1m\x1b[33m2.3s\x1b[0m', level: 'info' },
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
const meta: Meta<typeof WakaTerminalOutput> = {
|
|
29
|
+
title: 'Components/DevOps/WakaTerminalOutput',
|
|
30
|
+
component: WakaTerminalOutput,
|
|
31
|
+
parameters: {
|
|
32
|
+
layout: 'centered',
|
|
33
|
+
docs: {
|
|
34
|
+
description: {
|
|
35
|
+
component: 'A terminal output viewer with ANSI color support, syntax highlighting, search, filtering, virtualization, and auto-scroll.',
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
tags: ['autodocs'],
|
|
40
|
+
argTypes: {
|
|
41
|
+
showLineNumbers: {
|
|
42
|
+
control: 'boolean',
|
|
43
|
+
description: 'Show line numbers',
|
|
44
|
+
},
|
|
45
|
+
showTimestamps: {
|
|
46
|
+
control: 'boolean',
|
|
47
|
+
description: 'Show timestamps',
|
|
48
|
+
},
|
|
49
|
+
autoScroll: {
|
|
50
|
+
control: 'boolean',
|
|
51
|
+
description: 'Auto-scroll to bottom on new lines',
|
|
52
|
+
},
|
|
53
|
+
searchable: {
|
|
54
|
+
control: 'boolean',
|
|
55
|
+
description: 'Enable search functionality',
|
|
56
|
+
},
|
|
57
|
+
filterable: {
|
|
58
|
+
control: 'boolean',
|
|
59
|
+
description: 'Enable log level filtering',
|
|
60
|
+
},
|
|
61
|
+
height: {
|
|
62
|
+
control: { type: 'number', min: 200, max: 800, step: 50 },
|
|
63
|
+
description: 'Height of the terminal',
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export default meta
|
|
69
|
+
type Story = StoryObj<typeof WakaTerminalOutput>
|
|
70
|
+
|
|
71
|
+
export const Default: Story = {
|
|
72
|
+
args: {
|
|
73
|
+
lines: sampleLogs,
|
|
74
|
+
height: 400,
|
|
75
|
+
showLineNumbers: true,
|
|
76
|
+
showTimestamps: true,
|
|
77
|
+
autoScroll: true,
|
|
78
|
+
searchable: true,
|
|
79
|
+
filterable: true,
|
|
80
|
+
},
|
|
81
|
+
render: (args) => (
|
|
82
|
+
<div className="w-[700px]">
|
|
83
|
+
<WakaTerminalOutput {...args} />
|
|
84
|
+
</div>
|
|
85
|
+
),
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export const WithLineNumbers: Story = {
|
|
89
|
+
render: () => (
|
|
90
|
+
<div className="w-[700px]">
|
|
91
|
+
<WakaTerminalOutput
|
|
92
|
+
lines={sampleLogs}
|
|
93
|
+
showLineNumbers
|
|
94
|
+
height={400}
|
|
95
|
+
/>
|
|
96
|
+
</div>
|
|
97
|
+
),
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export const WithTimestamps: Story = {
|
|
101
|
+
render: () => (
|
|
102
|
+
<div className="w-[700px]">
|
|
103
|
+
<WakaTerminalOutput
|
|
104
|
+
lines={sampleLogs}
|
|
105
|
+
showTimestamps
|
|
106
|
+
height={400}
|
|
107
|
+
/>
|
|
108
|
+
</div>
|
|
109
|
+
),
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export const FullFeatured: Story = {
|
|
113
|
+
render: () => (
|
|
114
|
+
<div className="w-[800px]">
|
|
115
|
+
<WakaTerminalOutput
|
|
116
|
+
lines={sampleLogs}
|
|
117
|
+
showLineNumbers
|
|
118
|
+
showTimestamps
|
|
119
|
+
searchable
|
|
120
|
+
filterable
|
|
121
|
+
height={450}
|
|
122
|
+
onCopy={(content) => console.log('Copied:', content)}
|
|
123
|
+
onClear={() => console.log('Cleared')}
|
|
124
|
+
/>
|
|
125
|
+
</div>
|
|
126
|
+
),
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export const AnsiColors: Story = {
|
|
130
|
+
render: () => (
|
|
131
|
+
<div className="w-[700px]">
|
|
132
|
+
<p className="text-sm text-muted-foreground mb-4">
|
|
133
|
+
Terminal output with ANSI escape codes for colors
|
|
134
|
+
</p>
|
|
135
|
+
<WakaTerminalOutput
|
|
136
|
+
lines={ansiLogs}
|
|
137
|
+
height={300}
|
|
138
|
+
/>
|
|
139
|
+
</div>
|
|
140
|
+
),
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export const WithHook: Story = {
|
|
144
|
+
render: () => {
|
|
145
|
+
const { lines, log, warn, error, debug, clear } = useTerminalOutput()
|
|
146
|
+
|
|
147
|
+
return (
|
|
148
|
+
<div className="w-[700px] space-y-4">
|
|
149
|
+
<WakaTerminalOutput
|
|
150
|
+
lines={lines}
|
|
151
|
+
showLineNumbers
|
|
152
|
+
searchable
|
|
153
|
+
filterable
|
|
154
|
+
height={300}
|
|
155
|
+
onClear={clear}
|
|
156
|
+
/>
|
|
157
|
+
|
|
158
|
+
<div className="flex gap-2">
|
|
159
|
+
<button
|
|
160
|
+
onClick={() => log(`[${new Date().toISOString()}] INFO Application running normally`)}
|
|
161
|
+
className="px-3 py-1.5 text-xs rounded bg-blue-500 text-white"
|
|
162
|
+
>
|
|
163
|
+
Add Info
|
|
164
|
+
</button>
|
|
165
|
+
<button
|
|
166
|
+
onClick={() => warn(`[${new Date().toISOString()}] WARN Memory usage at 75%`)}
|
|
167
|
+
className="px-3 py-1.5 text-xs rounded bg-yellow-500 text-black"
|
|
168
|
+
>
|
|
169
|
+
Add Warning
|
|
170
|
+
</button>
|
|
171
|
+
<button
|
|
172
|
+
onClick={() => error(`[${new Date().toISOString()}] ERROR Connection failed`)}
|
|
173
|
+
className="px-3 py-1.5 text-xs rounded bg-red-500 text-white"
|
|
174
|
+
>
|
|
175
|
+
Add Error
|
|
176
|
+
</button>
|
|
177
|
+
<button
|
|
178
|
+
onClick={() => debug(`[${new Date().toISOString()}] DEBUG Request processed`)}
|
|
179
|
+
className="px-3 py-1.5 text-xs rounded bg-gray-500 text-white"
|
|
180
|
+
>
|
|
181
|
+
Add Debug
|
|
182
|
+
</button>
|
|
183
|
+
<button
|
|
184
|
+
onClick={clear}
|
|
185
|
+
className="px-3 py-1.5 text-xs rounded border hover:bg-muted"
|
|
186
|
+
>
|
|
187
|
+
Clear
|
|
188
|
+
</button>
|
|
189
|
+
</div>
|
|
190
|
+
</div>
|
|
191
|
+
)
|
|
192
|
+
},
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export const LiveStreaming: Story = {
|
|
196
|
+
render: () => {
|
|
197
|
+
const [lines, setLines] = React.useState<LogLine[]>([
|
|
198
|
+
{ content: '[INFO] Starting log stream...', level: 'info', timestamp: new Date() },
|
|
199
|
+
])
|
|
200
|
+
|
|
201
|
+
React.useEffect(() => {
|
|
202
|
+
const messages = [
|
|
203
|
+
{ content: 'GET /api/users - 200 OK (23ms)', level: 'debug' as LogLevel },
|
|
204
|
+
{ content: 'POST /api/orders - 201 Created (156ms)', level: 'info' as LogLevel },
|
|
205
|
+
{ content: 'Connection pool exhausted, retrying...', level: 'warn' as LogLevel },
|
|
206
|
+
{ content: 'GET /api/products - 200 OK (12ms)', level: 'debug' as LogLevel },
|
|
207
|
+
{ content: 'Cache invalidated for key: products:*', level: 'info' as LogLevel },
|
|
208
|
+
{ content: 'Database query timeout after 30s', level: 'error' as LogLevel },
|
|
209
|
+
{ content: 'Reconnecting to database...', level: 'info' as LogLevel },
|
|
210
|
+
{ content: 'DELETE /api/sessions/expired - 204 (89ms)', level: 'debug' as LogLevel },
|
|
211
|
+
]
|
|
212
|
+
|
|
213
|
+
let index = 0
|
|
214
|
+
const interval = setInterval(() => {
|
|
215
|
+
const msg = messages[index % messages.length]
|
|
216
|
+
setLines(prev => [
|
|
217
|
+
...prev,
|
|
218
|
+
{
|
|
219
|
+
content: `[${new Date().toISOString()}] ${msg.level.toUpperCase()} ${msg.content}`,
|
|
220
|
+
level: msg.level,
|
|
221
|
+
timestamp: new Date(),
|
|
222
|
+
},
|
|
223
|
+
].slice(-100))
|
|
224
|
+
index++
|
|
225
|
+
}, 800)
|
|
226
|
+
|
|
227
|
+
return () => clearInterval(interval)
|
|
228
|
+
}, [])
|
|
229
|
+
|
|
230
|
+
return (
|
|
231
|
+
<div className="w-[700px]">
|
|
232
|
+
<p className="text-sm text-muted-foreground mb-4">
|
|
233
|
+
Live streaming logs (simulated)
|
|
234
|
+
</p>
|
|
235
|
+
<WakaTerminalOutput
|
|
236
|
+
lines={lines}
|
|
237
|
+
showLineNumbers
|
|
238
|
+
filterable
|
|
239
|
+
autoScroll
|
|
240
|
+
height={400}
|
|
241
|
+
/>
|
|
242
|
+
</div>
|
|
243
|
+
)
|
|
244
|
+
},
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export const LargeLogs: Story = {
|
|
248
|
+
render: () => {
|
|
249
|
+
const largeLogs: LogLine[] = Array.from({ length: 1000 }, (_, i) => ({
|
|
250
|
+
content: `[${new Date().toISOString()}] ${['INFO', 'DEBUG', 'WARN', 'ERROR'][Math.floor(Math.random() * 4)]} Log line ${i + 1} - ${Math.random().toString(36).substring(7)}`,
|
|
251
|
+
level: ['info', 'debug', 'warn', 'error'][Math.floor(Math.random() * 4)] as LogLevel,
|
|
252
|
+
timestamp: new Date(Date.now() - (1000 - i) * 1000),
|
|
253
|
+
}))
|
|
254
|
+
|
|
255
|
+
return (
|
|
256
|
+
<div className="w-[700px]">
|
|
257
|
+
<p className="text-sm text-muted-foreground mb-4">
|
|
258
|
+
1000 lines with virtualization for smooth scrolling
|
|
259
|
+
</p>
|
|
260
|
+
<WakaTerminalOutput
|
|
261
|
+
lines={largeLogs}
|
|
262
|
+
showLineNumbers
|
|
263
|
+
searchable
|
|
264
|
+
filterable
|
|
265
|
+
height={400}
|
|
266
|
+
/>
|
|
267
|
+
</div>
|
|
268
|
+
)
|
|
269
|
+
},
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export const BuildOutput: Story = {
|
|
273
|
+
render: () => {
|
|
274
|
+
const buildLogs: LogLine[] = [
|
|
275
|
+
{ content: '> wakastar-ui@1.0.0 build', level: 'info' },
|
|
276
|
+
{ content: '> tsc && vite build', level: 'info' },
|
|
277
|
+
{ content: '', level: 'info' },
|
|
278
|
+
{ content: '\x1b[34mvite v5.0.12\x1b[0m building for production...', level: 'info' },
|
|
279
|
+
{ content: '✓ 156 modules transformed.', level: 'info' },
|
|
280
|
+
{ content: '\x1b[33mwarn\x1b[0m: The following dependencies are externalized:', level: 'warn' },
|
|
281
|
+
{ content: ' - react', level: 'warn' },
|
|
282
|
+
{ content: ' - react-dom', level: 'warn' },
|
|
283
|
+
{ content: 'rendering chunks...', level: 'debug' },
|
|
284
|
+
{ content: 'computing gzip size...', level: 'debug' },
|
|
285
|
+
{ content: '', level: 'info' },
|
|
286
|
+
{ content: 'dist/index.js 45.32 kB │ gzip: 14.21 kB', level: 'info' },
|
|
287
|
+
{ content: 'dist/index.css 12.45 kB │ gzip: 3.12 kB', level: 'info' },
|
|
288
|
+
{ content: '', level: 'info' },
|
|
289
|
+
{ content: '\x1b[32m✓ built in 2.34s\x1b[0m', level: 'info' },
|
|
290
|
+
]
|
|
291
|
+
|
|
292
|
+
return (
|
|
293
|
+
<div className="w-[700px]">
|
|
294
|
+
<p className="text-sm text-muted-foreground mb-4">
|
|
295
|
+
Build output with progress information
|
|
296
|
+
</p>
|
|
297
|
+
<WakaTerminalOutput
|
|
298
|
+
lines={buildLogs}
|
|
299
|
+
height={350}
|
|
300
|
+
/>
|
|
301
|
+
</div>
|
|
302
|
+
)
|
|
303
|
+
},
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
export const DockerLogs: Story = {
|
|
307
|
+
render: () => {
|
|
308
|
+
const dockerLogs: LogLine[] = [
|
|
309
|
+
{ content: 'Sending build context to Docker daemon 2.048kB', level: 'info' },
|
|
310
|
+
{ content: 'Step 1/8 : FROM node:20-alpine', level: 'info' },
|
|
311
|
+
{ content: ' ---> 3c2c7d5e3c12', level: 'debug' },
|
|
312
|
+
{ content: 'Step 2/8 : WORKDIR /app', level: 'info' },
|
|
313
|
+
{ content: ' ---> Using cache', level: 'debug' },
|
|
314
|
+
{ content: ' ---> 8f9b7c6d5e4a', level: 'debug' },
|
|
315
|
+
{ content: 'Step 3/8 : COPY package*.json ./', level: 'info' },
|
|
316
|
+
{ content: ' ---> 1a2b3c4d5e6f', level: 'debug' },
|
|
317
|
+
{ content: 'Step 4/8 : RUN npm ci --only=production', level: 'info' },
|
|
318
|
+
{ content: 'npm warn deprecated @types/node@16.0.0', level: 'warn' },
|
|
319
|
+
{ content: 'added 156 packages in 12s', level: 'info' },
|
|
320
|
+
{ content: 'Step 5/8 : COPY . .', level: 'info' },
|
|
321
|
+
{ content: ' ---> 7g8h9i0j1k2l', level: 'debug' },
|
|
322
|
+
{ content: 'Step 6/8 : RUN npm run build', level: 'info' },
|
|
323
|
+
{ content: 'Successfully built a1b2c3d4e5f6', level: 'info' },
|
|
324
|
+
{ content: 'Successfully tagged myapp:latest', level: 'info' },
|
|
325
|
+
]
|
|
326
|
+
|
|
327
|
+
return (
|
|
328
|
+
<div className="w-[700px]">
|
|
329
|
+
<p className="text-sm text-muted-foreground mb-4">
|
|
330
|
+
Docker build logs
|
|
331
|
+
</p>
|
|
332
|
+
<WakaTerminalOutput
|
|
333
|
+
lines={dockerLogs}
|
|
334
|
+
showLineNumbers
|
|
335
|
+
height={400}
|
|
336
|
+
/>
|
|
337
|
+
</div>
|
|
338
|
+
)
|
|
339
|
+
},
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
export const Empty: Story = {
|
|
343
|
+
render: () => (
|
|
344
|
+
<div className="w-[700px]">
|
|
345
|
+
<WakaTerminalOutput
|
|
346
|
+
lines={[]}
|
|
347
|
+
height={300}
|
|
348
|
+
/>
|
|
349
|
+
</div>
|
|
350
|
+
),
|
|
351
|
+
}
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react'
|
|
2
|
+
import { WakaTestReport, defaultTestSuites, defaultCoverage } from './index'
|
|
3
|
+
import type { TestSuite, TestCase, TestStatus, CoverageReport } from './index'
|
|
4
|
+
import * as React from 'react'
|
|
5
|
+
|
|
6
|
+
const allPassingSuites: TestSuite[] = [
|
|
7
|
+
{
|
|
8
|
+
id: '1',
|
|
9
|
+
name: 'Unit Tests',
|
|
10
|
+
file: 'src/__tests__/unit.test.ts',
|
|
11
|
+
duration: 1250,
|
|
12
|
+
tests: [
|
|
13
|
+
{ id: '1-1', name: 'should format date correctly', status: 'passed', duration: 45 },
|
|
14
|
+
{ id: '1-2', name: 'should parse JSON strings', status: 'passed', duration: 32 },
|
|
15
|
+
{ id: '1-3', name: 'should validate email format', status: 'passed', duration: 28 },
|
|
16
|
+
{ id: '1-4', name: 'should hash passwords securely', status: 'passed', duration: 156 },
|
|
17
|
+
],
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
id: '2',
|
|
21
|
+
name: 'Integration Tests',
|
|
22
|
+
file: 'src/__tests__/integration.test.ts',
|
|
23
|
+
duration: 3500,
|
|
24
|
+
tests: [
|
|
25
|
+
{ id: '2-1', name: 'should connect to database', status: 'passed', duration: 890 },
|
|
26
|
+
{ id: '2-2', name: 'should authenticate user', status: 'passed', duration: 1200 },
|
|
27
|
+
{ id: '2-3', name: 'should fetch user profile', status: 'passed', duration: 450 },
|
|
28
|
+
],
|
|
29
|
+
},
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
const allFailingSuites: TestSuite[] = [
|
|
33
|
+
{
|
|
34
|
+
id: '1',
|
|
35
|
+
name: 'API Tests',
|
|
36
|
+
file: 'src/api/__tests__/api.test.ts',
|
|
37
|
+
duration: 5200,
|
|
38
|
+
tests: [
|
|
39
|
+
{
|
|
40
|
+
id: '1-1',
|
|
41
|
+
name: 'should return 200 for valid request',
|
|
42
|
+
status: 'failed',
|
|
43
|
+
duration: 245,
|
|
44
|
+
errorMessage: 'Expected status code 200, received 500',
|
|
45
|
+
stackTrace: 'Error: Request failed\n at ApiClient.request (src/api/client.ts:45:15)',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
id: '1-2',
|
|
49
|
+
name: 'should handle rate limiting',
|
|
50
|
+
status: 'failed',
|
|
51
|
+
duration: 1500,
|
|
52
|
+
errorMessage: 'Rate limit not applied correctly',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
id: '1-3',
|
|
56
|
+
name: 'should validate request body',
|
|
57
|
+
status: 'failed',
|
|
58
|
+
duration: 89,
|
|
59
|
+
errorMessage: 'Validation error: missing required field "email"',
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
},
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
const mixedSuites: TestSuite[] = [
|
|
66
|
+
{
|
|
67
|
+
id: '1',
|
|
68
|
+
name: 'Component Tests',
|
|
69
|
+
file: 'src/components/__tests__/Button.test.tsx',
|
|
70
|
+
duration: 890,
|
|
71
|
+
tests: [
|
|
72
|
+
{ id: '1-1', name: 'renders with default props', status: 'passed', duration: 45, file: 'src/components/__tests__/Button.test.tsx', line: 12 },
|
|
73
|
+
{ id: '1-2', name: 'handles click events', status: 'passed', duration: 67, file: 'src/components/__tests__/Button.test.tsx', line: 28 },
|
|
74
|
+
{ id: '1-3', name: 'applies custom className', status: 'passed', duration: 23, file: 'src/components/__tests__/Button.test.tsx', line: 45 },
|
|
75
|
+
{
|
|
76
|
+
id: '1-4',
|
|
77
|
+
name: 'disables when loading',
|
|
78
|
+
status: 'failed',
|
|
79
|
+
duration: 89,
|
|
80
|
+
errorMessage: 'Button should be disabled when loading=true',
|
|
81
|
+
file: 'src/components/__tests__/Button.test.tsx',
|
|
82
|
+
line: 62,
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
id: '2',
|
|
88
|
+
name: 'Hook Tests',
|
|
89
|
+
file: 'src/hooks/__tests__/useAuth.test.ts',
|
|
90
|
+
duration: 1200,
|
|
91
|
+
tests: [
|
|
92
|
+
{ id: '2-1', name: 'returns authenticated state', status: 'passed', duration: 234 },
|
|
93
|
+
{ id: '2-2', name: 'handles login flow', status: 'passed', duration: 456 },
|
|
94
|
+
{ id: '2-3', name: 'handles logout', status: 'skipped', duration: 0 },
|
|
95
|
+
{ id: '2-4', name: 'refreshes token on expiry', status: 'pending', duration: 0 },
|
|
96
|
+
],
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
id: '3',
|
|
100
|
+
name: 'E2E Tests',
|
|
101
|
+
file: 'e2e/checkout.test.ts',
|
|
102
|
+
duration: 15000,
|
|
103
|
+
tests: [
|
|
104
|
+
{ id: '3-1', name: 'completes checkout flow', status: 'passed', duration: 8500 },
|
|
105
|
+
{
|
|
106
|
+
id: '3-2',
|
|
107
|
+
name: 'handles payment failure',
|
|
108
|
+
status: 'failed',
|
|
109
|
+
duration: 4500,
|
|
110
|
+
errorMessage: 'Timeout: Element not found within 5000ms',
|
|
111
|
+
stackTrace: 'TimeoutError: waitForSelector timed out\n at e2e/checkout.test.ts:89:5',
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
},
|
|
115
|
+
]
|
|
116
|
+
|
|
117
|
+
const lowCoverage: CoverageReport = {
|
|
118
|
+
lines: { covered: 450, total: 1500, percentage: 30.0 },
|
|
119
|
+
branches: { covered: 25, total: 120, percentage: 20.8 },
|
|
120
|
+
functions: { covered: 45, total: 180, percentage: 25.0 },
|
|
121
|
+
statements: { covered: 520, total: 1650, percentage: 31.5 },
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const highCoverage: CoverageReport = {
|
|
125
|
+
lines: { covered: 1425, total: 1500, percentage: 95.0 },
|
|
126
|
+
branches: { covered: 108, total: 120, percentage: 90.0 },
|
|
127
|
+
functions: { covered: 171, total: 180, percentage: 95.0 },
|
|
128
|
+
statements: { covered: 1567, total: 1650, percentage: 95.0 },
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const meta: Meta<typeof WakaTestReport> = {
|
|
132
|
+
title: 'Components/DevOps/WakaTestReport',
|
|
133
|
+
component: WakaTestReport,
|
|
134
|
+
parameters: {
|
|
135
|
+
layout: 'centered',
|
|
136
|
+
docs: {
|
|
137
|
+
description: {
|
|
138
|
+
component: 'A test report viewer with suite expansion, coverage bars, search, filtering, and detailed error messages.',
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
tags: ['autodocs'],
|
|
143
|
+
argTypes: {
|
|
144
|
+
showFailedOnly: {
|
|
145
|
+
control: 'boolean',
|
|
146
|
+
description: 'Show only failed tests by default',
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export default meta
|
|
152
|
+
type Story = StoryObj<typeof WakaTestReport>
|
|
153
|
+
|
|
154
|
+
export const Default: Story = {
|
|
155
|
+
args: {
|
|
156
|
+
suites: defaultTestSuites,
|
|
157
|
+
coverage: defaultCoverage,
|
|
158
|
+
},
|
|
159
|
+
render: (args) => (
|
|
160
|
+
<div className="w-[800px] h-[600px]">
|
|
161
|
+
<WakaTestReport
|
|
162
|
+
{...args}
|
|
163
|
+
onTestClick={(test) => console.log('Test click:', test)}
|
|
164
|
+
onViewFile={(file, line) => console.log('View file:', file, line)}
|
|
165
|
+
/>
|
|
166
|
+
</div>
|
|
167
|
+
),
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export const AllPassing: Story = {
|
|
171
|
+
render: () => (
|
|
172
|
+
<div className="w-[800px] h-[500px]">
|
|
173
|
+
<WakaTestReport
|
|
174
|
+
suites={allPassingSuites}
|
|
175
|
+
coverage={highCoverage}
|
|
176
|
+
title="All Tests Passing"
|
|
177
|
+
/>
|
|
178
|
+
</div>
|
|
179
|
+
),
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export const AllFailing: Story = {
|
|
183
|
+
render: () => (
|
|
184
|
+
<div className="w-[800px] h-[500px]">
|
|
185
|
+
<WakaTestReport
|
|
186
|
+
suites={allFailingSuites}
|
|
187
|
+
coverage={lowCoverage}
|
|
188
|
+
title="Build Failed"
|
|
189
|
+
/>
|
|
190
|
+
</div>
|
|
191
|
+
),
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export const MixedResults: Story = {
|
|
195
|
+
render: () => (
|
|
196
|
+
<div className="w-[800px] h-[600px]">
|
|
197
|
+
<WakaTestReport
|
|
198
|
+
suites={mixedSuites}
|
|
199
|
+
coverage={defaultCoverage}
|
|
200
|
+
title="Test Results"
|
|
201
|
+
onTestClick={(test) => console.log('Test click:', test)}
|
|
202
|
+
onViewFile={(file, line) => console.log('View file:', file, line)}
|
|
203
|
+
/>
|
|
204
|
+
</div>
|
|
205
|
+
),
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export const FailedOnlyFilter: Story = {
|
|
209
|
+
render: () => (
|
|
210
|
+
<div className="w-[800px] h-[500px]">
|
|
211
|
+
<p className="text-sm text-muted-foreground mb-4">
|
|
212
|
+
Pre-filtered to show only failed tests
|
|
213
|
+
</p>
|
|
214
|
+
<WakaTestReport
|
|
215
|
+
suites={mixedSuites}
|
|
216
|
+
showFailedOnly
|
|
217
|
+
title="Failed Tests"
|
|
218
|
+
/>
|
|
219
|
+
</div>
|
|
220
|
+
),
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export const NoCoverage: Story = {
|
|
224
|
+
render: () => (
|
|
225
|
+
<div className="w-[800px] h-[500px]">
|
|
226
|
+
<WakaTestReport
|
|
227
|
+
suites={defaultTestSuites}
|
|
228
|
+
title="Tests Without Coverage"
|
|
229
|
+
/>
|
|
230
|
+
</div>
|
|
231
|
+
),
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export const LowCoverage: Story = {
|
|
235
|
+
render: () => (
|
|
236
|
+
<div className="w-[800px] h-[500px]">
|
|
237
|
+
<p className="text-sm text-muted-foreground mb-4">
|
|
238
|
+
Coverage below threshold (red/yellow bars)
|
|
239
|
+
</p>
|
|
240
|
+
<WakaTestReport
|
|
241
|
+
suites={allFailingSuites}
|
|
242
|
+
coverage={lowCoverage}
|
|
243
|
+
title="Low Coverage Report"
|
|
244
|
+
/>
|
|
245
|
+
</div>
|
|
246
|
+
),
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export const HighCoverage: Story = {
|
|
250
|
+
render: () => (
|
|
251
|
+
<div className="w-[800px] h-[500px]">
|
|
252
|
+
<WakaTestReport
|
|
253
|
+
suites={allPassingSuites}
|
|
254
|
+
coverage={highCoverage}
|
|
255
|
+
title="Excellent Coverage"
|
|
256
|
+
/>
|
|
257
|
+
</div>
|
|
258
|
+
),
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export const ManySuites: Story = {
|
|
262
|
+
render: () => {
|
|
263
|
+
const manySuites: TestSuite[] = Array.from({ length: 15 }, (_, i) => ({
|
|
264
|
+
id: `suite-${i}`,
|
|
265
|
+
name: `Test Suite ${i + 1}`,
|
|
266
|
+
file: `src/modules/module-${i}/__tests__/index.test.ts`,
|
|
267
|
+
duration: Math.floor(Math.random() * 5000) + 500,
|
|
268
|
+
tests: Array.from({ length: Math.floor(Math.random() * 8) + 2 }, (_, j) => ({
|
|
269
|
+
id: `${i}-${j}`,
|
|
270
|
+
name: `Test case ${j + 1} for suite ${i + 1}`,
|
|
271
|
+
status: ['passed', 'passed', 'passed', 'failed', 'skipped'][Math.floor(Math.random() * 5)] as TestStatus,
|
|
272
|
+
duration: Math.floor(Math.random() * 500) + 10,
|
|
273
|
+
})),
|
|
274
|
+
}))
|
|
275
|
+
|
|
276
|
+
return (
|
|
277
|
+
<div className="w-[800px] h-[600px]">
|
|
278
|
+
<WakaTestReport
|
|
279
|
+
suites={manySuites}
|
|
280
|
+
coverage={defaultCoverage}
|
|
281
|
+
title="Large Test Suite"
|
|
282
|
+
/>
|
|
283
|
+
</div>
|
|
284
|
+
)
|
|
285
|
+
},
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
export const Empty: Story = {
|
|
289
|
+
render: () => (
|
|
290
|
+
<div className="w-[800px] h-[400px]">
|
|
291
|
+
<WakaTestReport suites={[]} title="No Tests" />
|
|
292
|
+
</div>
|
|
293
|
+
),
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
export const CITestReport: Story = {
|
|
297
|
+
render: () => (
|
|
298
|
+
<div className="p-6 rounded-xl border bg-card">
|
|
299
|
+
<div className="flex items-center justify-between mb-6">
|
|
300
|
+
<div>
|
|
301
|
+
<h2 className="text-xl font-bold">CI Pipeline - Test Stage</h2>
|
|
302
|
+
<p className="text-sm text-muted-foreground">
|
|
303
|
+
Branch: feature/add-auth • Commit: abc123f
|
|
304
|
+
</p>
|
|
305
|
+
</div>
|
|
306
|
+
<div className="flex items-center gap-2">
|
|
307
|
+
<div className="w-2 h-2 rounded-full bg-yellow-500" />
|
|
308
|
+
<span className="text-sm text-yellow-500 font-medium">Some tests failed</span>
|
|
309
|
+
</div>
|
|
310
|
+
</div>
|
|
311
|
+
|
|
312
|
+
<div className="w-[750px]">
|
|
313
|
+
<WakaTestReport
|
|
314
|
+
suites={mixedSuites}
|
|
315
|
+
coverage={defaultCoverage}
|
|
316
|
+
onTestClick={(test) => console.log('Test click:', test)}
|
|
317
|
+
onViewFile={(file, line) => console.log('View file:', file, line)}
|
|
318
|
+
/>
|
|
319
|
+
</div>
|
|
320
|
+
</div>
|
|
321
|
+
),
|
|
322
|
+
}
|