@wakastellar/ui 2.1.2 → 2.3.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.
Files changed (65) 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 +19 -0
  13. package/dist/components/waka-alert-panel/index.d.ts +45 -0
  14. package/dist/components/waka-artifact-list/index.d.ts +32 -0
  15. package/dist/components/waka-build-matrix/index.d.ts +36 -0
  16. package/dist/components/waka-config-comparator/index.d.ts +37 -0
  17. package/dist/components/waka-container-list/index.d.ts +51 -0
  18. package/dist/components/waka-database-card/index.d.ts +46 -0
  19. package/dist/components/waka-dependency-tree/index.d.ts +38 -0
  20. package/dist/components/waka-env-var-editor/index.d.ts +30 -0
  21. package/dist/components/waka-feature-flag-row/index.d.ts +45 -0
  22. package/dist/components/waka-kubernetes-overview/index.d.ts +98 -0
  23. package/dist/components/waka-log-viewer/index.d.ts +38 -0
  24. package/dist/components/waka-migration-list/index.d.ts +36 -0
  25. package/dist/components/waka-pod-card/index.d.ts +73 -0
  26. package/dist/components/waka-query-explain/index.d.ts +48 -0
  27. package/dist/components/waka-secret-card/index.d.ts +43 -0
  28. package/dist/components/waka-security-scan-result/index.d.ts +45 -0
  29. package/dist/components/waka-service-graph/index.d.ts +44 -0
  30. package/dist/components/waka-test-report/index.d.ts +60 -0
  31. package/dist/components/waka-trace-viewer/index.d.ts +36 -0
  32. package/dist/index.cjs.js +239 -194
  33. package/dist/index.es.js +45560 -35791
  34. package/package.json +1 -1
  35. package/src/blocks/apm-overview/index.tsx +672 -0
  36. package/src/blocks/cicd-builder/index.tsx +738 -0
  37. package/src/blocks/cloud-cost-dashboard/index.tsx +597 -0
  38. package/src/blocks/container-orchestrator/index.tsx +729 -0
  39. package/src/blocks/database-admin/index.tsx +679 -0
  40. package/src/blocks/gitops-sync-status/index.tsx +557 -0
  41. package/src/blocks/incident-manager/index.tsx +586 -0
  42. package/src/blocks/index.ts +119 -0
  43. package/src/blocks/infrastructure-map/index.tsx +638 -0
  44. package/src/blocks/on-call-schedule/index.tsx +615 -0
  45. package/src/blocks/release-notes/index.tsx +643 -0
  46. package/src/components/index.ts +189 -0
  47. package/src/components/waka-alert-panel/index.tsx +493 -0
  48. package/src/components/waka-artifact-list/index.tsx +416 -0
  49. package/src/components/waka-build-matrix/index.tsx +396 -0
  50. package/src/components/waka-config-comparator/index.tsx +416 -0
  51. package/src/components/waka-container-list/index.tsx +475 -0
  52. package/src/components/waka-database-card/index.tsx +473 -0
  53. package/src/components/waka-dependency-tree/index.tsx +542 -0
  54. package/src/components/waka-env-var-editor/index.tsx +417 -0
  55. package/src/components/waka-feature-flag-row/index.tsx +386 -0
  56. package/src/components/waka-kubernetes-overview/index.tsx +536 -0
  57. package/src/components/waka-log-viewer/index.tsx +386 -0
  58. package/src/components/waka-migration-list/index.tsx +487 -0
  59. package/src/components/waka-pod-card/index.tsx +528 -0
  60. package/src/components/waka-query-explain/index.tsx +657 -0
  61. package/src/components/waka-secret-card/index.tsx +371 -0
  62. package/src/components/waka-security-scan-result/index.tsx +473 -0
  63. package/src/components/waka-service-graph/index.tsx +445 -0
  64. package/src/components/waka-test-report/index.tsx +469 -0
  65. package/src/components/waka-trace-viewer/index.tsx +490 -0
@@ -0,0 +1,371 @@
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 {
9
+ Tooltip,
10
+ TooltipContent,
11
+ TooltipProvider,
12
+ TooltipTrigger,
13
+ } from "../tooltip"
14
+ import {
15
+ Key,
16
+ Copy,
17
+ CheckCircle2,
18
+ RotateCcw,
19
+ Trash2,
20
+ Clock,
21
+ Eye,
22
+ EyeOff,
23
+ AlertTriangle,
24
+ Shield,
25
+ User,
26
+ Calendar,
27
+ History,
28
+ } from "lucide-react"
29
+
30
+ export interface SecretAccess {
31
+ user: string
32
+ action: "read" | "write" | "rotate"
33
+ timestamp: Date
34
+ }
35
+
36
+ export interface Secret {
37
+ id: string
38
+ name: string
39
+ description?: string
40
+ type: "api-key" | "password" | "certificate" | "token" | "other"
41
+ value?: string // Usually not exposed
42
+ createdAt: Date
43
+ updatedAt: Date
44
+ expiresAt?: Date
45
+ rotatedAt?: Date
46
+ rotationPeriod?: number // in days
47
+ lastAccessedAt?: Date
48
+ lastAccessedBy?: string
49
+ accessHistory?: SecretAccess[]
50
+ tags?: string[]
51
+ }
52
+
53
+ export interface WakaSecretCardProps {
54
+ /** Secret data */
55
+ secret: Secret
56
+ /** Callback when rotating secret */
57
+ onRotate?: () => void
58
+ /** Callback when deleting secret */
59
+ onDelete?: () => void
60
+ /** Callback when copying secret */
61
+ onCopy?: () => void
62
+ /** Callback when viewing secret value */
63
+ onView?: () => void
64
+ /** Whether the secret value is visible */
65
+ isValueVisible?: boolean
66
+ /** Show access history */
67
+ showHistory?: boolean
68
+ /** Compact mode */
69
+ compact?: boolean
70
+ /** Custom class name */
71
+ className?: string
72
+ }
73
+
74
+ const typeConfig: Record<Secret["type"], { icon: React.ElementType; label: string; color: string }> = {
75
+ "api-key": { icon: Key, label: "API Key", color: "text-blue-500" },
76
+ password: { icon: Shield, label: "Password", color: "text-purple-500" },
77
+ certificate: { icon: Shield, label: "Certificate", color: "text-green-500" },
78
+ token: { icon: Key, label: "Token", color: "text-orange-500" },
79
+ other: { icon: Key, label: "Secret", color: "text-gray-500" },
80
+ }
81
+
82
+ function formatDate(date: Date): string {
83
+ return date.toLocaleDateString("fr-FR", {
84
+ day: "2-digit",
85
+ month: "short",
86
+ year: "numeric",
87
+ })
88
+ }
89
+
90
+ function formatRelativeTime(date: Date): string {
91
+ const diff = Date.now() - date.getTime()
92
+ const minutes = Math.floor(diff / 60000)
93
+ const hours = Math.floor(minutes / 60)
94
+ const days = Math.floor(hours / 24)
95
+
96
+ if (days > 30) return formatDate(date)
97
+ if (days > 0) return `${days}d ago`
98
+ if (hours > 0) return `${hours}h ago`
99
+ return `${minutes}m ago`
100
+ }
101
+
102
+ function isExpiringSoon(date?: Date): boolean {
103
+ if (!date) return false
104
+ const diff = date.getTime() - Date.now()
105
+ return diff > 0 && diff < 7 * 24 * 60 * 60 * 1000 // Less than 7 days
106
+ }
107
+
108
+ function isExpired(date?: Date): boolean {
109
+ if (!date) return false
110
+ return date.getTime() < Date.now()
111
+ }
112
+
113
+ function needsRotation(secret: Secret): boolean {
114
+ if (!secret.rotationPeriod || !secret.rotatedAt) return false
115
+ const daysSinceRotation = Math.floor(
116
+ (Date.now() - secret.rotatedAt.getTime()) / (24 * 60 * 60 * 1000)
117
+ )
118
+ return daysSinceRotation >= secret.rotationPeriod
119
+ }
120
+
121
+ export function WakaSecretCard({
122
+ secret,
123
+ onRotate,
124
+ onDelete,
125
+ onCopy,
126
+ onView,
127
+ isValueVisible = false,
128
+ showHistory = false,
129
+ compact = false,
130
+ className,
131
+ }: WakaSecretCardProps) {
132
+ const [copied, setCopied] = React.useState(false)
133
+ const typeConf = typeConfig[secret.type]
134
+ const TypeIcon = typeConf.icon
135
+ const expired = isExpired(secret.expiresAt)
136
+ const expiringSoon = isExpiringSoon(secret.expiresAt)
137
+ const needsRotate = needsRotation(secret)
138
+
139
+ const handleCopy = () => {
140
+ onCopy?.()
141
+ setCopied(true)
142
+ setTimeout(() => setCopied(false), 2000)
143
+ }
144
+
145
+ if (compact) {
146
+ return (
147
+ <div
148
+ className={cn(
149
+ "flex items-center gap-3 p-3 border rounded-lg hover:bg-muted/30 transition-colors",
150
+ expired && "border-red-500/50 bg-red-500/5",
151
+ expiringSoon && !expired && "border-yellow-500/50 bg-yellow-500/5",
152
+ needsRotate && "border-orange-500/50",
153
+ className
154
+ )}
155
+ >
156
+ <TypeIcon className={cn("h-5 w-5 shrink-0", typeConf.color)} />
157
+
158
+ <div className="flex-1 min-w-0">
159
+ <div className="font-medium truncate">{secret.name}</div>
160
+ <div className="text-xs text-muted-foreground flex items-center gap-2">
161
+ <span>{typeConf.label}</span>
162
+ {secret.lastAccessedAt && (
163
+ <span>Last used {formatRelativeTime(secret.lastAccessedAt)}</span>
164
+ )}
165
+ </div>
166
+ </div>
167
+
168
+ {expired && (
169
+ <Badge className="bg-red-500 text-xs">Expired</Badge>
170
+ )}
171
+ {expiringSoon && !expired && (
172
+ <Badge className="bg-yellow-500 text-xs">Expiring Soon</Badge>
173
+ )}
174
+ {needsRotate && (
175
+ <Badge variant="outline" className="text-orange-500 text-xs">
176
+ <RotateCcw className="h-3 w-3 mr-1" />
177
+ Rotate
178
+ </Badge>
179
+ )}
180
+
181
+ <div className="flex items-center gap-1">
182
+ {onView && (
183
+ <Button variant="ghost" size="sm" className="h-8 w-8 p-0" onClick={onView}>
184
+ {isValueVisible ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
185
+ </Button>
186
+ )}
187
+ {onCopy && (
188
+ <Button variant="ghost" size="sm" className="h-8 w-8 p-0" onClick={handleCopy}>
189
+ {copied ? <CheckCircle2 className="h-4 w-4 text-green-500" /> : <Copy className="h-4 w-4" />}
190
+ </Button>
191
+ )}
192
+ {onRotate && (
193
+ <Button variant="ghost" size="sm" className="h-8 w-8 p-0" onClick={onRotate}>
194
+ <RotateCcw className="h-4 w-4" />
195
+ </Button>
196
+ )}
197
+ </div>
198
+ </div>
199
+ )
200
+ }
201
+
202
+ return (
203
+ <Card className={cn(
204
+ expired && "border-red-500/50",
205
+ expiringSoon && !expired && "border-yellow-500/50",
206
+ className
207
+ )}>
208
+ <CardHeader className="pb-3">
209
+ <div className="flex items-start justify-between">
210
+ <div className="flex items-center gap-3">
211
+ <div className={cn(
212
+ "w-10 h-10 rounded-lg flex items-center justify-center",
213
+ "bg-muted"
214
+ )}>
215
+ <TypeIcon className={cn("h-5 w-5", typeConf.color)} />
216
+ </div>
217
+ <div>
218
+ <CardTitle className="text-base">{secret.name}</CardTitle>
219
+ <div className="flex items-center gap-2 mt-1">
220
+ <Badge variant="outline" className="text-xs">
221
+ {typeConf.label}
222
+ </Badge>
223
+ {secret.tags?.map((tag) => (
224
+ <Badge key={tag} variant="secondary" className="text-xs">
225
+ {tag}
226
+ </Badge>
227
+ ))}
228
+ </div>
229
+ </div>
230
+ </div>
231
+
232
+ <div className="flex items-center gap-1">
233
+ {expired && (
234
+ <Badge className="bg-red-500">
235
+ <AlertTriangle className="h-3 w-3 mr-1" />
236
+ Expired
237
+ </Badge>
238
+ )}
239
+ {expiringSoon && !expired && (
240
+ <Badge className="bg-yellow-500">
241
+ <Clock className="h-3 w-3 mr-1" />
242
+ Expires {formatDate(secret.expiresAt!)}
243
+ </Badge>
244
+ )}
245
+ {needsRotate && (
246
+ <Badge variant="outline" className="text-orange-500">
247
+ <RotateCcw className="h-3 w-3 mr-1" />
248
+ Needs Rotation
249
+ </Badge>
250
+ )}
251
+ </div>
252
+ </div>
253
+ </CardHeader>
254
+
255
+ <CardContent className="space-y-4">
256
+ {secret.description && (
257
+ <p className="text-sm text-muted-foreground">{secret.description}</p>
258
+ )}
259
+
260
+ {/* Secret value preview */}
261
+ {secret.value && (
262
+ <div className="flex items-center gap-2 p-2 bg-muted/50 rounded-lg font-mono text-sm">
263
+ <span className="flex-1 truncate">
264
+ {isValueVisible ? secret.value : "•".repeat(24)}
265
+ </span>
266
+ {onView && (
267
+ <Button variant="ghost" size="sm" className="h-7 w-7 p-0 shrink-0" onClick={onView}>
268
+ {isValueVisible ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
269
+ </Button>
270
+ )}
271
+ {onCopy && (
272
+ <Button variant="ghost" size="sm" className="h-7 w-7 p-0 shrink-0" onClick={handleCopy}>
273
+ {copied ? <CheckCircle2 className="h-4 w-4 text-green-500" /> : <Copy className="h-4 w-4" />}
274
+ </Button>
275
+ )}
276
+ </div>
277
+ )}
278
+
279
+ {/* Metadata */}
280
+ <div className="grid grid-cols-2 gap-4 text-sm">
281
+ <div className="flex items-center gap-2 text-muted-foreground">
282
+ <Calendar className="h-4 w-4" />
283
+ <span>Created {formatDate(secret.createdAt)}</span>
284
+ </div>
285
+ <div className="flex items-center gap-2 text-muted-foreground">
286
+ <Clock className="h-4 w-4" />
287
+ <span>Updated {formatRelativeTime(secret.updatedAt)}</span>
288
+ </div>
289
+ {secret.rotatedAt && (
290
+ <div className="flex items-center gap-2 text-muted-foreground">
291
+ <RotateCcw className="h-4 w-4" />
292
+ <span>Rotated {formatRelativeTime(secret.rotatedAt)}</span>
293
+ </div>
294
+ )}
295
+ {secret.lastAccessedAt && (
296
+ <div className="flex items-center gap-2 text-muted-foreground">
297
+ <User className="h-4 w-4" />
298
+ <span>
299
+ Used {formatRelativeTime(secret.lastAccessedAt)}
300
+ {secret.lastAccessedBy && ` by ${secret.lastAccessedBy}`}
301
+ </span>
302
+ </div>
303
+ )}
304
+ </div>
305
+
306
+ {/* Access history */}
307
+ {showHistory && secret.accessHistory && secret.accessHistory.length > 0 && (
308
+ <div className="border-t pt-4">
309
+ <div className="flex items-center gap-2 mb-2 text-sm font-medium">
310
+ <History className="h-4 w-4" />
311
+ Recent Access
312
+ </div>
313
+ <div className="space-y-1">
314
+ {secret.accessHistory.slice(0, 5).map((access, i) => (
315
+ <div key={i} className="flex items-center justify-between text-xs text-muted-foreground">
316
+ <span>
317
+ {access.user} - {access.action}
318
+ </span>
319
+ <span>{formatRelativeTime(access.timestamp)}</span>
320
+ </div>
321
+ ))}
322
+ </div>
323
+ </div>
324
+ )}
325
+
326
+ {/* Actions */}
327
+ <div className="flex items-center gap-2 pt-2 border-t">
328
+ {onRotate && (
329
+ <Button variant="outline" size="sm" onClick={onRotate}>
330
+ <RotateCcw className="h-4 w-4 mr-2" />
331
+ Rotate
332
+ </Button>
333
+ )}
334
+ {onDelete && (
335
+ <Button
336
+ variant="outline"
337
+ size="sm"
338
+ className="text-destructive hover:text-destructive"
339
+ onClick={onDelete}
340
+ >
341
+ <Trash2 className="h-4 w-4 mr-2" />
342
+ Delete
343
+ </Button>
344
+ )}
345
+ </div>
346
+ </CardContent>
347
+ </Card>
348
+ )
349
+ }
350
+
351
+ // Default sample secret for demo
352
+ export const defaultSecret: Secret = {
353
+ id: "1",
354
+ name: "Production API Key",
355
+ description: "Main API key for production services",
356
+ type: "api-key",
357
+ value: "sk_live_1234567890abcdefghijklmnopqrstuvwxyz",
358
+ createdAt: new Date(Date.now() - 90 * 24 * 3600000),
359
+ updatedAt: new Date(Date.now() - 7 * 24 * 3600000),
360
+ rotatedAt: new Date(Date.now() - 30 * 24 * 3600000),
361
+ rotationPeriod: 30,
362
+ expiresAt: new Date(Date.now() + 23 * 24 * 3600000),
363
+ lastAccessedAt: new Date(Date.now() - 2 * 3600000),
364
+ lastAccessedBy: "api-gateway",
365
+ tags: ["production", "critical"],
366
+ accessHistory: [
367
+ { user: "api-gateway", action: "read", timestamp: new Date(Date.now() - 2 * 3600000) },
368
+ { user: "john.doe", action: "rotate", timestamp: new Date(Date.now() - 30 * 24 * 3600000) },
369
+ { user: "api-gateway", action: "read", timestamp: new Date(Date.now() - 24 * 3600000) },
370
+ ],
371
+ }