@wakastellar/ui 2.1.2 → 2.3.2

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.
Files changed (123) hide show
  1. package/dist/blocks/apm-overview/index.d.ts +58 -0
  2. package/dist/blocks/cicd-builder/index.d.ts +47 -0
  3. package/dist/blocks/cloud-cost-dashboard/index.d.ts +49 -0
  4. package/dist/blocks/container-orchestrator/index.d.ts +63 -0
  5. package/dist/blocks/database-admin/index.d.ts +84 -0
  6. package/dist/blocks/gitops-sync-status/index.d.ts +45 -0
  7. package/dist/blocks/incident-manager/index.d.ts +44 -0
  8. package/dist/blocks/index.d.ts +10 -0
  9. package/dist/blocks/infrastructure-map/index.d.ts +32 -0
  10. package/dist/blocks/on-call-schedule/index.d.ts +43 -0
  11. package/dist/blocks/release-notes/index.d.ts +49 -0
  12. package/dist/components/index.d.ts +34 -0
  13. package/dist/components/waka-ad-banner/index.d.ts +36 -0
  14. package/dist/components/waka-ad-fallback/index.d.ts +33 -0
  15. package/dist/components/waka-ad-inline/index.d.ts +15 -0
  16. package/dist/components/waka-ad-interstitial/index.d.ts +26 -0
  17. package/dist/components/waka-ad-placeholder/index.d.ts +17 -0
  18. package/dist/components/waka-ad-provider/index.d.ts +103 -0
  19. package/dist/components/waka-ad-sidebar/index.d.ts +18 -0
  20. package/dist/components/waka-ad-sticky-footer/index.d.ts +17 -0
  21. package/dist/components/waka-alert-panel/index.d.ts +45 -0
  22. package/dist/components/waka-artifact-list/index.d.ts +32 -0
  23. package/dist/components/waka-build-matrix/index.d.ts +36 -0
  24. package/dist/components/waka-config-comparator/index.d.ts +37 -0
  25. package/dist/components/waka-container-list/index.d.ts +51 -0
  26. package/dist/components/waka-content-recommendation/index.d.ts +23 -0
  27. package/dist/components/waka-database-card/index.d.ts +46 -0
  28. package/dist/components/waka-dependency-tree/index.d.ts +38 -0
  29. package/dist/components/waka-env-var-editor/index.d.ts +30 -0
  30. package/dist/components/waka-feature-flag-row/index.d.ts +45 -0
  31. package/dist/components/waka-kubernetes-overview/index.d.ts +98 -0
  32. package/dist/components/waka-log-viewer/index.d.ts +38 -0
  33. package/dist/components/waka-migration-list/index.d.ts +36 -0
  34. package/dist/components/waka-outstream-video/index.d.ts +24 -0
  35. package/dist/components/waka-pod-card/index.d.ts +73 -0
  36. package/dist/components/waka-query-explain/index.d.ts +48 -0
  37. package/dist/components/waka-secret-card/index.d.ts +43 -0
  38. package/dist/components/waka-security-scan-result/index.d.ts +45 -0
  39. package/dist/components/waka-service-graph/index.d.ts +44 -0
  40. package/dist/components/waka-sponsored-badge/index.d.ts +20 -0
  41. package/dist/components/waka-sponsored-card/index.d.ts +25 -0
  42. package/dist/components/waka-sponsored-feed/index.d.ts +31 -0
  43. package/dist/components/waka-test-report/index.d.ts +60 -0
  44. package/dist/components/waka-trace-viewer/index.d.ts +36 -0
  45. package/dist/components/waka-video-ad/index.d.ts +32 -0
  46. package/dist/components/waka-video-overlay/index.d.ts +26 -0
  47. package/dist/index.cjs.js +251 -200
  48. package/dist/index.d.ts +1 -0
  49. package/dist/index.es.js +47315 -35823
  50. package/dist/utils/security.d.ts +96 -0
  51. package/package.json +4 -4
  52. package/src/blocks/apm-overview/index.tsx +672 -0
  53. package/src/blocks/cicd-builder/index.tsx +738 -0
  54. package/src/blocks/cloud-cost-dashboard/index.tsx +597 -0
  55. package/src/blocks/container-orchestrator/index.tsx +729 -0
  56. package/src/blocks/database-admin/index.tsx +679 -0
  57. package/src/blocks/gitops-sync-status/index.tsx +557 -0
  58. package/src/blocks/incident-manager/index.tsx +586 -0
  59. package/src/blocks/index.ts +119 -0
  60. package/src/blocks/infrastructure-map/index.tsx +638 -0
  61. package/src/blocks/on-call-schedule/index.tsx +615 -0
  62. package/src/blocks/release-notes/index.tsx +643 -0
  63. package/src/blocks/sidebar/index.tsx +6 -6
  64. package/src/components/DataTable/templates/index.tsx +3 -2
  65. package/src/components/index.ts +283 -0
  66. package/src/components/waka-3d-pie-chart/index.tsx +11 -11
  67. package/src/components/waka-achievement-unlock/index.tsx +16 -16
  68. package/src/components/waka-ad-banner/index.tsx +275 -0
  69. package/src/components/waka-ad-fallback/index.tsx +181 -0
  70. package/src/components/waka-ad-inline/index.tsx +103 -0
  71. package/src/components/waka-ad-interstitial/index.tsx +278 -0
  72. package/src/components/waka-ad-placeholder/index.tsx +84 -0
  73. package/src/components/waka-ad-provider/index.tsx +329 -0
  74. package/src/components/waka-ad-sidebar/index.tsx +113 -0
  75. package/src/components/waka-ad-sticky-footer/index.tsx +125 -0
  76. package/src/components/waka-alert-panel/index.tsx +493 -0
  77. package/src/components/waka-artifact-list/index.tsx +416 -0
  78. package/src/components/waka-badge-showcase/index.tsx +12 -11
  79. package/src/components/waka-build-matrix/index.tsx +396 -0
  80. package/src/components/waka-command-bar/index.tsx +2 -1
  81. package/src/components/waka-config-comparator/index.tsx +416 -0
  82. package/src/components/waka-container-list/index.tsx +475 -0
  83. package/src/components/waka-content-recommendation/index.tsx +294 -0
  84. package/src/components/waka-cost-breakdown/index.tsx +10 -10
  85. package/src/components/waka-database-card/index.tsx +473 -0
  86. package/src/components/waka-dependency-tree/index.tsx +542 -0
  87. package/src/components/waka-env-var-editor/index.tsx +417 -0
  88. package/src/components/waka-feature-flag-row/index.tsx +386 -0
  89. package/src/components/waka-funnel-chart/index.tsx +8 -8
  90. package/src/components/waka-health-pulse/index.tsx +6 -6
  91. package/src/components/waka-kubernetes-overview/index.tsx +536 -0
  92. package/src/components/waka-leaderboard/index.tsx +9 -9
  93. package/src/components/waka-log-viewer/index.tsx +386 -0
  94. package/src/components/waka-loot-box/index.tsx +20 -20
  95. package/src/components/waka-migration-list/index.tsx +487 -0
  96. package/src/components/waka-outstream-video/index.tsx +240 -0
  97. package/src/components/waka-player-card/index.tsx +5 -5
  98. package/src/components/waka-pod-card/index.tsx +528 -0
  99. package/src/components/waka-query-explain/index.tsx +657 -0
  100. package/src/components/waka-quota-bar/index.tsx +4 -4
  101. package/src/components/waka-radar-score/index.tsx +10 -10
  102. package/src/components/waka-scratch-card/index.tsx +5 -4
  103. package/src/components/waka-secret-card/index.tsx +371 -0
  104. package/src/components/waka-security-scan-result/index.tsx +473 -0
  105. package/src/components/waka-server-rack/index.tsx +28 -27
  106. package/src/components/waka-service-graph/index.tsx +445 -0
  107. package/src/components/waka-sponsored-badge/index.tsx +97 -0
  108. package/src/components/waka-sponsored-card/index.tsx +275 -0
  109. package/src/components/waka-sponsored-feed/index.tsx +127 -0
  110. package/src/components/waka-spotlight/index.tsx +2 -1
  111. package/src/components/waka-success-explosion/index.tsx +4 -4
  112. package/src/components/waka-test-report/index.tsx +469 -0
  113. package/src/components/waka-trace-viewer/index.tsx +490 -0
  114. package/src/components/waka-video-ad/index.tsx +406 -0
  115. package/src/components/waka-video-overlay/index.tsx +257 -0
  116. package/src/components/waka-xp-bar/index.tsx +13 -13
  117. package/src/styles/base.css +16 -0
  118. package/src/styles/tailwind.preset.js +12 -0
  119. package/src/styles/themes/forest.css +16 -0
  120. package/src/styles/themes/monochrome.css +16 -0
  121. package/src/styles/themes/perpetuity.css +16 -0
  122. package/src/styles/themes/sunset.css +16 -0
  123. package/src/styles/themes/twilight.css +16 -0
@@ -0,0 +1,528 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { cn } from "../../utils/cn"
5
+ import { Button } from "../button"
6
+ import { Badge } from "../badge"
7
+ import { Card, CardContent, CardHeader, CardTitle } from "../card"
8
+ import { Progress } from "../progress"
9
+ import { ScrollArea } from "../scroll-area"
10
+ import {
11
+ Tooltip,
12
+ TooltipContent,
13
+ TooltipProvider,
14
+ TooltipTrigger,
15
+ } from "../tooltip"
16
+ import {
17
+ Box,
18
+ CheckCircle2,
19
+ XCircle,
20
+ AlertTriangle,
21
+ Clock,
22
+ Cpu,
23
+ HardDrive,
24
+ RotateCcw,
25
+ Terminal,
26
+ FileText,
27
+ Trash2,
28
+ ChevronDown,
29
+ ChevronRight,
30
+ Container,
31
+ Activity,
32
+ } from "lucide-react"
33
+
34
+ export type PodPhase = "Running" | "Pending" | "Succeeded" | "Failed" | "Unknown"
35
+ export type ContainerState = "running" | "waiting" | "terminated"
36
+
37
+ export interface PodContainer {
38
+ name: string
39
+ image: string
40
+ state: ContainerState
41
+ ready: boolean
42
+ restartCount: number
43
+ startedAt?: Date
44
+ reason?: string
45
+ message?: string
46
+ resources?: {
47
+ cpu: { used: number; limit: number }
48
+ memory: { used: number; limit: number }
49
+ }
50
+ ports?: Array<{ containerPort: number; protocol: string }>
51
+ }
52
+
53
+ export interface PodEvent {
54
+ type: "Normal" | "Warning"
55
+ reason: string
56
+ message: string
57
+ timestamp: Date
58
+ count?: number
59
+ }
60
+
61
+ export interface PodDetails {
62
+ name: string
63
+ namespace: string
64
+ phase: PodPhase
65
+ nodeName?: string
66
+ podIP?: string
67
+ hostIP?: string
68
+ startTime?: Date
69
+ containers: PodContainer[]
70
+ events?: PodEvent[]
71
+ labels?: Record<string, string>
72
+ annotations?: Record<string, string>
73
+ conditions?: Array<{
74
+ type: string
75
+ status: boolean
76
+ reason?: string
77
+ message?: string
78
+ lastTransitionTime?: Date
79
+ }>
80
+ }
81
+
82
+ export interface WakaPodCardProps {
83
+ /** Pod details */
84
+ pod: PodDetails
85
+ /** Callback when viewing logs */
86
+ onViewLogs?: (containerName: string) => void
87
+ /** Callback when opening terminal */
88
+ onExec?: (containerName: string) => void
89
+ /** Callback when deleting pod */
90
+ onDelete?: () => void
91
+ /** Callback when restarting (deleting for recreation) */
92
+ onRestart?: () => void
93
+ /** Show events section */
94
+ showEvents?: boolean
95
+ /** Compact mode */
96
+ compact?: boolean
97
+ /** Custom class name */
98
+ className?: string
99
+ }
100
+
101
+ const phaseConfig: Record<PodPhase, { color: string; bgColor: string; icon: React.ElementType }> = {
102
+ Running: { color: "text-green-500", bgColor: "bg-green-500/10", icon: CheckCircle2 },
103
+ Pending: { color: "text-yellow-500", bgColor: "bg-yellow-500/10", icon: Clock },
104
+ Succeeded: { color: "text-blue-500", bgColor: "bg-blue-500/10", icon: CheckCircle2 },
105
+ Failed: { color: "text-red-500", bgColor: "bg-red-500/10", icon: XCircle },
106
+ Unknown: { color: "text-gray-500", bgColor: "bg-gray-500/10", icon: AlertTriangle },
107
+ }
108
+
109
+ const containerStateConfig: Record<ContainerState, { color: string; label: string }> = {
110
+ running: { color: "text-green-500", label: "Running" },
111
+ waiting: { color: "text-yellow-500", label: "Waiting" },
112
+ terminated: { color: "text-gray-500", label: "Terminated" },
113
+ }
114
+
115
+ function formatBytes(bytes: number): string {
116
+ if (bytes === 0) return "0 B"
117
+ const k = 1024
118
+ const sizes = ["B", "KB", "MB", "GB"]
119
+ const i = Math.floor(Math.log(bytes) / Math.log(k))
120
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + " " + sizes[i]
121
+ }
122
+
123
+ function formatAge(date?: Date): string {
124
+ if (!date) return "-"
125
+ const diff = Date.now() - date.getTime()
126
+ const minutes = Math.floor(diff / 60000)
127
+ const hours = Math.floor(minutes / 60)
128
+ const days = Math.floor(hours / 24)
129
+
130
+ if (days > 0) return `${days}d ago`
131
+ if (hours > 0) return `${hours}h ago`
132
+ return `${minutes}m ago`
133
+ }
134
+
135
+ function ContainerCard({
136
+ container,
137
+ onViewLogs,
138
+ onExec,
139
+ }: {
140
+ container: PodContainer
141
+ onViewLogs?: (name: string) => void
142
+ onExec?: (name: string) => void
143
+ }) {
144
+ const stateConfig = containerStateConfig[container.state]
145
+ const [expanded, setExpanded] = React.useState(false)
146
+
147
+ return (
148
+ <div className="border rounded-lg overflow-hidden">
149
+ <div
150
+ className={cn(
151
+ "flex items-center gap-3 p-3 cursor-pointer hover:bg-muted/50 transition-colors",
152
+ !container.ready && "bg-yellow-500/5"
153
+ )}
154
+ onClick={() => setExpanded(!expanded)}
155
+ >
156
+ <button className="text-muted-foreground">
157
+ {expanded ? <ChevronDown className="h-4 w-4" /> : <ChevronRight className="h-4 w-4" />}
158
+ </button>
159
+
160
+ <Container className="h-4 w-4 text-muted-foreground" />
161
+
162
+ <div className="flex-1 min-w-0">
163
+ <div className="font-medium truncate">{container.name}</div>
164
+ <div className="text-xs text-muted-foreground truncate">{container.image}</div>
165
+ </div>
166
+
167
+ <Badge variant="outline" className={stateConfig.color}>
168
+ {stateConfig.label}
169
+ </Badge>
170
+
171
+ {container.restartCount > 0 && (
172
+ <TooltipProvider>
173
+ <Tooltip>
174
+ <TooltipTrigger>
175
+ <Badge variant="secondary" className="text-xs">
176
+ <RotateCcw className="h-3 w-3 mr-1" />
177
+ {container.restartCount}
178
+ </Badge>
179
+ </TooltipTrigger>
180
+ <TooltipContent>Restart count</TooltipContent>
181
+ </Tooltip>
182
+ </TooltipProvider>
183
+ )}
184
+
185
+ <div className="flex items-center gap-1">
186
+ <TooltipProvider>
187
+ <Tooltip>
188
+ <TooltipTrigger asChild>
189
+ <Button
190
+ variant="ghost"
191
+ size="sm"
192
+ className="h-7 w-7 p-0"
193
+ onClick={(e) => {
194
+ e.stopPropagation()
195
+ onViewLogs?.(container.name)
196
+ }}
197
+ >
198
+ <FileText className="h-4 w-4" />
199
+ </Button>
200
+ </TooltipTrigger>
201
+ <TooltipContent>View Logs</TooltipContent>
202
+ </Tooltip>
203
+ </TooltipProvider>
204
+
205
+ {container.state === "running" && (
206
+ <TooltipProvider>
207
+ <Tooltip>
208
+ <TooltipTrigger asChild>
209
+ <Button
210
+ variant="ghost"
211
+ size="sm"
212
+ className="h-7 w-7 p-0"
213
+ onClick={(e) => {
214
+ e.stopPropagation()
215
+ onExec?.(container.name)
216
+ }}
217
+ >
218
+ <Terminal className="h-4 w-4" />
219
+ </Button>
220
+ </TooltipTrigger>
221
+ <TooltipContent>Open Terminal</TooltipContent>
222
+ </Tooltip>
223
+ </TooltipProvider>
224
+ )}
225
+ </div>
226
+ </div>
227
+
228
+ {expanded && (
229
+ <div className="border-t bg-muted/20 p-3 space-y-3">
230
+ {/* Resources */}
231
+ {container.resources && (
232
+ <div className="grid grid-cols-2 gap-4">
233
+ <div className="space-y-1">
234
+ <div className="flex items-center justify-between text-xs">
235
+ <span className="flex items-center gap-1">
236
+ <Cpu className="h-3 w-3" /> CPU
237
+ </span>
238
+ <span>
239
+ {container.resources.cpu.used}m / {container.resources.cpu.limit}m
240
+ </span>
241
+ </div>
242
+ <Progress
243
+ value={(container.resources.cpu.used / container.resources.cpu.limit) * 100}
244
+ className="h-1.5"
245
+ />
246
+ </div>
247
+ <div className="space-y-1">
248
+ <div className="flex items-center justify-between text-xs">
249
+ <span className="flex items-center gap-1">
250
+ <HardDrive className="h-3 w-3" /> Memory
251
+ </span>
252
+ <span>
253
+ {formatBytes(container.resources.memory.used)} / {formatBytes(container.resources.memory.limit)}
254
+ </span>
255
+ </div>
256
+ <Progress
257
+ value={(container.resources.memory.used / container.resources.memory.limit) * 100}
258
+ className="h-1.5"
259
+ />
260
+ </div>
261
+ </div>
262
+ )}
263
+
264
+ {/* Ports */}
265
+ {container.ports && container.ports.length > 0 && (
266
+ <div>
267
+ <div className="text-xs text-muted-foreground mb-1">Ports</div>
268
+ <div className="flex flex-wrap gap-1">
269
+ {container.ports.map((port, i) => (
270
+ <Badge key={i} variant="outline" className="text-xs">
271
+ {port.containerPort}/{port.protocol}
272
+ </Badge>
273
+ ))}
274
+ </div>
275
+ </div>
276
+ )}
277
+
278
+ {/* State details */}
279
+ {(container.reason || container.message) && (
280
+ <div className="text-xs">
281
+ {container.reason && (
282
+ <div className="font-medium text-yellow-500">{container.reason}</div>
283
+ )}
284
+ {container.message && (
285
+ <div className="text-muted-foreground">{container.message}</div>
286
+ )}
287
+ </div>
288
+ )}
289
+
290
+ {/* Started time */}
291
+ {container.startedAt && (
292
+ <div className="text-xs text-muted-foreground">
293
+ Started: {container.startedAt.toLocaleString()}
294
+ </div>
295
+ )}
296
+ </div>
297
+ )}
298
+ </div>
299
+ )
300
+ }
301
+
302
+ export function WakaPodCard({
303
+ pod,
304
+ onViewLogs,
305
+ onExec,
306
+ onDelete,
307
+ onRestart,
308
+ showEvents = true,
309
+ compact = false,
310
+ className,
311
+ }: WakaPodCardProps) {
312
+ const config = phaseConfig[pod.phase]
313
+ const PhaseIcon = config.icon
314
+ const readyContainers = pod.containers.filter((c) => c.ready).length
315
+ const totalRestarts = pod.containers.reduce((acc, c) => acc + c.restartCount, 0)
316
+
317
+ return (
318
+ <Card className={cn(config.bgColor, className)}>
319
+ <CardHeader className="pb-3">
320
+ <div className="flex items-start justify-between">
321
+ <div className="flex items-center gap-3">
322
+ <Box className="h-5 w-5 text-muted-foreground" />
323
+ <div>
324
+ <CardTitle className="text-base">{pod.name}</CardTitle>
325
+ <div className="text-sm text-muted-foreground">{pod.namespace}</div>
326
+ </div>
327
+ </div>
328
+
329
+ <div className="flex items-center gap-2">
330
+ <Badge variant="outline" className={config.color}>
331
+ <PhaseIcon className="h-3 w-3 mr-1" />
332
+ {pod.phase}
333
+ </Badge>
334
+
335
+ <div className="flex items-center gap-1">
336
+ {onRestart && (
337
+ <TooltipProvider>
338
+ <Tooltip>
339
+ <TooltipTrigger asChild>
340
+ <Button variant="ghost" size="sm" className="h-8 w-8 p-0" onClick={onRestart}>
341
+ <RotateCcw className="h-4 w-4" />
342
+ </Button>
343
+ </TooltipTrigger>
344
+ <TooltipContent>Restart Pod</TooltipContent>
345
+ </Tooltip>
346
+ </TooltipProvider>
347
+ )}
348
+ {onDelete && (
349
+ <TooltipProvider>
350
+ <Tooltip>
351
+ <TooltipTrigger asChild>
352
+ <Button
353
+ variant="ghost"
354
+ size="sm"
355
+ className="h-8 w-8 p-0 text-destructive"
356
+ onClick={onDelete}
357
+ >
358
+ <Trash2 className="h-4 w-4" />
359
+ </Button>
360
+ </TooltipTrigger>
361
+ <TooltipContent>Delete Pod</TooltipContent>
362
+ </Tooltip>
363
+ </TooltipProvider>
364
+ )}
365
+ </div>
366
+ </div>
367
+ </div>
368
+
369
+ {/* Quick stats */}
370
+ <div className="flex items-center gap-4 text-sm text-muted-foreground mt-2">
371
+ <span>Ready: {readyContainers}/{pod.containers.length}</span>
372
+ <span>Restarts: {totalRestarts}</span>
373
+ {pod.nodeName && <span>Node: {pod.nodeName}</span>}
374
+ {pod.startTime && <span>Age: {formatAge(pod.startTime)}</span>}
375
+ </div>
376
+ </CardHeader>
377
+
378
+ <CardContent className="space-y-4">
379
+ {/* Pod IPs */}
380
+ {(pod.podIP || pod.hostIP) && (
381
+ <div className="flex items-center gap-4 text-sm">
382
+ {pod.podIP && (
383
+ <div>
384
+ <span className="text-muted-foreground">Pod IP: </span>
385
+ <code className="bg-muted px-1.5 py-0.5 rounded text-xs">{pod.podIP}</code>
386
+ </div>
387
+ )}
388
+ {pod.hostIP && (
389
+ <div>
390
+ <span className="text-muted-foreground">Host IP: </span>
391
+ <code className="bg-muted px-1.5 py-0.5 rounded text-xs">{pod.hostIP}</code>
392
+ </div>
393
+ )}
394
+ </div>
395
+ )}
396
+
397
+ {/* Containers */}
398
+ <div className="space-y-2">
399
+ <div className="text-sm font-medium">Containers ({pod.containers.length})</div>
400
+ {pod.containers.map((container) => (
401
+ <ContainerCard
402
+ key={container.name}
403
+ container={container}
404
+ onViewLogs={onViewLogs}
405
+ onExec={onExec}
406
+ />
407
+ ))}
408
+ </div>
409
+
410
+ {/* Events */}
411
+ {showEvents && pod.events && pod.events.length > 0 && (
412
+ <div className="space-y-2">
413
+ <div className="text-sm font-medium flex items-center gap-2">
414
+ <Activity className="h-4 w-4" />
415
+ Events
416
+ </div>
417
+ <ScrollArea className="h-32">
418
+ <div className="space-y-2">
419
+ {pod.events.map((event, i) => (
420
+ <div
421
+ key={i}
422
+ className={cn(
423
+ "text-xs p-2 rounded border",
424
+ event.type === "Warning"
425
+ ? "bg-yellow-500/10 border-yellow-500/30"
426
+ : "bg-muted/50"
427
+ )}
428
+ >
429
+ <div className="flex items-center justify-between mb-1">
430
+ <span className="font-medium">{event.reason}</span>
431
+ <span className="text-muted-foreground">{formatAge(event.timestamp)}</span>
432
+ </div>
433
+ <div className="text-muted-foreground">{event.message}</div>
434
+ </div>
435
+ ))}
436
+ </div>
437
+ </ScrollArea>
438
+ </div>
439
+ )}
440
+
441
+ {/* Labels */}
442
+ {pod.labels && Object.keys(pod.labels).length > 0 && !compact && (
443
+ <div className="space-y-1">
444
+ <div className="text-xs text-muted-foreground">Labels</div>
445
+ <div className="flex flex-wrap gap-1">
446
+ {Object.entries(pod.labels).slice(0, 5).map(([key, value]) => (
447
+ <Badge key={key} variant="outline" className="text-xs">
448
+ {key}: {value}
449
+ </Badge>
450
+ ))}
451
+ {Object.keys(pod.labels).length > 5 && (
452
+ <Badge variant="outline" className="text-xs">
453
+ +{Object.keys(pod.labels).length - 5} more
454
+ </Badge>
455
+ )}
456
+ </div>
457
+ </div>
458
+ )}
459
+ </CardContent>
460
+ </Card>
461
+ )
462
+ }
463
+
464
+ // Default sample pod for demo
465
+ export const defaultPodDetails: PodDetails = {
466
+ name: "api-server-7d8f9b6c4d-x2k9l",
467
+ namespace: "default",
468
+ phase: "Running",
469
+ nodeName: "node-2",
470
+ podIP: "10.244.1.15",
471
+ hostIP: "192.168.1.10",
472
+ startTime: new Date(Date.now() - 5 * 24 * 3600000),
473
+ containers: [
474
+ {
475
+ name: "api",
476
+ image: "myapp/api:v1.2.3",
477
+ state: "running",
478
+ ready: true,
479
+ restartCount: 0,
480
+ startedAt: new Date(Date.now() - 5 * 24 * 3600000),
481
+ resources: {
482
+ cpu: { used: 150, limit: 500 },
483
+ memory: { used: 256 * 1024 * 1024, limit: 512 * 1024 * 1024 },
484
+ },
485
+ ports: [
486
+ { containerPort: 8080, protocol: "TCP" },
487
+ { containerPort: 9090, protocol: "TCP" },
488
+ ],
489
+ },
490
+ {
491
+ name: "sidecar",
492
+ image: "envoyproxy/envoy:v1.28",
493
+ state: "running",
494
+ ready: true,
495
+ restartCount: 1,
496
+ startedAt: new Date(Date.now() - 5 * 24 * 3600000),
497
+ resources: {
498
+ cpu: { used: 50, limit: 200 },
499
+ memory: { used: 64 * 1024 * 1024, limit: 128 * 1024 * 1024 },
500
+ },
501
+ },
502
+ ],
503
+ events: [
504
+ {
505
+ type: "Normal",
506
+ reason: "Scheduled",
507
+ message: "Successfully assigned default/api-server-7d8f9b6c4d-x2k9l to node-2",
508
+ timestamp: new Date(Date.now() - 5 * 24 * 3600000),
509
+ },
510
+ {
511
+ type: "Normal",
512
+ reason: "Pulled",
513
+ message: "Container image \"myapp/api:v1.2.3\" already present on machine",
514
+ timestamp: new Date(Date.now() - 5 * 24 * 3600000),
515
+ },
516
+ {
517
+ type: "Normal",
518
+ reason: "Started",
519
+ message: "Started container api",
520
+ timestamp: new Date(Date.now() - 5 * 24 * 3600000),
521
+ },
522
+ ],
523
+ labels: {
524
+ app: "api-server",
525
+ version: "v1.2.3",
526
+ environment: "production",
527
+ },
528
+ }