@moontra/moonui-pro 2.20.2 → 2.20.4
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/package.json +8 -3
- package/plugin/index.d.ts +86 -0
- package/plugin/index.js +308 -0
- package/scripts/postinstall.js +191 -23
- package/src/components/advanced-chart/index.tsx +0 -1246
- package/src/components/advanced-forms/index.tsx +0 -585
- package/src/components/animated-button/index.tsx +0 -385
- package/src/components/calendar/event-dialog.tsx +0 -377
- package/src/components/calendar/index.tsx +0 -1220
- package/src/components/calendar-pro/index.tsx +0 -1697
- package/src/components/color-picker/index.tsx +0 -432
- package/src/components/credit-card-input/index.tsx +0 -406
- package/src/components/dashboard/dashboard-grid.tsx +0 -480
- package/src/components/dashboard/demo.tsx +0 -425
- package/src/components/dashboard/index.tsx +0 -1046
- package/src/components/dashboard/time-range-picker.tsx +0 -336
- package/src/components/dashboard/types.ts +0 -225
- package/src/components/dashboard/widgets/activity-feed.tsx +0 -349
- package/src/components/dashboard/widgets/chart-widget.tsx +0 -418
- package/src/components/dashboard/widgets/comparison-widget.tsx +0 -177
- package/src/components/dashboard/widgets/index.ts +0 -5
- package/src/components/dashboard/widgets/metric-card.tsx +0 -363
- package/src/components/dashboard/widgets/progress-widget.tsx +0 -113
- package/src/components/data-table/data-table-bulk-actions.tsx +0 -204
- package/src/components/data-table/data-table-column-toggle.tsx +0 -169
- package/src/components/data-table/data-table-export.ts +0 -156
- package/src/components/data-table/data-table-filter-drawer.tsx +0 -448
- package/src/components/data-table/index.tsx +0 -845
- package/src/components/draggable-list/index.tsx +0 -100
- package/src/components/error-boundary/index.tsx +0 -232
- package/src/components/file-upload/index.tsx +0 -1660
- package/src/components/floating-action-button/index.tsx +0 -206
- package/src/components/form-wizard/form-wizard-context.tsx +0 -335
- package/src/components/form-wizard/form-wizard-navigation.tsx +0 -118
- package/src/components/form-wizard/form-wizard-progress.tsx +0 -329
- package/src/components/form-wizard/form-wizard-step.tsx +0 -111
- package/src/components/form-wizard/index.tsx +0 -102
- package/src/components/form-wizard/types.ts +0 -77
- package/src/components/gesture-drawer/index.tsx +0 -551
- package/src/components/github-stars/github-api.ts +0 -426
- package/src/components/github-stars/hooks.ts +0 -517
- package/src/components/github-stars/index.tsx +0 -375
- package/src/components/github-stars/types.ts +0 -148
- package/src/components/github-stars/variants.tsx +0 -515
- package/src/components/health-check/index.tsx +0 -439
- package/src/components/hover-card-3d/index.tsx +0 -529
- package/src/components/index.ts +0 -130
- package/src/components/internal/index.ts +0 -78
- package/src/components/kanban/add-card-modal.tsx +0 -502
- package/src/components/kanban/card-detail-modal.tsx +0 -761
- package/src/components/kanban/index.ts +0 -13
- package/src/components/kanban/kanban.tsx +0 -1689
- package/src/components/kanban/types.ts +0 -168
- package/src/components/lazy-component/index.tsx +0 -823
- package/src/components/license-error/index.tsx +0 -31
- package/src/components/magnetic-button/index.tsx +0 -216
- package/src/components/memory-efficient-data/index.tsx +0 -1018
- package/src/components/moonui-quiz-form/index.tsx +0 -817
- package/src/components/navbar/index.tsx +0 -781
- package/src/components/optimized-image/index.tsx +0 -425
- package/src/components/performance-debugger/index.tsx +0 -613
- package/src/components/performance-monitor/index.tsx +0 -808
- package/src/components/phone-number-input/index.tsx +0 -343
- package/src/components/phone-number-input/phone-number-input-simple.tsx +0 -167
- package/src/components/pinch-zoom/index.tsx +0 -566
- package/src/components/quiz-form/index.tsx +0 -479
- package/src/components/rich-text-editor/index.tsx +0 -2322
- package/src/components/rich-text-editor/slash-commands-extension.ts +0 -230
- package/src/components/rich-text-editor/slash-commands.css +0 -35
- package/src/components/rich-text-editor/table-styles.css +0 -65
- package/src/components/sidebar/index.tsx +0 -884
- package/src/components/spotlight-card/index.tsx +0 -191
- package/src/components/swipeable-card/index.tsx +0 -100
- package/src/components/timeline/index.tsx +0 -1183
- package/src/components/ui/accordion.tsx +0 -581
- package/src/components/ui/alert-dialog.tsx +0 -141
- package/src/components/ui/alert.tsx +0 -141
- package/src/components/ui/aspect-ratio.tsx +0 -245
- package/src/components/ui/avatar.tsx +0 -155
- package/src/components/ui/badge.tsx +0 -230
- package/src/components/ui/breadcrumb.tsx +0 -216
- package/src/components/ui/button.tsx +0 -228
- package/src/components/ui/calendar.tsx +0 -387
- package/src/components/ui/card.tsx +0 -216
- package/src/components/ui/checkbox.tsx +0 -259
- package/src/components/ui/collapsible.tsx +0 -631
- package/src/components/ui/color-picker.tsx +0 -97
- package/src/components/ui/command.tsx +0 -948
- package/src/components/ui/dialog.tsx +0 -752
- package/src/components/ui/dropdown-menu.tsx +0 -706
- package/src/components/ui/gesture-drawer.tsx +0 -11
- package/src/components/ui/hover-card.tsx +0 -29
- package/src/components/ui/index.ts +0 -222
- package/src/components/ui/input.tsx +0 -224
- package/src/components/ui/label.tsx +0 -29
- package/src/components/ui/lightbox.tsx +0 -606
- package/src/components/ui/magnetic-button.tsx +0 -129
- package/src/components/ui/media-gallery.tsx +0 -611
- package/src/components/ui/navigation-menu.tsx +0 -130
- package/src/components/ui/pagination.tsx +0 -125
- package/src/components/ui/popover.tsx +0 -185
- package/src/components/ui/progress.tsx +0 -30
- package/src/components/ui/radio-group.tsx +0 -257
- package/src/components/ui/scroll-area.tsx +0 -47
- package/src/components/ui/select.tsx +0 -378
- package/src/components/ui/separator.tsx +0 -145
- package/src/components/ui/sheet.tsx +0 -139
- package/src/components/ui/skeleton.tsx +0 -20
- package/src/components/ui/slider.tsx +0 -354
- package/src/components/ui/spotlight-card.tsx +0 -119
- package/src/components/ui/switch.tsx +0 -86
- package/src/components/ui/table.tsx +0 -331
- package/src/components/ui/tabs-pro.tsx +0 -542
- package/src/components/ui/tabs.tsx +0 -54
- package/src/components/ui/textarea.tsx +0 -28
- package/src/components/ui/toast.tsx +0 -317
- package/src/components/ui/toggle.tsx +0 -119
- package/src/components/ui/tooltip.tsx +0 -151
- package/src/components/virtual-list/index.tsx +0 -668
- package/src/hooks/use-chart.ts +0 -205
- package/src/hooks/use-data-table.ts +0 -182
- package/src/hooks/use-docs-pro-access.ts +0 -13
- package/src/hooks/use-license-check.ts +0 -65
- package/src/hooks/use-subscription.ts +0 -19
- package/src/hooks/use-toast.ts +0 -15
- package/src/index.ts +0 -22
- package/src/lib/ai-providers.ts +0 -377
- package/src/lib/component-metadata.ts +0 -18
- package/src/lib/micro-interactions.ts +0 -255
- package/src/lib/paddle.ts +0 -17
- package/src/lib/utils.ts +0 -6
- package/src/patterns/login-form/index.tsx +0 -276
- package/src/patterns/login-form/types.ts +0 -67
- package/src/setupTests.ts +0 -41
- package/src/styles/advanced-chart.css +0 -239
- package/src/styles/calendar.css +0 -35
- package/src/styles/design-system.css +0 -363
- package/src/styles/index.css +0 -681
- package/src/styles/tailwind.css +0 -7
- package/src/styles/tokens.css +0 -455
- package/src/types/next-auth.d.ts +0 -21
- package/src/use-intersection-observer.tsx +0 -154
- package/src/use-local-storage.tsx +0 -71
- package/src/use-paddle.ts +0 -138
- package/src/use-performance-optimizer.ts +0 -389
- package/src/use-pro-access.ts +0 -141
- package/src/use-scroll-animation.ts +0 -219
- package/src/use-subscription.ts +0 -37
- package/src/use-toast.ts +0 -32
- package/src/utils/chart-helpers.ts +0 -357
- package/src/utils/cn.ts +0 -6
- package/src/utils/data-processing.ts +0 -151
- package/src/utils/license-validator.tsx +0 -183
|
@@ -1,439 +0,0 @@
|
|
|
1
|
-
"use client"
|
|
2
|
-
|
|
3
|
-
import React, { useState, useEffect, useCallback } from "react"
|
|
4
|
-
import { motion, AnimatePresence } from "framer-motion"
|
|
5
|
-
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../ui/card"
|
|
6
|
-
import { Button } from "../ui/button"
|
|
7
|
-
import { MoonUIBadgePro as Badge } from "../ui/badge"
|
|
8
|
-
import { Progress } from "../ui/progress"
|
|
9
|
-
import { cn } from "../../lib/utils"
|
|
10
|
-
import {
|
|
11
|
-
Activity,
|
|
12
|
-
CheckCircle,
|
|
13
|
-
XCircle,
|
|
14
|
-
AlertCircle,
|
|
15
|
-
Clock,
|
|
16
|
-
Zap,
|
|
17
|
-
Globe,
|
|
18
|
-
Database,
|
|
19
|
-
Server,
|
|
20
|
-
Lock,
|
|
21
|
-
Sparkles,
|
|
22
|
-
RefreshCw,
|
|
23
|
-
TrendingUp,
|
|
24
|
-
Timer
|
|
25
|
-
} from "lucide-react"
|
|
26
|
-
import { useSubscription } from "../../hooks/use-subscription"
|
|
27
|
-
|
|
28
|
-
interface HealthCheckEndpoint {
|
|
29
|
-
id: string
|
|
30
|
-
name: string
|
|
31
|
-
url: string
|
|
32
|
-
method: "GET" | "POST" | "PUT" | "DELETE" | "HEAD"
|
|
33
|
-
expectedStatus?: number[]
|
|
34
|
-
timeout?: number
|
|
35
|
-
headers?: Record<string, string>
|
|
36
|
-
body?: string
|
|
37
|
-
critical?: boolean
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
interface HealthCheckResult {
|
|
41
|
-
id: string
|
|
42
|
-
name: string
|
|
43
|
-
status: "healthy" | "unhealthy" | "warning" | "pending"
|
|
44
|
-
responseTime: number
|
|
45
|
-
statusCode?: number
|
|
46
|
-
error?: string
|
|
47
|
-
timestamp: Date
|
|
48
|
-
uptime?: number
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
interface HealthCheckProps {
|
|
52
|
-
endpoints: HealthCheckEndpoint[]
|
|
53
|
-
interval?: number
|
|
54
|
-
autoRefresh?: boolean
|
|
55
|
-
showResponseTime?: boolean
|
|
56
|
-
showUptime?: boolean
|
|
57
|
-
showHistory?: boolean
|
|
58
|
-
maxHistory?: number
|
|
59
|
-
onStatusChange?: (results: HealthCheckResult[]) => void
|
|
60
|
-
className?: string
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const HealthCheckInternal: React.FC<HealthCheckProps> = ({
|
|
64
|
-
endpoints,
|
|
65
|
-
interval = 30000, // 30 seconds
|
|
66
|
-
autoRefresh = true,
|
|
67
|
-
showResponseTime = true,
|
|
68
|
-
showUptime = true,
|
|
69
|
-
showHistory = true,
|
|
70
|
-
maxHistory = 20,
|
|
71
|
-
onStatusChange,
|
|
72
|
-
className
|
|
73
|
-
}) => {
|
|
74
|
-
const [results, setResults] = useState<HealthCheckResult[]>([])
|
|
75
|
-
const [history, setHistory] = useState<Record<string, HealthCheckResult[]>>({})
|
|
76
|
-
const [isChecking, setIsChecking] = useState(false)
|
|
77
|
-
const [lastCheck, setLastCheck] = useState<Date | null>(null)
|
|
78
|
-
|
|
79
|
-
const checkEndpoint = async (endpoint: HealthCheckEndpoint): Promise<HealthCheckResult> => {
|
|
80
|
-
const startTime = Date.now()
|
|
81
|
-
|
|
82
|
-
try {
|
|
83
|
-
const controller = new AbortController()
|
|
84
|
-
const timeoutId = setTimeout(() => controller.abort(), endpoint.timeout || 5000)
|
|
85
|
-
|
|
86
|
-
const response = await fetch(endpoint.url, {
|
|
87
|
-
method: endpoint.method,
|
|
88
|
-
headers: {
|
|
89
|
-
'Content-Type': 'application/json',
|
|
90
|
-
...endpoint.headers
|
|
91
|
-
},
|
|
92
|
-
body: endpoint.body,
|
|
93
|
-
signal: controller.signal
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
clearTimeout(timeoutId)
|
|
97
|
-
const responseTime = Date.now() - startTime
|
|
98
|
-
const expectedStatuses = endpoint.expectedStatus || [200, 201, 204]
|
|
99
|
-
|
|
100
|
-
const isHealthy = expectedStatuses.includes(response.status)
|
|
101
|
-
|
|
102
|
-
return {
|
|
103
|
-
id: endpoint.id,
|
|
104
|
-
name: endpoint.name,
|
|
105
|
-
status: isHealthy ? "healthy" : "unhealthy",
|
|
106
|
-
responseTime,
|
|
107
|
-
statusCode: response.status,
|
|
108
|
-
timestamp: new Date()
|
|
109
|
-
}
|
|
110
|
-
} catch (error) {
|
|
111
|
-
const responseTime = Date.now() - startTime
|
|
112
|
-
|
|
113
|
-
return {
|
|
114
|
-
id: endpoint.id,
|
|
115
|
-
name: endpoint.name,
|
|
116
|
-
status: "unhealthy",
|
|
117
|
-
responseTime,
|
|
118
|
-
error: error instanceof Error ? error.message : "Unknown error",
|
|
119
|
-
timestamp: new Date()
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
const checkAllEndpoints = useCallback(async () => {
|
|
125
|
-
setIsChecking(true)
|
|
126
|
-
|
|
127
|
-
try {
|
|
128
|
-
const checks = endpoints.map(endpoint => checkEndpoint(endpoint))
|
|
129
|
-
const newResults = await Promise.all(checks)
|
|
130
|
-
|
|
131
|
-
setResults(newResults)
|
|
132
|
-
setLastCheck(new Date())
|
|
133
|
-
|
|
134
|
-
// Update history
|
|
135
|
-
setHistory(prevHistory => {
|
|
136
|
-
const newHistory = { ...prevHistory }
|
|
137
|
-
|
|
138
|
-
newResults.forEach(result => {
|
|
139
|
-
if (!newHistory[result.id]) {
|
|
140
|
-
newHistory[result.id] = []
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
newHistory[result.id] = [
|
|
144
|
-
result,
|
|
145
|
-
...newHistory[result.id].slice(0, maxHistory - 1)
|
|
146
|
-
]
|
|
147
|
-
})
|
|
148
|
-
|
|
149
|
-
return newHistory
|
|
150
|
-
})
|
|
151
|
-
|
|
152
|
-
onStatusChange?.(newResults)
|
|
153
|
-
} catch (error) {
|
|
154
|
-
console.error("Health check failed:", error)
|
|
155
|
-
} finally {
|
|
156
|
-
setIsChecking(false)
|
|
157
|
-
}
|
|
158
|
-
}, [endpoints, maxHistory, onStatusChange])
|
|
159
|
-
|
|
160
|
-
// Initial check
|
|
161
|
-
useEffect(() => {
|
|
162
|
-
checkAllEndpoints()
|
|
163
|
-
}, [checkAllEndpoints])
|
|
164
|
-
|
|
165
|
-
// Auto refresh
|
|
166
|
-
useEffect(() => {
|
|
167
|
-
if (!autoRefresh) return
|
|
168
|
-
|
|
169
|
-
const intervalId = setInterval(checkAllEndpoints, interval)
|
|
170
|
-
return () => clearInterval(intervalId)
|
|
171
|
-
}, [autoRefresh, interval, checkAllEndpoints])
|
|
172
|
-
|
|
173
|
-
const getOverallStatus = (): "healthy" | "unhealthy" | "warning" => {
|
|
174
|
-
if (results.length === 0) return "warning"
|
|
175
|
-
|
|
176
|
-
const criticalEndpoints = endpoints.filter(e => e.critical !== false)
|
|
177
|
-
const criticalResults = results.filter(r =>
|
|
178
|
-
criticalEndpoints.some(e => e.id === r.id)
|
|
179
|
-
)
|
|
180
|
-
|
|
181
|
-
const hasUnhealthy = criticalResults.some(r => r.status === "unhealthy")
|
|
182
|
-
const hasWarning = results.some(r => r.status === "warning")
|
|
183
|
-
|
|
184
|
-
if (hasUnhealthy) return "unhealthy"
|
|
185
|
-
if (hasWarning) return "warning"
|
|
186
|
-
return "healthy"
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
const getStatusIcon = (status: string) => {
|
|
190
|
-
switch (status) {
|
|
191
|
-
case "healthy":
|
|
192
|
-
return <CheckCircle className="h-4 w-4 text-green-500" />
|
|
193
|
-
case "unhealthy":
|
|
194
|
-
return <XCircle className="h-4 w-4 text-red-500" />
|
|
195
|
-
case "warning":
|
|
196
|
-
return <AlertCircle className="h-4 w-4 text-yellow-500" />
|
|
197
|
-
default:
|
|
198
|
-
return <Clock className="h-4 w-4 text-muted-foreground" />
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
const getStatusColor = (status: string) => {
|
|
203
|
-
switch (status) {
|
|
204
|
-
case "healthy":
|
|
205
|
-
return "bg-green-500"
|
|
206
|
-
case "unhealthy":
|
|
207
|
-
return "bg-red-500"
|
|
208
|
-
case "warning":
|
|
209
|
-
return "bg-yellow-500"
|
|
210
|
-
default:
|
|
211
|
-
return "bg-muted-foreground"
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
const formatResponseTime = (time: number) => {
|
|
216
|
-
if (time < 1000) return `${time}ms`
|
|
217
|
-
return `${(time / 1000).toFixed(2)}s`
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
const calculateUptime = (endpointId: string): number => {
|
|
221
|
-
const endpointHistory = history[endpointId] || []
|
|
222
|
-
if (endpointHistory.length === 0) return 0
|
|
223
|
-
|
|
224
|
-
const healthyCount = endpointHistory.filter(r => r.status === "healthy").length
|
|
225
|
-
return (healthyCount / endpointHistory.length) * 100
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
const overallStatus = getOverallStatus()
|
|
229
|
-
const healthyCount = results.filter(r => r.status === "healthy").length
|
|
230
|
-
const overallUptime = results.length > 0
|
|
231
|
-
? results.reduce((acc, result) => acc + calculateUptime(result.id), 0) / results.length
|
|
232
|
-
: 0
|
|
233
|
-
|
|
234
|
-
return (
|
|
235
|
-
<Card className={cn("w-full", className)}>
|
|
236
|
-
<CardHeader className="p-6">
|
|
237
|
-
<div className="flex items-center justify-between">
|
|
238
|
-
<div className="flex items-center gap-3">
|
|
239
|
-
<div className="flex items-center gap-2">
|
|
240
|
-
<Activity className="h-6 w-6" />
|
|
241
|
-
<div>
|
|
242
|
-
<CardTitle className="flex items-center gap-2">
|
|
243
|
-
System Health
|
|
244
|
-
<Badge
|
|
245
|
-
variant={overallStatus === "healthy" ? "secondary" : "destructive"}
|
|
246
|
-
className={cn(
|
|
247
|
-
"text-white",
|
|
248
|
-
overallStatus === "healthy" && "bg-green-500",
|
|
249
|
-
overallStatus === "warning" && "bg-yellow-500",
|
|
250
|
-
overallStatus === "unhealthy" && "bg-red-500"
|
|
251
|
-
)}
|
|
252
|
-
>
|
|
253
|
-
{overallStatus.toUpperCase()}
|
|
254
|
-
</Badge>
|
|
255
|
-
</CardTitle>
|
|
256
|
-
{lastCheck && (
|
|
257
|
-
<CardDescription>
|
|
258
|
-
Last checked: {lastCheck.toLocaleTimeString()}
|
|
259
|
-
</CardDescription>
|
|
260
|
-
)}
|
|
261
|
-
</div>
|
|
262
|
-
</div>
|
|
263
|
-
</div>
|
|
264
|
-
|
|
265
|
-
<div className="flex items-center gap-2">
|
|
266
|
-
{showUptime && (
|
|
267
|
-
<div className="text-right">
|
|
268
|
-
<div className="text-sm font-medium">{overallUptime.toFixed(1)}%</div>
|
|
269
|
-
<div className="text-xs text-muted-foreground mt-0.5">Uptime</div>
|
|
270
|
-
</div>
|
|
271
|
-
)}
|
|
272
|
-
|
|
273
|
-
<Button
|
|
274
|
-
onClick={checkAllEndpoints}
|
|
275
|
-
disabled={isChecking}
|
|
276
|
-
variant="outline"
|
|
277
|
-
size="sm"
|
|
278
|
-
>
|
|
279
|
-
<RefreshCw className={cn("h-4 w-4", isChecking && "animate-spin")} />
|
|
280
|
-
</Button>
|
|
281
|
-
</div>
|
|
282
|
-
</div>
|
|
283
|
-
|
|
284
|
-
{/* Overall Stats */}
|
|
285
|
-
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 mt-6">
|
|
286
|
-
<div className="p-6 text-center bg-muted/10 rounded-lg">
|
|
287
|
-
<div className="text-2xl font-bold text-green-500">{healthyCount}</div>
|
|
288
|
-
<div className="text-xs text-muted-foreground mt-1">Healthy</div>
|
|
289
|
-
</div>
|
|
290
|
-
<div className="p-6 text-center bg-muted/10 rounded-lg">
|
|
291
|
-
<div className="text-2xl font-bold text-red-500">
|
|
292
|
-
{results.filter(r => r.status === "unhealthy").length}
|
|
293
|
-
</div>
|
|
294
|
-
<div className="text-xs text-muted-foreground mt-1">Unhealthy</div>
|
|
295
|
-
</div>
|
|
296
|
-
{showResponseTime && (
|
|
297
|
-
<div className="p-6 text-center bg-muted/10 rounded-lg">
|
|
298
|
-
<div className="text-lg font-bold">
|
|
299
|
-
{results.length > 0
|
|
300
|
-
? formatResponseTime(
|
|
301
|
-
results.reduce((acc, r) => acc + r.responseTime, 0) / results.length
|
|
302
|
-
)
|
|
303
|
-
: "0ms"
|
|
304
|
-
}
|
|
305
|
-
</div>
|
|
306
|
-
<div className="text-xs text-muted-foreground mt-1">Avg Response</div>
|
|
307
|
-
</div>
|
|
308
|
-
)}
|
|
309
|
-
<div className="p-6 text-center bg-muted/10 rounded-lg">
|
|
310
|
-
<div className="text-lg font-bold">{results.length}</div>
|
|
311
|
-
<div className="text-xs text-muted-foreground mt-1">Services</div>
|
|
312
|
-
</div>
|
|
313
|
-
</div>
|
|
314
|
-
</CardHeader>
|
|
315
|
-
|
|
316
|
-
<CardContent className="p-6 pt-0">
|
|
317
|
-
<div className="space-y-4">
|
|
318
|
-
<AnimatePresence>
|
|
319
|
-
{results.map((result, index) => (
|
|
320
|
-
<motion.div
|
|
321
|
-
key={result.id}
|
|
322
|
-
initial={{ opacity: 0, x: -20 }}
|
|
323
|
-
animate={{ opacity: 1, x: 0 }}
|
|
324
|
-
exit={{ opacity: 0, x: 20 }}
|
|
325
|
-
transition={{ delay: index * 0.05 }}
|
|
326
|
-
>
|
|
327
|
-
<Card>
|
|
328
|
-
<CardContent className="p-4">
|
|
329
|
-
<div className="flex items-center justify-between">
|
|
330
|
-
<div className="flex items-center gap-3">
|
|
331
|
-
{getStatusIcon(result.status)}
|
|
332
|
-
<div>
|
|
333
|
-
<div className="font-medium">{result.name}</div>
|
|
334
|
-
{result.error && (
|
|
335
|
-
<div className="text-sm text-red-500">{result.error}</div>
|
|
336
|
-
)}
|
|
337
|
-
{result.statusCode && (
|
|
338
|
-
<div className="text-xs text-muted-foreground">
|
|
339
|
-
HTTP {result.statusCode}
|
|
340
|
-
</div>
|
|
341
|
-
)}
|
|
342
|
-
</div>
|
|
343
|
-
</div>
|
|
344
|
-
|
|
345
|
-
<div className="flex items-center gap-4 text-sm">
|
|
346
|
-
{showResponseTime && (
|
|
347
|
-
<div className="text-right">
|
|
348
|
-
<div className="font-medium">
|
|
349
|
-
{formatResponseTime(result.responseTime)}
|
|
350
|
-
</div>
|
|
351
|
-
<div className="text-xs text-muted-foreground mt-0.5">Response</div>
|
|
352
|
-
</div>
|
|
353
|
-
)}
|
|
354
|
-
|
|
355
|
-
{showUptime && (
|
|
356
|
-
<div className="text-right">
|
|
357
|
-
<div className="font-medium">
|
|
358
|
-
{calculateUptime(result.id).toFixed(1)}%
|
|
359
|
-
</div>
|
|
360
|
-
<div className="text-xs text-muted-foreground mt-0.5">Uptime</div>
|
|
361
|
-
</div>
|
|
362
|
-
)}
|
|
363
|
-
</div>
|
|
364
|
-
</div>
|
|
365
|
-
|
|
366
|
-
{/* Mini history chart */}
|
|
367
|
-
{showHistory && history[result.id] && (
|
|
368
|
-
<div className="mt-3">
|
|
369
|
-
<div className="flex items-center gap-1 h-2">
|
|
370
|
-
{history[result.id].slice(0, 20).reverse().map((historyResult, i) => (
|
|
371
|
-
<div
|
|
372
|
-
key={i}
|
|
373
|
-
className={cn(
|
|
374
|
-
"flex-1 h-full rounded-sm",
|
|
375
|
-
getStatusColor(historyResult.status)
|
|
376
|
-
)}
|
|
377
|
-
/>
|
|
378
|
-
))}
|
|
379
|
-
</div>
|
|
380
|
-
<div className="text-xs text-muted-foreground mt-1">
|
|
381
|
-
Last {Math.min(history[result.id].length, 20)} checks
|
|
382
|
-
</div>
|
|
383
|
-
</div>
|
|
384
|
-
)}
|
|
385
|
-
</CardContent>
|
|
386
|
-
</Card>
|
|
387
|
-
</motion.div>
|
|
388
|
-
))}
|
|
389
|
-
</AnimatePresence>
|
|
390
|
-
|
|
391
|
-
{results.length === 0 && !isChecking && (
|
|
392
|
-
<div className="text-center py-8">
|
|
393
|
-
<Server className="h-12 w-12 mx-auto mb-4 text-muted-foreground" />
|
|
394
|
-
<p className="text-muted-foreground">No endpoints configured</p>
|
|
395
|
-
</div>
|
|
396
|
-
)}
|
|
397
|
-
</div>
|
|
398
|
-
</CardContent>
|
|
399
|
-
</Card>
|
|
400
|
-
)
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
export const HealthCheck: React.FC<HealthCheckProps> = ({ className, ...props }) => {
|
|
404
|
-
// Check if we're in docs mode or have pro access
|
|
405
|
-
const { hasProAccess, isLoading } = useSubscription()
|
|
406
|
-
|
|
407
|
-
// In docs mode, always show the component
|
|
408
|
-
|
|
409
|
-
// If not in docs mode and no pro access, show upgrade prompt
|
|
410
|
-
if (!isLoading && !hasProAccess) {
|
|
411
|
-
return (
|
|
412
|
-
<Card className={cn("w-fit", className)}>
|
|
413
|
-
<CardContent className="py-6 text-center">
|
|
414
|
-
<div className="space-y-4">
|
|
415
|
-
<div className="rounded-full bg-purple-100 dark:bg-purple-900/30 p-3 w-fit mx-auto">
|
|
416
|
-
<Lock className="h-6 w-6 text-purple-600 dark:text-purple-400" />
|
|
417
|
-
</div>
|
|
418
|
-
<div>
|
|
419
|
-
<h3 className="font-semibold text-sm mb-2">Pro Feature</h3>
|
|
420
|
-
<p className="text-muted-foreground text-xs mb-4">
|
|
421
|
-
Health Check is available exclusively to MoonUI Pro subscribers.
|
|
422
|
-
</p>
|
|
423
|
-
<a href="/pricing">
|
|
424
|
-
<Button size="sm">
|
|
425
|
-
<Sparkles className="mr-2 h-4 w-4" />
|
|
426
|
-
Upgrade to Pro
|
|
427
|
-
</Button>
|
|
428
|
-
</a>
|
|
429
|
-
</div>
|
|
430
|
-
</div>
|
|
431
|
-
</CardContent>
|
|
432
|
-
</Card>
|
|
433
|
-
)
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
return <HealthCheckInternal className={className} {...props} />
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
export type { HealthCheckEndpoint, HealthCheckResult, HealthCheckProps }
|