@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,386 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { cn } from "../../utils/cn"
|
|
5
|
+
import { Button } from "../button"
|
|
6
|
+
import { Input } from "../input"
|
|
7
|
+
import { Badge } from "../badge"
|
|
8
|
+
import { ScrollArea } from "../scroll-area"
|
|
9
|
+
import {
|
|
10
|
+
Select,
|
|
11
|
+
SelectContent,
|
|
12
|
+
SelectItem,
|
|
13
|
+
SelectTrigger,
|
|
14
|
+
SelectValue,
|
|
15
|
+
} from "../select"
|
|
16
|
+
import {
|
|
17
|
+
Search,
|
|
18
|
+
Filter,
|
|
19
|
+
Download,
|
|
20
|
+
Pause,
|
|
21
|
+
Play,
|
|
22
|
+
Trash2,
|
|
23
|
+
ChevronDown,
|
|
24
|
+
ChevronRight,
|
|
25
|
+
AlertCircle,
|
|
26
|
+
AlertTriangle,
|
|
27
|
+
Info,
|
|
28
|
+
Bug,
|
|
29
|
+
Clock,
|
|
30
|
+
RefreshCw,
|
|
31
|
+
} from "lucide-react"
|
|
32
|
+
|
|
33
|
+
export type LogLevel = "error" | "warn" | "info" | "debug" | "trace"
|
|
34
|
+
|
|
35
|
+
export interface LogEntry {
|
|
36
|
+
id: string
|
|
37
|
+
timestamp: Date
|
|
38
|
+
level: LogLevel
|
|
39
|
+
message: string
|
|
40
|
+
source?: string
|
|
41
|
+
metadata?: Record<string, unknown>
|
|
42
|
+
stackTrace?: string
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface WakaLogViewerProps {
|
|
46
|
+
/** Log entries to display */
|
|
47
|
+
logs: LogEntry[]
|
|
48
|
+
/** Callback when requesting more logs */
|
|
49
|
+
onLoadMore?: () => void
|
|
50
|
+
/** Callback when clearing logs */
|
|
51
|
+
onClear?: () => void
|
|
52
|
+
/** Callback when exporting logs */
|
|
53
|
+
onExport?: (logs: LogEntry[]) => void
|
|
54
|
+
/** Whether streaming is active */
|
|
55
|
+
isStreaming?: boolean
|
|
56
|
+
/** Callback to toggle streaming */
|
|
57
|
+
onToggleStreaming?: () => void
|
|
58
|
+
/** Maximum number of logs to display */
|
|
59
|
+
maxLogs?: number
|
|
60
|
+
/** Show timestamp */
|
|
61
|
+
showTimestamp?: boolean
|
|
62
|
+
/** Show source */
|
|
63
|
+
showSource?: boolean
|
|
64
|
+
/** Enable auto-scroll to bottom */
|
|
65
|
+
autoScroll?: boolean
|
|
66
|
+
/** Custom class name */
|
|
67
|
+
className?: string
|
|
68
|
+
/** Title */
|
|
69
|
+
title?: string
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const levelConfig: Record<LogLevel, { icon: React.ElementType; color: string; bgColor: string }> = {
|
|
73
|
+
error: { icon: AlertCircle, color: "text-red-500", bgColor: "bg-red-500/10" },
|
|
74
|
+
warn: { icon: AlertTriangle, color: "text-yellow-500", bgColor: "bg-yellow-500/10" },
|
|
75
|
+
info: { icon: Info, color: "text-blue-500", bgColor: "bg-blue-500/10" },
|
|
76
|
+
debug: { icon: Bug, color: "text-purple-500", bgColor: "bg-purple-500/10" },
|
|
77
|
+
trace: { icon: Clock, color: "text-gray-500", bgColor: "bg-gray-500/10" },
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function LogEntryRow({
|
|
81
|
+
entry,
|
|
82
|
+
showTimestamp,
|
|
83
|
+
showSource,
|
|
84
|
+
isExpanded,
|
|
85
|
+
onToggleExpand,
|
|
86
|
+
}: {
|
|
87
|
+
entry: LogEntry
|
|
88
|
+
showTimestamp: boolean
|
|
89
|
+
showSource: boolean
|
|
90
|
+
isExpanded: boolean
|
|
91
|
+
onToggleExpand: () => void
|
|
92
|
+
}) {
|
|
93
|
+
const config = levelConfig[entry.level]
|
|
94
|
+
const Icon = config.icon
|
|
95
|
+
const hasDetails = entry.metadata || entry.stackTrace
|
|
96
|
+
|
|
97
|
+
return (
|
|
98
|
+
<div className={cn("border-b border-border/50 hover:bg-muted/30 transition-colors", config.bgColor)}>
|
|
99
|
+
<div
|
|
100
|
+
className={cn(
|
|
101
|
+
"flex items-start gap-2 px-3 py-2 font-mono text-sm",
|
|
102
|
+
hasDetails && "cursor-pointer"
|
|
103
|
+
)}
|
|
104
|
+
onClick={hasDetails ? onToggleExpand : undefined}
|
|
105
|
+
>
|
|
106
|
+
{hasDetails && (
|
|
107
|
+
<button className="mt-0.5 text-muted-foreground hover:text-foreground">
|
|
108
|
+
{isExpanded ? <ChevronDown className="h-4 w-4" /> : <ChevronRight className="h-4 w-4" />}
|
|
109
|
+
</button>
|
|
110
|
+
)}
|
|
111
|
+
|
|
112
|
+
<Icon className={cn("h-4 w-4 mt-0.5 shrink-0", config.color)} />
|
|
113
|
+
|
|
114
|
+
{showTimestamp && (
|
|
115
|
+
<span className="text-muted-foreground shrink-0 text-xs">
|
|
116
|
+
{entry.timestamp.toLocaleTimeString("fr-FR", {
|
|
117
|
+
hour: "2-digit",
|
|
118
|
+
minute: "2-digit",
|
|
119
|
+
second: "2-digit",
|
|
120
|
+
})}.{entry.timestamp.getMilliseconds().toString().padStart(3, '0')}
|
|
121
|
+
</span>
|
|
122
|
+
)}
|
|
123
|
+
|
|
124
|
+
<Badge variant="outline" className={cn("shrink-0 uppercase text-xs", config.color)}>
|
|
125
|
+
{entry.level}
|
|
126
|
+
</Badge>
|
|
127
|
+
|
|
128
|
+
{showSource && entry.source && (
|
|
129
|
+
<span className="text-muted-foreground shrink-0">[{entry.source}]</span>
|
|
130
|
+
)}
|
|
131
|
+
|
|
132
|
+
<span className="flex-1 break-all whitespace-pre-wrap">{entry.message}</span>
|
|
133
|
+
</div>
|
|
134
|
+
|
|
135
|
+
{isExpanded && hasDetails && (
|
|
136
|
+
<div className="px-3 pb-3 pl-10 space-y-2">
|
|
137
|
+
{entry.metadata && (
|
|
138
|
+
<div className="bg-muted/50 rounded p-2 font-mono text-xs">
|
|
139
|
+
<pre className="overflow-x-auto">
|
|
140
|
+
{JSON.stringify(entry.metadata, null, 2)}
|
|
141
|
+
</pre>
|
|
142
|
+
</div>
|
|
143
|
+
)}
|
|
144
|
+
{entry.stackTrace && (
|
|
145
|
+
<div className="bg-red-500/5 border border-red-500/20 rounded p-2 font-mono text-xs text-red-400">
|
|
146
|
+
<pre className="overflow-x-auto whitespace-pre-wrap">{entry.stackTrace}</pre>
|
|
147
|
+
</div>
|
|
148
|
+
)}
|
|
149
|
+
</div>
|
|
150
|
+
)}
|
|
151
|
+
</div>
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function WakaLogViewer({
|
|
156
|
+
logs,
|
|
157
|
+
onLoadMore,
|
|
158
|
+
onClear,
|
|
159
|
+
onExport,
|
|
160
|
+
isStreaming = false,
|
|
161
|
+
onToggleStreaming,
|
|
162
|
+
maxLogs = 1000,
|
|
163
|
+
showTimestamp = true,
|
|
164
|
+
showSource = true,
|
|
165
|
+
autoScroll = true,
|
|
166
|
+
className,
|
|
167
|
+
title = "Logs",
|
|
168
|
+
}: WakaLogViewerProps) {
|
|
169
|
+
const [searchQuery, setSearchQuery] = React.useState("")
|
|
170
|
+
const [levelFilter, setLevelFilter] = React.useState<LogLevel | "all">("all")
|
|
171
|
+
const [expandedIds, setExpandedIds] = React.useState<Set<string>>(new Set())
|
|
172
|
+
const scrollRef = React.useRef<HTMLDivElement>(null)
|
|
173
|
+
|
|
174
|
+
// Filter logs
|
|
175
|
+
const filteredLogs = React.useMemo(() => {
|
|
176
|
+
return logs
|
|
177
|
+
.filter(log => {
|
|
178
|
+
if (levelFilter !== "all" && log.level !== levelFilter) return false
|
|
179
|
+
if (searchQuery) {
|
|
180
|
+
const query = searchQuery.toLowerCase()
|
|
181
|
+
return (
|
|
182
|
+
log.message.toLowerCase().includes(query) ||
|
|
183
|
+
log.source?.toLowerCase().includes(query) ||
|
|
184
|
+
JSON.stringify(log.metadata).toLowerCase().includes(query)
|
|
185
|
+
)
|
|
186
|
+
}
|
|
187
|
+
return true
|
|
188
|
+
})
|
|
189
|
+
.slice(-maxLogs)
|
|
190
|
+
}, [logs, levelFilter, searchQuery, maxLogs])
|
|
191
|
+
|
|
192
|
+
// Auto-scroll to bottom
|
|
193
|
+
React.useEffect(() => {
|
|
194
|
+
if (autoScroll && scrollRef.current) {
|
|
195
|
+
scrollRef.current.scrollTop = scrollRef.current.scrollHeight
|
|
196
|
+
}
|
|
197
|
+
}, [filteredLogs, autoScroll])
|
|
198
|
+
|
|
199
|
+
const toggleExpand = (id: string) => {
|
|
200
|
+
setExpandedIds(prev => {
|
|
201
|
+
const next = new Set(prev)
|
|
202
|
+
if (next.has(id)) {
|
|
203
|
+
next.delete(id)
|
|
204
|
+
} else {
|
|
205
|
+
next.add(id)
|
|
206
|
+
}
|
|
207
|
+
return next
|
|
208
|
+
})
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Count by level
|
|
212
|
+
const levelCounts = React.useMemo(() => {
|
|
213
|
+
return logs.reduce((acc, log) => {
|
|
214
|
+
acc[log.level] = (acc[log.level] || 0) + 1
|
|
215
|
+
return acc
|
|
216
|
+
}, {} as Record<LogLevel, number>)
|
|
217
|
+
}, [logs])
|
|
218
|
+
|
|
219
|
+
return (
|
|
220
|
+
<div className={cn("flex flex-col h-full border rounded-lg bg-background", className)}>
|
|
221
|
+
{/* Header */}
|
|
222
|
+
<div className="flex items-center justify-between gap-4 p-3 border-b">
|
|
223
|
+
<div className="flex items-center gap-2">
|
|
224
|
+
<h3 className="font-semibold">{title}</h3>
|
|
225
|
+
<Badge variant="secondary">{filteredLogs.length}</Badge>
|
|
226
|
+
{isStreaming && (
|
|
227
|
+
<Badge variant="default" className="bg-green-500 animate-pulse">
|
|
228
|
+
Live
|
|
229
|
+
</Badge>
|
|
230
|
+
)}
|
|
231
|
+
</div>
|
|
232
|
+
|
|
233
|
+
<div className="flex items-center gap-2">
|
|
234
|
+
{/* Level counts */}
|
|
235
|
+
<div className="hidden md:flex items-center gap-1">
|
|
236
|
+
{(["error", "warn", "info", "debug"] as LogLevel[]).map(level => {
|
|
237
|
+
const config = levelConfig[level]
|
|
238
|
+
const count = levelCounts[level] || 0
|
|
239
|
+
return (
|
|
240
|
+
<Badge
|
|
241
|
+
key={level}
|
|
242
|
+
variant="outline"
|
|
243
|
+
className={cn("text-xs cursor-pointer", config.color)}
|
|
244
|
+
onClick={() => setLevelFilter(levelFilter === level ? "all" : level)}
|
|
245
|
+
>
|
|
246
|
+
{level}: {count}
|
|
247
|
+
</Badge>
|
|
248
|
+
)
|
|
249
|
+
})}
|
|
250
|
+
</div>
|
|
251
|
+
</div>
|
|
252
|
+
</div>
|
|
253
|
+
|
|
254
|
+
{/* Toolbar */}
|
|
255
|
+
<div className="flex items-center gap-2 p-2 border-b bg-muted/30">
|
|
256
|
+
<div className="relative flex-1 max-w-sm">
|
|
257
|
+
<Search className="absolute left-2.5 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
|
|
258
|
+
<Input
|
|
259
|
+
placeholder="Rechercher..."
|
|
260
|
+
value={searchQuery}
|
|
261
|
+
onChange={(e) => setSearchQuery(e.target.value)}
|
|
262
|
+
className="pl-8 h-8"
|
|
263
|
+
/>
|
|
264
|
+
</div>
|
|
265
|
+
|
|
266
|
+
<Select value={levelFilter} onValueChange={(v) => setLevelFilter(v as LogLevel | "all")}>
|
|
267
|
+
<SelectTrigger className="w-[120px] h-8">
|
|
268
|
+
<Filter className="h-4 w-4 mr-2" />
|
|
269
|
+
<SelectValue placeholder="Niveau" />
|
|
270
|
+
</SelectTrigger>
|
|
271
|
+
<SelectContent>
|
|
272
|
+
<SelectItem value="all">Tous</SelectItem>
|
|
273
|
+
<SelectItem value="error">Error</SelectItem>
|
|
274
|
+
<SelectItem value="warn">Warn</SelectItem>
|
|
275
|
+
<SelectItem value="info">Info</SelectItem>
|
|
276
|
+
<SelectItem value="debug">Debug</SelectItem>
|
|
277
|
+
<SelectItem value="trace">Trace</SelectItem>
|
|
278
|
+
</SelectContent>
|
|
279
|
+
</Select>
|
|
280
|
+
|
|
281
|
+
<div className="flex items-center gap-1">
|
|
282
|
+
{onToggleStreaming && (
|
|
283
|
+
<Button
|
|
284
|
+
variant="ghost"
|
|
285
|
+
size="sm"
|
|
286
|
+
onClick={onToggleStreaming}
|
|
287
|
+
className="h-8"
|
|
288
|
+
>
|
|
289
|
+
{isStreaming ? <Pause className="h-4 w-4" /> : <Play className="h-4 w-4" />}
|
|
290
|
+
</Button>
|
|
291
|
+
)}
|
|
292
|
+
|
|
293
|
+
{onLoadMore && (
|
|
294
|
+
<Button variant="ghost" size="sm" onClick={onLoadMore} className="h-8">
|
|
295
|
+
<RefreshCw className="h-4 w-4" />
|
|
296
|
+
</Button>
|
|
297
|
+
)}
|
|
298
|
+
|
|
299
|
+
{onExport && (
|
|
300
|
+
<Button
|
|
301
|
+
variant="ghost"
|
|
302
|
+
size="sm"
|
|
303
|
+
onClick={() => onExport(filteredLogs)}
|
|
304
|
+
className="h-8"
|
|
305
|
+
>
|
|
306
|
+
<Download className="h-4 w-4" />
|
|
307
|
+
</Button>
|
|
308
|
+
)}
|
|
309
|
+
|
|
310
|
+
{onClear && (
|
|
311
|
+
<Button variant="ghost" size="sm" onClick={onClear} className="h-8 text-destructive">
|
|
312
|
+
<Trash2 className="h-4 w-4" />
|
|
313
|
+
</Button>
|
|
314
|
+
)}
|
|
315
|
+
</div>
|
|
316
|
+
</div>
|
|
317
|
+
|
|
318
|
+
{/* Log entries */}
|
|
319
|
+
<ScrollArea ref={scrollRef} className="flex-1">
|
|
320
|
+
<div className="min-w-max">
|
|
321
|
+
{filteredLogs.length === 0 ? (
|
|
322
|
+
<div className="flex items-center justify-center h-32 text-muted-foreground">
|
|
323
|
+
Aucun log à afficher
|
|
324
|
+
</div>
|
|
325
|
+
) : (
|
|
326
|
+
filteredLogs.map(entry => (
|
|
327
|
+
<LogEntryRow
|
|
328
|
+
key={entry.id}
|
|
329
|
+
entry={entry}
|
|
330
|
+
showTimestamp={showTimestamp}
|
|
331
|
+
showSource={showSource}
|
|
332
|
+
isExpanded={expandedIds.has(entry.id)}
|
|
333
|
+
onToggleExpand={() => toggleExpand(entry.id)}
|
|
334
|
+
/>
|
|
335
|
+
))
|
|
336
|
+
)}
|
|
337
|
+
</div>
|
|
338
|
+
</ScrollArea>
|
|
339
|
+
</div>
|
|
340
|
+
)
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Default sample logs for demo
|
|
344
|
+
export const defaultLogs: LogEntry[] = [
|
|
345
|
+
{
|
|
346
|
+
id: "1",
|
|
347
|
+
timestamp: new Date(),
|
|
348
|
+
level: "info",
|
|
349
|
+
message: "Application started successfully",
|
|
350
|
+
source: "main",
|
|
351
|
+
},
|
|
352
|
+
{
|
|
353
|
+
id: "2",
|
|
354
|
+
timestamp: new Date(),
|
|
355
|
+
level: "debug",
|
|
356
|
+
message: "Loading configuration from /etc/app/config.yaml",
|
|
357
|
+
source: "config",
|
|
358
|
+
metadata: { path: "/etc/app/config.yaml", format: "yaml" },
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
id: "3",
|
|
362
|
+
timestamp: new Date(),
|
|
363
|
+
level: "warn",
|
|
364
|
+
message: "Deprecated API version detected, please upgrade to v2",
|
|
365
|
+
source: "api",
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
id: "4",
|
|
369
|
+
timestamp: new Date(),
|
|
370
|
+
level: "error",
|
|
371
|
+
message: "Failed to connect to database",
|
|
372
|
+
source: "db",
|
|
373
|
+
metadata: { host: "localhost", port: 5432 },
|
|
374
|
+
stackTrace: `Error: Connection refused
|
|
375
|
+
at PostgresClient.connect (/app/node_modules/pg/lib/client.js:123:15)
|
|
376
|
+
at async DatabaseService.init (/app/src/services/database.ts:45:5)
|
|
377
|
+
at async bootstrap (/app/src/main.ts:12:3)`,
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
id: "5",
|
|
381
|
+
timestamp: new Date(),
|
|
382
|
+
level: "info",
|
|
383
|
+
message: "Retry connection attempt 1/3",
|
|
384
|
+
source: "db",
|
|
385
|
+
},
|
|
386
|
+
]
|
|
@@ -102,46 +102,46 @@ const rarityConfig = {
|
|
|
102
102
|
common: {
|
|
103
103
|
gradient: "from-slate-400 to-slate-600",
|
|
104
104
|
glow: "shadow-slate-400/50",
|
|
105
|
-
glowColor: "
|
|
105
|
+
glowColor: "hsl(var(--muted-foreground))",
|
|
106
106
|
borderColor: "border-slate-400",
|
|
107
|
-
bgColor: "bg-slate-100",
|
|
108
|
-
textColor: "text-slate-600",
|
|
109
|
-
particleColors: ["
|
|
107
|
+
bgColor: "bg-slate-100 dark:bg-slate-900",
|
|
108
|
+
textColor: "text-slate-600 dark:text-slate-400",
|
|
109
|
+
particleColors: ["hsl(var(--muted-foreground))", "hsl(var(--muted))", "hsl(var(--border))"],
|
|
110
110
|
label: "Common",
|
|
111
|
-
beamColor: "
|
|
111
|
+
beamColor: "hsl(var(--muted-foreground) / 0.8)",
|
|
112
112
|
},
|
|
113
113
|
rare: {
|
|
114
114
|
gradient: "from-blue-400 to-blue-600",
|
|
115
115
|
glow: "shadow-blue-400/50",
|
|
116
|
-
glowColor: "
|
|
116
|
+
glowColor: "hsl(var(--info))",
|
|
117
117
|
borderColor: "border-blue-400",
|
|
118
|
-
bgColor: "bg-blue-100",
|
|
119
|
-
textColor: "text-blue-600",
|
|
120
|
-
particleColors: ["
|
|
118
|
+
bgColor: "bg-blue-100 dark:bg-blue-950",
|
|
119
|
+
textColor: "text-blue-600 dark:text-blue-400",
|
|
120
|
+
particleColors: ["hsl(var(--info))", "hsl(var(--chart-1))", "hsl(var(--primary))"],
|
|
121
121
|
label: "Rare",
|
|
122
|
-
beamColor: "
|
|
122
|
+
beamColor: "hsl(var(--info) / 0.8)",
|
|
123
123
|
},
|
|
124
124
|
epic: {
|
|
125
125
|
gradient: "from-purple-400 to-purple-600",
|
|
126
126
|
glow: "shadow-purple-400/50",
|
|
127
|
-
glowColor: "
|
|
127
|
+
glowColor: "hsl(var(--chart-2))",
|
|
128
128
|
borderColor: "border-purple-400",
|
|
129
|
-
bgColor: "bg-purple-100",
|
|
130
|
-
textColor: "text-purple-600",
|
|
131
|
-
particleColors: ["
|
|
129
|
+
bgColor: "bg-purple-100 dark:bg-purple-950",
|
|
130
|
+
textColor: "text-purple-600 dark:text-purple-400",
|
|
131
|
+
particleColors: ["hsl(var(--chart-2))", "hsl(var(--chart-3))", "hsl(var(--primary))"],
|
|
132
132
|
label: "Epic",
|
|
133
|
-
beamColor: "
|
|
133
|
+
beamColor: "hsl(var(--chart-2) / 0.8)",
|
|
134
134
|
},
|
|
135
135
|
legendary: {
|
|
136
136
|
gradient: "from-amber-400 via-orange-500 to-red-500",
|
|
137
137
|
glow: "shadow-amber-400/50",
|
|
138
|
-
glowColor: "
|
|
138
|
+
glowColor: "hsl(var(--warning))",
|
|
139
139
|
borderColor: "border-amber-400",
|
|
140
|
-
bgColor: "bg-amber-100",
|
|
141
|
-
textColor: "text-amber-600",
|
|
142
|
-
particleColors: ["
|
|
140
|
+
bgColor: "bg-amber-100 dark:bg-amber-950",
|
|
141
|
+
textColor: "text-amber-600 dark:text-amber-400",
|
|
142
|
+
particleColors: ["hsl(var(--warning))", "hsl(var(--chart-4))", "hsl(var(--destructive))", "hsl(var(--chart-5))"],
|
|
143
143
|
label: "Legendary",
|
|
144
|
-
beamColor: "
|
|
144
|
+
beamColor: "hsl(var(--warning) / 0.9)",
|
|
145
145
|
},
|
|
146
146
|
}
|
|
147
147
|
|