@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.
- package/dist/blocks/apm-overview/index.d.ts +58 -0
- package/dist/blocks/cicd-builder/index.d.ts +47 -0
- package/dist/blocks/cloud-cost-dashboard/index.d.ts +49 -0
- package/dist/blocks/container-orchestrator/index.d.ts +63 -0
- package/dist/blocks/database-admin/index.d.ts +84 -0
- package/dist/blocks/gitops-sync-status/index.d.ts +45 -0
- package/dist/blocks/incident-manager/index.d.ts +44 -0
- package/dist/blocks/index.d.ts +10 -0
- package/dist/blocks/infrastructure-map/index.d.ts +32 -0
- package/dist/blocks/on-call-schedule/index.d.ts +43 -0
- package/dist/blocks/release-notes/index.d.ts +49 -0
- package/dist/components/index.d.ts +34 -0
- package/dist/components/waka-ad-banner/index.d.ts +36 -0
- package/dist/components/waka-ad-fallback/index.d.ts +33 -0
- package/dist/components/waka-ad-inline/index.d.ts +15 -0
- package/dist/components/waka-ad-interstitial/index.d.ts +26 -0
- package/dist/components/waka-ad-placeholder/index.d.ts +17 -0
- package/dist/components/waka-ad-provider/index.d.ts +103 -0
- package/dist/components/waka-ad-sidebar/index.d.ts +18 -0
- package/dist/components/waka-ad-sticky-footer/index.d.ts +17 -0
- package/dist/components/waka-alert-panel/index.d.ts +45 -0
- package/dist/components/waka-artifact-list/index.d.ts +32 -0
- package/dist/components/waka-build-matrix/index.d.ts +36 -0
- package/dist/components/waka-config-comparator/index.d.ts +37 -0
- package/dist/components/waka-container-list/index.d.ts +51 -0
- package/dist/components/waka-content-recommendation/index.d.ts +23 -0
- package/dist/components/waka-database-card/index.d.ts +46 -0
- package/dist/components/waka-dependency-tree/index.d.ts +38 -0
- package/dist/components/waka-env-var-editor/index.d.ts +30 -0
- package/dist/components/waka-feature-flag-row/index.d.ts +45 -0
- package/dist/components/waka-kubernetes-overview/index.d.ts +98 -0
- package/dist/components/waka-log-viewer/index.d.ts +38 -0
- package/dist/components/waka-migration-list/index.d.ts +36 -0
- package/dist/components/waka-outstream-video/index.d.ts +24 -0
- package/dist/components/waka-pod-card/index.d.ts +73 -0
- package/dist/components/waka-query-explain/index.d.ts +48 -0
- package/dist/components/waka-secret-card/index.d.ts +43 -0
- package/dist/components/waka-security-scan-result/index.d.ts +45 -0
- package/dist/components/waka-service-graph/index.d.ts +44 -0
- package/dist/components/waka-sponsored-badge/index.d.ts +20 -0
- package/dist/components/waka-sponsored-card/index.d.ts +25 -0
- package/dist/components/waka-sponsored-feed/index.d.ts +31 -0
- package/dist/components/waka-test-report/index.d.ts +60 -0
- package/dist/components/waka-trace-viewer/index.d.ts +36 -0
- package/dist/components/waka-video-ad/index.d.ts +32 -0
- package/dist/components/waka-video-overlay/index.d.ts +26 -0
- package/dist/index.cjs.js +251 -200
- package/dist/index.d.ts +1 -0
- package/dist/index.es.js +47315 -35823
- package/dist/utils/security.d.ts +96 -0
- package/package.json +4 -4
- package/src/blocks/apm-overview/index.tsx +672 -0
- package/src/blocks/cicd-builder/index.tsx +738 -0
- package/src/blocks/cloud-cost-dashboard/index.tsx +597 -0
- package/src/blocks/container-orchestrator/index.tsx +729 -0
- package/src/blocks/database-admin/index.tsx +679 -0
- package/src/blocks/gitops-sync-status/index.tsx +557 -0
- package/src/blocks/incident-manager/index.tsx +586 -0
- package/src/blocks/index.ts +119 -0
- package/src/blocks/infrastructure-map/index.tsx +638 -0
- package/src/blocks/on-call-schedule/index.tsx +615 -0
- package/src/blocks/release-notes/index.tsx +643 -0
- package/src/blocks/sidebar/index.tsx +6 -6
- package/src/components/DataTable/templates/index.tsx +3 -2
- package/src/components/index.ts +283 -0
- package/src/components/waka-3d-pie-chart/index.tsx +11 -11
- package/src/components/waka-achievement-unlock/index.tsx +16 -16
- package/src/components/waka-ad-banner/index.tsx +275 -0
- package/src/components/waka-ad-fallback/index.tsx +181 -0
- package/src/components/waka-ad-inline/index.tsx +103 -0
- package/src/components/waka-ad-interstitial/index.tsx +278 -0
- package/src/components/waka-ad-placeholder/index.tsx +84 -0
- package/src/components/waka-ad-provider/index.tsx +329 -0
- package/src/components/waka-ad-sidebar/index.tsx +113 -0
- package/src/components/waka-ad-sticky-footer/index.tsx +125 -0
- package/src/components/waka-alert-panel/index.tsx +493 -0
- package/src/components/waka-artifact-list/index.tsx +416 -0
- package/src/components/waka-badge-showcase/index.tsx +12 -11
- package/src/components/waka-build-matrix/index.tsx +396 -0
- package/src/components/waka-command-bar/index.tsx +2 -1
- package/src/components/waka-config-comparator/index.tsx +416 -0
- package/src/components/waka-container-list/index.tsx +475 -0
- package/src/components/waka-content-recommendation/index.tsx +294 -0
- package/src/components/waka-cost-breakdown/index.tsx +10 -10
- package/src/components/waka-database-card/index.tsx +473 -0
- package/src/components/waka-dependency-tree/index.tsx +542 -0
- package/src/components/waka-env-var-editor/index.tsx +417 -0
- package/src/components/waka-feature-flag-row/index.tsx +386 -0
- package/src/components/waka-funnel-chart/index.tsx +8 -8
- package/src/components/waka-health-pulse/index.tsx +6 -6
- package/src/components/waka-kubernetes-overview/index.tsx +536 -0
- package/src/components/waka-leaderboard/index.tsx +9 -9
- package/src/components/waka-log-viewer/index.tsx +386 -0
- package/src/components/waka-loot-box/index.tsx +20 -20
- package/src/components/waka-migration-list/index.tsx +487 -0
- package/src/components/waka-outstream-video/index.tsx +240 -0
- package/src/components/waka-player-card/index.tsx +5 -5
- package/src/components/waka-pod-card/index.tsx +528 -0
- package/src/components/waka-query-explain/index.tsx +657 -0
- package/src/components/waka-quota-bar/index.tsx +4 -4
- package/src/components/waka-radar-score/index.tsx +10 -10
- package/src/components/waka-scratch-card/index.tsx +5 -4
- package/src/components/waka-secret-card/index.tsx +371 -0
- package/src/components/waka-security-scan-result/index.tsx +473 -0
- package/src/components/waka-server-rack/index.tsx +28 -27
- package/src/components/waka-service-graph/index.tsx +445 -0
- package/src/components/waka-sponsored-badge/index.tsx +97 -0
- package/src/components/waka-sponsored-card/index.tsx +275 -0
- package/src/components/waka-sponsored-feed/index.tsx +127 -0
- package/src/components/waka-spotlight/index.tsx +2 -1
- package/src/components/waka-success-explosion/index.tsx +4 -4
- package/src/components/waka-test-report/index.tsx +469 -0
- package/src/components/waka-trace-viewer/index.tsx +490 -0
- package/src/components/waka-video-ad/index.tsx +406 -0
- package/src/components/waka-video-overlay/index.tsx +257 -0
- package/src/components/waka-xp-bar/index.tsx +13 -13
- package/src/styles/base.css +16 -0
- package/src/styles/tailwind.preset.js +12 -0
- package/src/styles/themes/forest.css +16 -0
- package/src/styles/themes/monochrome.css +16 -0
- package/src/styles/themes/perpetuity.css +16 -0
- package/src/styles/themes/sunset.css +16 -0
- package/src/styles/themes/twilight.css +16 -0
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { cn } from "../../utils/cn"
|
|
5
|
+
import { Badge } from "../badge"
|
|
6
|
+
import { Button } from "../button"
|
|
7
|
+
import { Input } from "../input"
|
|
8
|
+
import { ScrollArea } from "../scroll-area"
|
|
9
|
+
import {
|
|
10
|
+
Tooltip,
|
|
11
|
+
TooltipContent,
|
|
12
|
+
TooltipProvider,
|
|
13
|
+
TooltipTrigger,
|
|
14
|
+
} from "../tooltip"
|
|
15
|
+
import {
|
|
16
|
+
Package,
|
|
17
|
+
Download,
|
|
18
|
+
Trash2,
|
|
19
|
+
Search,
|
|
20
|
+
FileArchive,
|
|
21
|
+
FileText,
|
|
22
|
+
Image,
|
|
23
|
+
File,
|
|
24
|
+
Folder,
|
|
25
|
+
Clock,
|
|
26
|
+
HardDrive,
|
|
27
|
+
ExternalLink,
|
|
28
|
+
Copy,
|
|
29
|
+
CheckCircle2,
|
|
30
|
+
} from "lucide-react"
|
|
31
|
+
|
|
32
|
+
export interface Artifact {
|
|
33
|
+
id: string
|
|
34
|
+
name: string
|
|
35
|
+
type: "archive" | "binary" | "log" | "report" | "image" | "other"
|
|
36
|
+
size: number // in bytes
|
|
37
|
+
createdAt: Date
|
|
38
|
+
expiresAt?: Date
|
|
39
|
+
downloadUrl?: string
|
|
40
|
+
sha256?: string
|
|
41
|
+
buildId?: string
|
|
42
|
+
metadata?: Record<string, string>
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface WakaArtifactListProps {
|
|
46
|
+
/** List of artifacts */
|
|
47
|
+
artifacts: Artifact[]
|
|
48
|
+
/** Callback when downloading an artifact */
|
|
49
|
+
onDownload?: (artifact: Artifact) => void
|
|
50
|
+
/** Callback when deleting an artifact */
|
|
51
|
+
onDelete?: (artifact: Artifact) => void
|
|
52
|
+
/** Callback when viewing artifact details */
|
|
53
|
+
onView?: (artifact: Artifact) => void
|
|
54
|
+
/** Title */
|
|
55
|
+
title?: string
|
|
56
|
+
/** Show expiration */
|
|
57
|
+
showExpiration?: boolean
|
|
58
|
+
/** Allow deletion */
|
|
59
|
+
allowDelete?: boolean
|
|
60
|
+
/** Custom class name */
|
|
61
|
+
className?: string
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const typeConfig: Record<Artifact["type"], { icon: React.ElementType; color: string }> = {
|
|
65
|
+
archive: { icon: FileArchive, color: "text-orange-500" },
|
|
66
|
+
binary: { icon: Package, color: "text-blue-500" },
|
|
67
|
+
log: { icon: FileText, color: "text-gray-500" },
|
|
68
|
+
report: { icon: FileText, color: "text-green-500" },
|
|
69
|
+
image: { icon: Image, color: "text-purple-500" },
|
|
70
|
+
other: { icon: File, color: "text-muted-foreground" },
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function formatBytes(bytes: number): string {
|
|
74
|
+
if (bytes === 0) return "0 B"
|
|
75
|
+
const k = 1024
|
|
76
|
+
const sizes = ["B", "KB", "MB", "GB"]
|
|
77
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k))
|
|
78
|
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i]
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function formatDate(date: Date): string {
|
|
82
|
+
return date.toLocaleDateString("fr-FR", {
|
|
83
|
+
day: "2-digit",
|
|
84
|
+
month: "short",
|
|
85
|
+
hour: "2-digit",
|
|
86
|
+
minute: "2-digit",
|
|
87
|
+
})
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function isExpiringSoon(date?: Date): boolean {
|
|
91
|
+
if (!date) return false
|
|
92
|
+
const diff = date.getTime() - Date.now()
|
|
93
|
+
return diff > 0 && diff < 24 * 60 * 60 * 1000 // Less than 24h
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function ArtifactRow({
|
|
97
|
+
artifact,
|
|
98
|
+
onDownload,
|
|
99
|
+
onDelete,
|
|
100
|
+
onView,
|
|
101
|
+
showExpiration,
|
|
102
|
+
allowDelete,
|
|
103
|
+
}: {
|
|
104
|
+
artifact: Artifact
|
|
105
|
+
onDownload?: (artifact: Artifact) => void
|
|
106
|
+
onDelete?: (artifact: Artifact) => void
|
|
107
|
+
onView?: (artifact: Artifact) => void
|
|
108
|
+
showExpiration: boolean
|
|
109
|
+
allowDelete: boolean
|
|
110
|
+
}) {
|
|
111
|
+
const [copied, setCopied] = React.useState(false)
|
|
112
|
+
const config = typeConfig[artifact.type]
|
|
113
|
+
const Icon = config.icon
|
|
114
|
+
const expiringSoon = isExpiringSoon(artifact.expiresAt)
|
|
115
|
+
|
|
116
|
+
const copyHash = () => {
|
|
117
|
+
if (artifact.sha256) {
|
|
118
|
+
navigator.clipboard.writeText(artifact.sha256)
|
|
119
|
+
setCopied(true)
|
|
120
|
+
setTimeout(() => setCopied(false), 2000)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return (
|
|
125
|
+
<div className="flex items-center gap-4 p-3 border-b hover:bg-muted/30 transition-colors">
|
|
126
|
+
{/* Icon */}
|
|
127
|
+
<Icon className={cn("h-8 w-8 shrink-0", config.color)} />
|
|
128
|
+
|
|
129
|
+
{/* Info */}
|
|
130
|
+
<div className="flex-1 min-w-0">
|
|
131
|
+
<div className="flex items-center gap-2">
|
|
132
|
+
<span
|
|
133
|
+
className="font-medium truncate cursor-pointer hover:text-primary"
|
|
134
|
+
onClick={() => onView?.(artifact)}
|
|
135
|
+
>
|
|
136
|
+
{artifact.name}
|
|
137
|
+
</span>
|
|
138
|
+
<Badge variant="outline" className="text-xs capitalize">
|
|
139
|
+
{artifact.type}
|
|
140
|
+
</Badge>
|
|
141
|
+
</div>
|
|
142
|
+
<div className="flex items-center gap-3 text-xs text-muted-foreground mt-1">
|
|
143
|
+
<span className="flex items-center gap-1">
|
|
144
|
+
<HardDrive className="h-3 w-3" />
|
|
145
|
+
{formatBytes(artifact.size)}
|
|
146
|
+
</span>
|
|
147
|
+
<span className="flex items-center gap-1">
|
|
148
|
+
<Clock className="h-3 w-3" />
|
|
149
|
+
{formatDate(artifact.createdAt)}
|
|
150
|
+
</span>
|
|
151
|
+
{showExpiration && artifact.expiresAt && (
|
|
152
|
+
<span className={cn("flex items-center gap-1", expiringSoon && "text-yellow-500")}>
|
|
153
|
+
Expires: {formatDate(artifact.expiresAt)}
|
|
154
|
+
</span>
|
|
155
|
+
)}
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
158
|
+
|
|
159
|
+
{/* SHA256 */}
|
|
160
|
+
{artifact.sha256 && (
|
|
161
|
+
<TooltipProvider>
|
|
162
|
+
<Tooltip>
|
|
163
|
+
<TooltipTrigger asChild>
|
|
164
|
+
<button
|
|
165
|
+
className="hidden md:flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground"
|
|
166
|
+
onClick={copyHash}
|
|
167
|
+
>
|
|
168
|
+
{copied ? (
|
|
169
|
+
<CheckCircle2 className="h-3 w-3 text-green-500" />
|
|
170
|
+
) : (
|
|
171
|
+
<Copy className="h-3 w-3" />
|
|
172
|
+
)}
|
|
173
|
+
<code className="truncate max-w-[100px]">{artifact.sha256.slice(0, 12)}...</code>
|
|
174
|
+
</button>
|
|
175
|
+
</TooltipTrigger>
|
|
176
|
+
<TooltipContent>
|
|
177
|
+
<div className="space-y-1">
|
|
178
|
+
<div className="text-xs font-medium">SHA256</div>
|
|
179
|
+
<code className="text-xs break-all">{artifact.sha256}</code>
|
|
180
|
+
</div>
|
|
181
|
+
</TooltipContent>
|
|
182
|
+
</Tooltip>
|
|
183
|
+
</TooltipProvider>
|
|
184
|
+
)}
|
|
185
|
+
|
|
186
|
+
{/* Actions */}
|
|
187
|
+
<div className="flex items-center gap-1 shrink-0">
|
|
188
|
+
{artifact.downloadUrl && (
|
|
189
|
+
<TooltipProvider>
|
|
190
|
+
<Tooltip>
|
|
191
|
+
<TooltipTrigger asChild>
|
|
192
|
+
<Button
|
|
193
|
+
variant="ghost"
|
|
194
|
+
size="sm"
|
|
195
|
+
className="h-8 w-8 p-0"
|
|
196
|
+
onClick={() => onDownload?.(artifact)}
|
|
197
|
+
>
|
|
198
|
+
<Download className="h-4 w-4" />
|
|
199
|
+
</Button>
|
|
200
|
+
</TooltipTrigger>
|
|
201
|
+
<TooltipContent>Download</TooltipContent>
|
|
202
|
+
</Tooltip>
|
|
203
|
+
</TooltipProvider>
|
|
204
|
+
)}
|
|
205
|
+
|
|
206
|
+
<TooltipProvider>
|
|
207
|
+
<Tooltip>
|
|
208
|
+
<TooltipTrigger asChild>
|
|
209
|
+
<Button
|
|
210
|
+
variant="ghost"
|
|
211
|
+
size="sm"
|
|
212
|
+
className="h-8 w-8 p-0"
|
|
213
|
+
onClick={() => onView?.(artifact)}
|
|
214
|
+
>
|
|
215
|
+
<ExternalLink className="h-4 w-4" />
|
|
216
|
+
</Button>
|
|
217
|
+
</TooltipTrigger>
|
|
218
|
+
<TooltipContent>View Details</TooltipContent>
|
|
219
|
+
</Tooltip>
|
|
220
|
+
</TooltipProvider>
|
|
221
|
+
|
|
222
|
+
{allowDelete && (
|
|
223
|
+
<TooltipProvider>
|
|
224
|
+
<Tooltip>
|
|
225
|
+
<TooltipTrigger asChild>
|
|
226
|
+
<Button
|
|
227
|
+
variant="ghost"
|
|
228
|
+
size="sm"
|
|
229
|
+
className="h-8 w-8 p-0 text-destructive hover:text-destructive"
|
|
230
|
+
onClick={() => onDelete?.(artifact)}
|
|
231
|
+
>
|
|
232
|
+
<Trash2 className="h-4 w-4" />
|
|
233
|
+
</Button>
|
|
234
|
+
</TooltipTrigger>
|
|
235
|
+
<TooltipContent>Delete</TooltipContent>
|
|
236
|
+
</Tooltip>
|
|
237
|
+
</TooltipProvider>
|
|
238
|
+
)}
|
|
239
|
+
</div>
|
|
240
|
+
</div>
|
|
241
|
+
)
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export function WakaArtifactList({
|
|
245
|
+
artifacts,
|
|
246
|
+
onDownload,
|
|
247
|
+
onDelete,
|
|
248
|
+
onView,
|
|
249
|
+
title = "Artifacts",
|
|
250
|
+
showExpiration = true,
|
|
251
|
+
allowDelete = false,
|
|
252
|
+
className,
|
|
253
|
+
}: WakaArtifactListProps) {
|
|
254
|
+
const [searchQuery, setSearchQuery] = React.useState("")
|
|
255
|
+
const [typeFilter, setTypeFilter] = React.useState<Artifact["type"] | "all">("all")
|
|
256
|
+
|
|
257
|
+
// Filter artifacts
|
|
258
|
+
const filteredArtifacts = React.useMemo(() => {
|
|
259
|
+
return artifacts.filter((artifact) => {
|
|
260
|
+
if (typeFilter !== "all" && artifact.type !== typeFilter) return false
|
|
261
|
+
if (searchQuery) {
|
|
262
|
+
return artifact.name.toLowerCase().includes(searchQuery.toLowerCase())
|
|
263
|
+
}
|
|
264
|
+
return true
|
|
265
|
+
})
|
|
266
|
+
}, [artifacts, typeFilter, searchQuery])
|
|
267
|
+
|
|
268
|
+
// Calculate total size
|
|
269
|
+
const totalSize = artifacts.reduce((acc, a) => acc + a.size, 0)
|
|
270
|
+
|
|
271
|
+
// Count by type
|
|
272
|
+
const typeCounts = React.useMemo(() => {
|
|
273
|
+
return artifacts.reduce((acc, a) => {
|
|
274
|
+
acc[a.type] = (acc[a.type] || 0) + 1
|
|
275
|
+
return acc
|
|
276
|
+
}, {} as Record<string, number>)
|
|
277
|
+
}, [artifacts])
|
|
278
|
+
|
|
279
|
+
return (
|
|
280
|
+
<div className={cn("flex flex-col border rounded-lg bg-background", className)}>
|
|
281
|
+
{/* Header */}
|
|
282
|
+
<div className="flex items-center justify-between gap-4 p-3 border-b">
|
|
283
|
+
<div className="flex items-center gap-3">
|
|
284
|
+
<Package className="h-5 w-5" />
|
|
285
|
+
<h3 className="font-semibold">{title}</h3>
|
|
286
|
+
<Badge variant="secondary">{artifacts.length}</Badge>
|
|
287
|
+
</div>
|
|
288
|
+
|
|
289
|
+
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
|
290
|
+
<HardDrive className="h-4 w-4" />
|
|
291
|
+
Total: {formatBytes(totalSize)}
|
|
292
|
+
</div>
|
|
293
|
+
</div>
|
|
294
|
+
|
|
295
|
+
{/* Toolbar */}
|
|
296
|
+
<div className="flex items-center gap-2 p-2 border-b bg-muted/30">
|
|
297
|
+
<div className="relative flex-1 max-w-sm">
|
|
298
|
+
<Search className="absolute left-2.5 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
|
|
299
|
+
<Input
|
|
300
|
+
placeholder="Search artifacts..."
|
|
301
|
+
value={searchQuery}
|
|
302
|
+
onChange={(e) => setSearchQuery(e.target.value)}
|
|
303
|
+
className="pl-8 h-8"
|
|
304
|
+
/>
|
|
305
|
+
</div>
|
|
306
|
+
|
|
307
|
+
<div className="flex items-center gap-1 flex-wrap">
|
|
308
|
+
<Button
|
|
309
|
+
variant={typeFilter === "all" ? "default" : "ghost"}
|
|
310
|
+
size="sm"
|
|
311
|
+
className="h-7 text-xs"
|
|
312
|
+
onClick={() => setTypeFilter("all")}
|
|
313
|
+
>
|
|
314
|
+
All
|
|
315
|
+
</Button>
|
|
316
|
+
{Object.entries(typeCounts).map(([type, count]) => {
|
|
317
|
+
const config = typeConfig[type as Artifact["type"]]
|
|
318
|
+
const Icon = config.icon
|
|
319
|
+
return (
|
|
320
|
+
<Button
|
|
321
|
+
key={type}
|
|
322
|
+
variant={typeFilter === type ? "default" : "ghost"}
|
|
323
|
+
size="sm"
|
|
324
|
+
className="h-7 text-xs"
|
|
325
|
+
onClick={() => setTypeFilter(type as Artifact["type"])}
|
|
326
|
+
>
|
|
327
|
+
<Icon className={cn("h-3 w-3 mr-1", config.color)} />
|
|
328
|
+
{type} ({count})
|
|
329
|
+
</Button>
|
|
330
|
+
)
|
|
331
|
+
})}
|
|
332
|
+
</div>
|
|
333
|
+
</div>
|
|
334
|
+
|
|
335
|
+
{/* Artifact list */}
|
|
336
|
+
<ScrollArea className="flex-1 max-h-[400px]">
|
|
337
|
+
{filteredArtifacts.length === 0 ? (
|
|
338
|
+
<div className="flex flex-col items-center justify-center h-32 text-muted-foreground">
|
|
339
|
+
<Folder className="h-8 w-8 mb-2" />
|
|
340
|
+
<span>No artifacts found</span>
|
|
341
|
+
</div>
|
|
342
|
+
) : (
|
|
343
|
+
filteredArtifacts.map((artifact) => (
|
|
344
|
+
<ArtifactRow
|
|
345
|
+
key={artifact.id}
|
|
346
|
+
artifact={artifact}
|
|
347
|
+
onDownload={onDownload}
|
|
348
|
+
onDelete={onDelete}
|
|
349
|
+
onView={onView}
|
|
350
|
+
showExpiration={showExpiration}
|
|
351
|
+
allowDelete={allowDelete}
|
|
352
|
+
/>
|
|
353
|
+
))
|
|
354
|
+
)}
|
|
355
|
+
</ScrollArea>
|
|
356
|
+
</div>
|
|
357
|
+
)
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Default sample artifacts for demo
|
|
361
|
+
export const defaultArtifacts: Artifact[] = [
|
|
362
|
+
{
|
|
363
|
+
id: "1",
|
|
364
|
+
name: "build-linux-x64.tar.gz",
|
|
365
|
+
type: "archive",
|
|
366
|
+
size: 45 * 1024 * 1024,
|
|
367
|
+
createdAt: new Date(Date.now() - 2 * 3600000),
|
|
368
|
+
expiresAt: new Date(Date.now() + 7 * 24 * 3600000),
|
|
369
|
+
downloadUrl: "#",
|
|
370
|
+
sha256: "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6",
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
id: "2",
|
|
374
|
+
name: "build-darwin-arm64.tar.gz",
|
|
375
|
+
type: "archive",
|
|
376
|
+
size: 42 * 1024 * 1024,
|
|
377
|
+
createdAt: new Date(Date.now() - 2 * 3600000),
|
|
378
|
+
expiresAt: new Date(Date.now() + 7 * 24 * 3600000),
|
|
379
|
+
downloadUrl: "#",
|
|
380
|
+
sha256: "b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6a1",
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
id: "3",
|
|
384
|
+
name: "test-results.xml",
|
|
385
|
+
type: "report",
|
|
386
|
+
size: 256 * 1024,
|
|
387
|
+
createdAt: new Date(Date.now() - 2 * 3600000),
|
|
388
|
+
downloadUrl: "#",
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
id: "4",
|
|
392
|
+
name: "coverage-report.html",
|
|
393
|
+
type: "report",
|
|
394
|
+
size: 1.2 * 1024 * 1024,
|
|
395
|
+
createdAt: new Date(Date.now() - 2 * 3600000),
|
|
396
|
+
downloadUrl: "#",
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
id: "5",
|
|
400
|
+
name: "build.log",
|
|
401
|
+
type: "log",
|
|
402
|
+
size: 512 * 1024,
|
|
403
|
+
createdAt: new Date(Date.now() - 2 * 3600000),
|
|
404
|
+
downloadUrl: "#",
|
|
405
|
+
},
|
|
406
|
+
{
|
|
407
|
+
id: "6",
|
|
408
|
+
name: "docker-image.tar",
|
|
409
|
+
type: "image",
|
|
410
|
+
size: 250 * 1024 * 1024,
|
|
411
|
+
createdAt: new Date(Date.now() - 2 * 3600000),
|
|
412
|
+
expiresAt: new Date(Date.now() + 12 * 3600000), // Expiring soon
|
|
413
|
+
downloadUrl: "#",
|
|
414
|
+
sha256: "c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6a1b2",
|
|
415
|
+
},
|
|
416
|
+
]
|
|
@@ -55,41 +55,42 @@ export interface WakaBadgeShowcaseProps {
|
|
|
55
55
|
// Rarity Configuration
|
|
56
56
|
// ============================================================================
|
|
57
57
|
|
|
58
|
+
// Rarity configuration using CSS variables for theme support
|
|
58
59
|
const rarityConfig = {
|
|
59
60
|
common: {
|
|
60
61
|
gradient: "from-slate-400 to-slate-500",
|
|
61
|
-
glow: "
|
|
62
|
+
glow: "hsl(var(--muted-foreground))",
|
|
62
63
|
border: "border-slate-400",
|
|
63
64
|
bg: "bg-slate-100 dark:bg-slate-800",
|
|
64
65
|
text: "text-slate-600 dark:text-slate-300",
|
|
65
|
-
shine: "
|
|
66
|
+
shine: "hsl(var(--muted-foreground) / 0.6)",
|
|
66
67
|
label: "Common",
|
|
67
68
|
},
|
|
68
69
|
rare: {
|
|
69
70
|
gradient: "from-blue-400 to-blue-600",
|
|
70
|
-
glow: "
|
|
71
|
+
glow: "hsl(var(--info))",
|
|
71
72
|
border: "border-blue-400",
|
|
72
73
|
bg: "bg-blue-100 dark:bg-blue-900",
|
|
73
74
|
text: "text-blue-600 dark:text-blue-300",
|
|
74
|
-
shine: "
|
|
75
|
+
shine: "hsl(var(--info) / 0.6)",
|
|
75
76
|
label: "Rare",
|
|
76
77
|
},
|
|
77
78
|
epic: {
|
|
78
79
|
gradient: "from-purple-400 to-purple-600",
|
|
79
|
-
glow: "
|
|
80
|
+
glow: "hsl(var(--chart-3))",
|
|
80
81
|
border: "border-purple-400",
|
|
81
82
|
bg: "bg-purple-100 dark:bg-purple-900",
|
|
82
83
|
text: "text-purple-600 dark:text-purple-300",
|
|
83
|
-
shine: "
|
|
84
|
+
shine: "hsl(var(--chart-3) / 0.6)",
|
|
84
85
|
label: "Epic",
|
|
85
86
|
},
|
|
86
87
|
legendary: {
|
|
87
88
|
gradient: "from-amber-400 via-orange-500 to-red-500",
|
|
88
|
-
glow: "
|
|
89
|
+
glow: "hsl(var(--warning))",
|
|
89
90
|
border: "border-amber-400",
|
|
90
91
|
bg: "bg-amber-100 dark:bg-amber-900",
|
|
91
92
|
text: "text-amber-600 dark:text-amber-300",
|
|
92
|
-
shine: "
|
|
93
|
+
shine: "hsl(var(--warning) / 0.8)",
|
|
93
94
|
label: "Legendary",
|
|
94
95
|
},
|
|
95
96
|
}
|
|
@@ -195,9 +196,9 @@ function NewBadgeIndicator() {
|
|
|
195
196
|
<>
|
|
196
197
|
<div className="absolute -top-1 -right-1 z-20">
|
|
197
198
|
<span className="relative flex h-4 w-4">
|
|
198
|
-
<span className="animate-badge-ping absolute inline-flex h-full w-full rounded-full bg-
|
|
199
|
-
<span className="relative inline-flex rounded-full h-4 w-4 bg-
|
|
200
|
-
<span className="text-[8px] font-bold text-
|
|
199
|
+
<span className="animate-badge-ping absolute inline-flex h-full w-full rounded-full bg-success opacity-75" />
|
|
200
|
+
<span className="relative inline-flex rounded-full h-4 w-4 bg-success items-center justify-center">
|
|
201
|
+
<span className="text-[8px] font-bold text-success-foreground">!</span>
|
|
201
202
|
</span>
|
|
202
203
|
</span>
|
|
203
204
|
</div>
|