@geenius/tools 0.1.0 → 0.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.
- package/package.json +62 -3
- package/packages/convex/shared/README.md +1 -1
- package/packages/devtools/dist/index.d.ts +204 -0
- package/packages/devtools/dist/index.js +186 -0
- package/packages/devtools/dist/index.js.map +1 -0
- package/packages/devtools/react/README.md +1 -1
- package/packages/devtools/solidjs/README.md +1 -1
- package/packages/devtools/solidjs/dist/index.js +1830 -0
- package/packages/devtools/solidjs/dist/index.js.map +1 -0
- package/packages/env/dist/index.d.ts +151 -0
- package/packages/env/dist/index.js +93 -0
- package/packages/env/dist/index.js.map +1 -0
- package/packages/errors/dist/index.d.ts +177 -0
- package/packages/errors/dist/index.js +187 -0
- package/packages/errors/dist/index.js.map +1 -0
- package/packages/errors/react/README.md +1 -1
- package/packages/errors/solidjs/README.md +1 -1
- package/packages/logger/dist/index.d.ts +171 -0
- package/packages/logger/dist/index.js +216 -0
- package/packages/logger/dist/index.js.map +1 -0
- package/packages/logger/react/README.md +1 -1
- package/packages/logger/solidjs/README.md +1 -1
- package/packages/perf/dist/index.d.ts +168 -0
- package/packages/perf/dist/index.js +265 -0
- package/packages/perf/dist/index.js.map +1 -0
- package/packages/perf/react/README.md +1 -1
- package/packages/perf/solidjs/README.md +1 -1
- package/packages/shared/dist/index.d.ts +253 -0
- package/packages/shared/dist/index.js +278 -0
- package/packages/shared/dist/index.js.map +1 -0
- package/.changeset/config.json +0 -11
- package/.env.example +0 -2
- package/.github/CODEOWNERS +0 -1
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -16
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -11
- package/.github/PULL_REQUEST_TEMPLATE.md +0 -10
- package/.github/dependabot.yml +0 -11
- package/.github/workflows/ci.yml +0 -23
- package/.github/workflows/release.yml +0 -29
- package/.node-version +0 -1
- package/.nvmrc +0 -1
- package/.prettierrc +0 -7
- package/.project/ACCOUNT.yaml +0 -4
- package/.project/IDEAS.yaml +0 -7
- package/.project/PROJECT.yaml +0 -11
- package/.project/ROADMAP.yaml +0 -15
- package/CODE_OF_CONDUCT.md +0 -26
- package/CONTRIBUTING.md +0 -69
- package/SECURITY.md +0 -18
- package/SUPPORT.md +0 -14
- package/packages/convex/shared/package.json +0 -42
- package/packages/convex/shared/src/audit/index.ts +0 -5
- package/packages/convex/shared/src/audit/presets.ts +0 -165
- package/packages/convex/shared/src/audit/schema.ts +0 -85
- package/packages/convex/shared/src/audit/write.ts +0 -102
- package/packages/convex/shared/src/extract.ts +0 -75
- package/packages/convex/shared/src/index.ts +0 -41
- package/packages/convex/shared/src/messages.ts +0 -45
- package/packages/convex/shared/src/security.ts +0 -112
- package/packages/convex/shared/src/throw.ts +0 -184
- package/packages/convex/shared/src/types.ts +0 -57
- package/packages/convex/shared/src/utils.ts +0 -58
- package/packages/convex/shared/tsconfig.json +0 -28
- package/packages/convex/shared/tsup.config.ts +0 -12
- package/packages/devtools/package.json +0 -27
- package/packages/devtools/react/package.json +0 -53
- package/packages/devtools/react/src/components/DesignPreview.tsx +0 -59
- package/packages/devtools/react/src/components/DesignSwitcherDropdown.tsx +0 -99
- package/packages/devtools/react/src/components/DevSidebar.tsx +0 -247
- package/packages/devtools/react/src/components/DevToolbar.tsx +0 -242
- package/packages/devtools/react/src/components/GitHubIssueDialog.tsx +0 -402
- package/packages/devtools/react/src/components/InspectorOverlay.tsx +0 -312
- package/packages/devtools/react/src/components/PageLoadWaterfall.tsx +0 -144
- package/packages/devtools/react/src/components/PerformancePanel.tsx +0 -330
- package/packages/devtools/react/src/context/DevModeContext.tsx +0 -226
- package/packages/devtools/react/src/context/PerformanceContext.tsx +0 -143
- package/packages/devtools/react/src/data/designs.ts +0 -13
- package/packages/devtools/react/src/hooks/useGitHubLabels.ts +0 -47
- package/packages/devtools/react/src/hooks/useVirtualList.ts +0 -124
- package/packages/devtools/react/src/index.ts +0 -77
- package/packages/devtools/react/src/panels/ConvexSpy.tsx +0 -130
- package/packages/devtools/react/src/panels/DatabaseSeeder.tsx +0 -116
- package/packages/devtools/react/src/panels/DevModePhase2.tsx +0 -191
- package/packages/devtools/react/src/panels/DevModePhase3.tsx +0 -234
- package/packages/devtools/react/src/panels/FeatureFlagsToggle.tsx +0 -104
- package/packages/devtools/react/src/panels/QuickRouteJump.tsx +0 -152
- package/packages/devtools/react/src/services/github-service.ts +0 -247
- package/packages/devtools/react/tsconfig.json +0 -31
- package/packages/devtools/react/tsup.config.ts +0 -18
- package/packages/devtools/solidjs/package.json +0 -49
- package/packages/devtools/solidjs/src/components/DesignPreview.tsx +0 -51
- package/packages/devtools/solidjs/src/components/DesignSwitcherDropdown.tsx +0 -95
- package/packages/devtools/solidjs/src/components/DevSidebar.tsx +0 -247
- package/packages/devtools/solidjs/src/components/DevToolbar.tsx +0 -242
- package/packages/devtools/solidjs/src/components/GitHubIssueDialog.tsx +0 -400
- package/packages/devtools/solidjs/src/components/InspectorOverlay.tsx +0 -311
- package/packages/devtools/solidjs/src/components/PageLoadWaterfall.tsx +0 -144
- package/packages/devtools/solidjs/src/components/PerformancePanel.tsx +0 -330
- package/packages/devtools/solidjs/src/context/DevModeContext.tsx +0 -216
- package/packages/devtools/solidjs/src/context/PerformanceContext.tsx +0 -135
- package/packages/devtools/solidjs/src/data/designs.ts +0 -13
- package/packages/devtools/solidjs/src/hooks/createGitHubLabels.ts +0 -47
- package/packages/devtools/solidjs/src/index.ts +0 -64
- package/packages/devtools/solidjs/src/services/github-service.ts +0 -247
- package/packages/devtools/solidjs/tsconfig.json +0 -21
- package/packages/devtools/src/index.ts +0 -377
- package/packages/devtools/tsup.config.ts +0 -12
- package/packages/env/package.json +0 -30
- package/packages/env/src/index.ts +0 -264
- package/packages/env/tsup.config.ts +0 -12
- package/packages/errors/package.json +0 -27
- package/packages/errors/react/package.json +0 -72
- package/packages/errors/react/src/analytics.ts +0 -16
- package/packages/errors/react/src/components/ErrorBoundary.tsx +0 -248
- package/packages/errors/react/src/components/ErrorDisplay.tsx +0 -328
- package/packages/errors/react/src/components/ValidationErrors.tsx +0 -102
- package/packages/errors/react/src/config.ts +0 -199
- package/packages/errors/react/src/constants.ts +0 -74
- package/packages/errors/react/src/hooks/useErrorBoundary.ts +0 -92
- package/packages/errors/react/src/hooks/useErrorHandler.ts +0 -87
- package/packages/errors/react/src/index.ts +0 -96
- package/packages/errors/react/src/types.ts +0 -102
- package/packages/errors/react/src/utils/errorMessages.ts +0 -35
- package/packages/errors/react/src/utils/errorPolicy.ts +0 -139
- package/packages/errors/react/src/utils/extractAppError.ts +0 -174
- package/packages/errors/react/src/utils/formatError.ts +0 -112
- package/packages/errors/react/tsconfig.json +0 -25
- package/packages/errors/react/tsup.config.ts +0 -24
- package/packages/errors/solidjs/package.json +0 -46
- package/packages/errors/solidjs/src/components/ErrorDisplay.tsx +0 -179
- package/packages/errors/solidjs/src/config.ts +0 -98
- package/packages/errors/solidjs/src/hooks/createErrorHandler.ts +0 -107
- package/packages/errors/solidjs/src/index.ts +0 -61
- package/packages/errors/solidjs/src/types.ts +0 -34
- package/packages/errors/solidjs/src/utils/errorPolicy.ts +0 -56
- package/packages/errors/solidjs/src/utils/extractAppError.ts +0 -94
- package/packages/errors/solidjs/src/utils/formatError.ts +0 -33
- package/packages/errors/solidjs/tsconfig.json +0 -26
- package/packages/errors/solidjs/tsup.config.ts +0 -21
- package/packages/errors/src/index.ts +0 -320
- package/packages/errors/tsup.config.ts +0 -12
- package/packages/logger/package.json +0 -27
- package/packages/logger/react/package.json +0 -46
- package/packages/logger/react/src/index.ts +0 -4
- package/packages/logger/react/src/useMetrics.ts +0 -42
- package/packages/logger/react/src/usePerformanceLog.ts +0 -61
- package/packages/logger/react/tsconfig.json +0 -31
- package/packages/logger/react/tsup.config.ts +0 -12
- package/packages/logger/solidjs/package.json +0 -45
- package/packages/logger/solidjs/src/createMetrics.ts +0 -37
- package/packages/logger/solidjs/src/createPerformanceLog.ts +0 -58
- package/packages/logger/solidjs/src/index.ts +0 -4
- package/packages/logger/solidjs/tsconfig.json +0 -32
- package/packages/logger/solidjs/tsup.config.ts +0 -12
- package/packages/logger/src/index.ts +0 -363
- package/packages/logger/tsup.config.ts +0 -12
- package/packages/perf/package.json +0 -27
- package/packages/perf/react/package.json +0 -59
- package/packages/perf/react/src/components/PerformanceDashboard.tsx +0 -257
- package/packages/perf/react/src/hooks/useMonitoredQuery.ts +0 -89
- package/packages/perf/react/src/hooks/usePerformanceMetrics.ts +0 -78
- package/packages/perf/react/src/index.ts +0 -33
- package/packages/perf/react/src/services/PerformanceMonitor.ts +0 -313
- package/packages/perf/react/src/types.ts +0 -77
- package/packages/perf/react/tsconfig.json +0 -25
- package/packages/perf/react/tsup.config.ts +0 -19
- package/packages/perf/solidjs/package.json +0 -41
- package/packages/perf/solidjs/src/components/PerformanceDashboard.tsx +0 -207
- package/packages/perf/solidjs/src/hooks/createPerformanceMetrics.ts +0 -73
- package/packages/perf/solidjs/src/index.ts +0 -31
- package/packages/perf/solidjs/src/services/PerformanceMonitor.ts +0 -134
- package/packages/perf/solidjs/src/types.ts +0 -78
- package/packages/perf/solidjs/tsconfig.json +0 -26
- package/packages/perf/solidjs/tsup.config.ts +0 -14
- package/packages/perf/src/index.ts +0 -410
- package/packages/perf/tsup.config.ts +0 -12
- package/pnpm-workspace.yaml +0 -2
|
@@ -1,330 +0,0 @@
|
|
|
1
|
-
// @geenius-tools/devtools-react — src/components/PerformancePanel.tsx
|
|
2
|
-
|
|
3
|
-
import { memo, useMemo, useRef, useEffect } from 'react'
|
|
4
|
-
import { cn } from '@geenius-ui/react'
|
|
5
|
-
import { X, Trash2, Activity, Zap, Clock, AlertTriangle } from 'lucide-react'
|
|
6
|
-
import { usePerformanceContext } from '../context/PerformanceContext'
|
|
7
|
-
import type { PerformanceMetric } from '@geenius-tools/logger'
|
|
8
|
-
|
|
9
|
-
function getDurationColor(duration: number | undefined): string {
|
|
10
|
-
if (duration === undefined) return 'text-white/40'
|
|
11
|
-
if (duration > 100) return 'text-red-400'
|
|
12
|
-
if (duration > 50) return 'text-yellow-400'
|
|
13
|
-
return 'text-green-400'
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function getDurationBgColor(duration: number | undefined): string {
|
|
17
|
-
if (duration === undefined) return 'bg-white/20'
|
|
18
|
-
if (duration > 100) return 'bg-red-500'
|
|
19
|
-
if (duration > 50) return 'bg-yellow-500'
|
|
20
|
-
return 'bg-green-500'
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function getTypeColor(type: string): string {
|
|
24
|
-
switch (type) {
|
|
25
|
-
case 'network':
|
|
26
|
-
return 'text-blue-400'
|
|
27
|
-
case 'query':
|
|
28
|
-
return 'text-orange-400'
|
|
29
|
-
case 'mutation':
|
|
30
|
-
return 'text-red-400'
|
|
31
|
-
case 'render':
|
|
32
|
-
return 'text-purple-400'
|
|
33
|
-
case 'route':
|
|
34
|
-
return 'text-green-400'
|
|
35
|
-
case 'component':
|
|
36
|
-
return 'text-cyan-400'
|
|
37
|
-
case 'effect':
|
|
38
|
-
return 'text-teal-400'
|
|
39
|
-
default:
|
|
40
|
-
return 'text-white/60'
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function getTypeIcon(type: string) {
|
|
45
|
-
switch (type) {
|
|
46
|
-
case 'network':
|
|
47
|
-
return '🌐'
|
|
48
|
-
case 'query':
|
|
49
|
-
return '🔍'
|
|
50
|
-
case 'mutation':
|
|
51
|
-
return '✏️'
|
|
52
|
-
case 'render':
|
|
53
|
-
return '🎨'
|
|
54
|
-
case 'route':
|
|
55
|
-
return '🧭'
|
|
56
|
-
case 'component':
|
|
57
|
-
return '📦'
|
|
58
|
-
case 'effect':
|
|
59
|
-
return '⚡'
|
|
60
|
-
default:
|
|
61
|
-
return '📝'
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const MiniBar = memo(function MiniBar({
|
|
66
|
-
height,
|
|
67
|
-
color,
|
|
68
|
-
label,
|
|
69
|
-
}: {
|
|
70
|
-
height: number
|
|
71
|
-
color: string
|
|
72
|
-
label: string
|
|
73
|
-
}) {
|
|
74
|
-
return (
|
|
75
|
-
<div className="flex flex-col items-center gap-0.5 flex-1 min-w-0">
|
|
76
|
-
<div className="w-full h-12 flex items-end">
|
|
77
|
-
<div
|
|
78
|
-
className={cn('w-full rounded-t-sm transition-all duration-300', color)}
|
|
79
|
-
style={{ height: `${Math.min(height, 100)}%` }}
|
|
80
|
-
title={label}
|
|
81
|
-
/>
|
|
82
|
-
</div>
|
|
83
|
-
</div>
|
|
84
|
-
)
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
const MetricRow = memo(function MetricRow({
|
|
88
|
-
metric,
|
|
89
|
-
}: {
|
|
90
|
-
metric: PerformanceMetric
|
|
91
|
-
}) {
|
|
92
|
-
const duration = metric.duration
|
|
93
|
-
const durationStr = duration ? `${duration.toFixed(1)}ms` : 'pending...'
|
|
94
|
-
|
|
95
|
-
return (
|
|
96
|
-
<div
|
|
97
|
-
className={cn(
|
|
98
|
-
'flex items-center gap-3 px-3 py-2 rounded-lg',
|
|
99
|
-
'bg-white/5 hover:bg-white/10 transition-colors',
|
|
100
|
-
)}
|
|
101
|
-
>
|
|
102
|
-
<span className="text-sm">{getTypeIcon(metric.type)}</span>
|
|
103
|
-
<div className="flex-1 min-w-0">
|
|
104
|
-
<div className={cn('text-xs font-medium truncate', getTypeColor(metric.type))}>
|
|
105
|
-
{metric.name}
|
|
106
|
-
</div>
|
|
107
|
-
</div>
|
|
108
|
-
<div
|
|
109
|
-
className={cn(
|
|
110
|
-
'text-xs font-mono font-bold',
|
|
111
|
-
getDurationColor(duration),
|
|
112
|
-
)}
|
|
113
|
-
>
|
|
114
|
-
{durationStr}
|
|
115
|
-
</div>
|
|
116
|
-
</div>
|
|
117
|
-
)
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
const StatCard = memo(function StatCard({
|
|
121
|
-
icon: Icon,
|
|
122
|
-
label,
|
|
123
|
-
value,
|
|
124
|
-
color = 'text-white',
|
|
125
|
-
}: {
|
|
126
|
-
icon: React.ElementType
|
|
127
|
-
label: string
|
|
128
|
-
value: string | number
|
|
129
|
-
color?: string
|
|
130
|
-
}) {
|
|
131
|
-
return (
|
|
132
|
-
<div className="flex items-center gap-2 px-3 py-2 rounded-lg bg-white/5">
|
|
133
|
-
<Icon className={cn('w-4 h-4', color)} />
|
|
134
|
-
<div className="flex flex-col">
|
|
135
|
-
<span className="text-[10px] text-white/50 uppercase">{label}</span>
|
|
136
|
-
<span className="text-sm font-bold text-white">{value}</span>
|
|
137
|
-
</div>
|
|
138
|
-
</div>
|
|
139
|
-
)
|
|
140
|
-
})
|
|
141
|
-
|
|
142
|
-
const FilterToggle = memo(function FilterToggle({
|
|
143
|
-
label,
|
|
144
|
-
active,
|
|
145
|
-
color,
|
|
146
|
-
onClick,
|
|
147
|
-
}: {
|
|
148
|
-
label: string
|
|
149
|
-
active: boolean
|
|
150
|
-
color: string
|
|
151
|
-
onClick: () => void
|
|
152
|
-
}) {
|
|
153
|
-
return (
|
|
154
|
-
<button
|
|
155
|
-
onClick={onClick}
|
|
156
|
-
className={cn(
|
|
157
|
-
'px-2 py-1 rounded text-xs font-medium transition-all',
|
|
158
|
-
active
|
|
159
|
-
? `${color} text-white`
|
|
160
|
-
: 'bg-white/10 text-white/50 hover:bg-white/20',
|
|
161
|
-
)}
|
|
162
|
-
>
|
|
163
|
-
{label}
|
|
164
|
-
</button>
|
|
165
|
-
)
|
|
166
|
-
})
|
|
167
|
-
|
|
168
|
-
export const PerformancePanel = memo(function PerformancePanel() {
|
|
169
|
-
const {
|
|
170
|
-
isPerformancePanelOpen,
|
|
171
|
-
metrics,
|
|
172
|
-
filters,
|
|
173
|
-
stats,
|
|
174
|
-
togglePerformancePanel,
|
|
175
|
-
clearMetrics,
|
|
176
|
-
toggleFilter,
|
|
177
|
-
} = usePerformanceContext()
|
|
178
|
-
|
|
179
|
-
const listRef = useRef<HTMLDivElement>(null)
|
|
180
|
-
|
|
181
|
-
const filteredMetrics = useMemo(() => {
|
|
182
|
-
return metrics.filter((m) => {
|
|
183
|
-
if (m.type === 'network' && !filters.network) return false
|
|
184
|
-
if (m.type === 'query' && !filters.query) return false
|
|
185
|
-
if (m.type === 'mutation' && !filters.mutation) return false
|
|
186
|
-
if (m.type === 'render' && !filters.render) return false
|
|
187
|
-
if (m.type === 'route' && !filters.route) return false
|
|
188
|
-
return true
|
|
189
|
-
})
|
|
190
|
-
}, [metrics, filters])
|
|
191
|
-
|
|
192
|
-
const chartMetrics = useMemo(() => {
|
|
193
|
-
return filteredMetrics.filter((m) => m.duration !== undefined).slice(-20)
|
|
194
|
-
}, [filteredMetrics])
|
|
195
|
-
|
|
196
|
-
const maxDuration = useMemo(() => {
|
|
197
|
-
if (chartMetrics.length === 0) return 100
|
|
198
|
-
const max = Math.max(...chartMetrics.map((m) => m.duration || 0))
|
|
199
|
-
return Math.max(max, 100)
|
|
200
|
-
}, [chartMetrics])
|
|
201
|
-
|
|
202
|
-
useEffect(() => {
|
|
203
|
-
if (listRef.current) {
|
|
204
|
-
listRef.current.scrollTop = listRef.current.scrollHeight
|
|
205
|
-
}
|
|
206
|
-
}, [filteredMetrics.length])
|
|
207
|
-
|
|
208
|
-
if (!isPerformancePanelOpen) return null
|
|
209
|
-
|
|
210
|
-
return (
|
|
211
|
-
<div
|
|
212
|
-
data-dev-tool="true"
|
|
213
|
-
className={cn(
|
|
214
|
-
'fixed bottom-20 left-1/2 -translate-x-1/2 z-50',
|
|
215
|
-
'w-[440px] max-h-[400px]',
|
|
216
|
-
'rounded-2xl border border-white/10',
|
|
217
|
-
'bg-gradient-to-b from-slate-900/95 via-slate-800/95 to-slate-900/95',
|
|
218
|
-
'backdrop-blur-xl shadow-2xl shadow-black/50',
|
|
219
|
-
'flex flex-col overflow-hidden',
|
|
220
|
-
'animate-in slide-in-from-bottom-4 fade-in duration-300',
|
|
221
|
-
)}
|
|
222
|
-
>
|
|
223
|
-
{/* Header */}
|
|
224
|
-
<div className="flex items-center justify-between px-4 py-3 border-b border-white/10">
|
|
225
|
-
<div className="flex items-center gap-2">
|
|
226
|
-
<Activity className="w-4 h-4 text-primary" />
|
|
227
|
-
<span className="text-sm font-bold text-white">Performance</span>
|
|
228
|
-
<span className="text-xs text-white/40">
|
|
229
|
-
({filteredMetrics.length} events)
|
|
230
|
-
</span>
|
|
231
|
-
</div>
|
|
232
|
-
<div className="flex items-center gap-1">
|
|
233
|
-
<button
|
|
234
|
-
onClick={clearMetrics}
|
|
235
|
-
className="p-1.5 text-white/40 hover:text-white hover:bg-white/10 rounded-lg transition-colors"
|
|
236
|
-
title="Clear metrics"
|
|
237
|
-
>
|
|
238
|
-
<Trash2 className="w-3.5 h-3.5" />
|
|
239
|
-
</button>
|
|
240
|
-
<button
|
|
241
|
-
onClick={togglePerformancePanel}
|
|
242
|
-
className="p-1.5 text-white/40 hover:text-white hover:bg-white/10 rounded-lg transition-colors"
|
|
243
|
-
title="Close panel"
|
|
244
|
-
>
|
|
245
|
-
<X className="w-4 h-4" />
|
|
246
|
-
</button>
|
|
247
|
-
</div>
|
|
248
|
-
</div>
|
|
249
|
-
|
|
250
|
-
{/* Stats Bar */}
|
|
251
|
-
<div className="flex gap-2 px-4 py-3 border-b border-white/10 overflow-x-auto">
|
|
252
|
-
<StatCard
|
|
253
|
-
icon={Activity}
|
|
254
|
-
label="Requests"
|
|
255
|
-
value={stats.totalRequests}
|
|
256
|
-
color="text-blue-400"
|
|
257
|
-
/>
|
|
258
|
-
<StatCard
|
|
259
|
-
icon={Clock}
|
|
260
|
-
label="Avg"
|
|
261
|
-
value={`${stats.avgDuration}ms`}
|
|
262
|
-
color={
|
|
263
|
-
stats.avgDuration > 100
|
|
264
|
-
? 'text-red-400'
|
|
265
|
-
: stats.avgDuration > 50
|
|
266
|
-
? 'text-yellow-400'
|
|
267
|
-
: 'text-green-400'
|
|
268
|
-
}
|
|
269
|
-
/>
|
|
270
|
-
<StatCard
|
|
271
|
-
icon={Zap}
|
|
272
|
-
label="Fast"
|
|
273
|
-
value={stats.fastRequests}
|
|
274
|
-
color="text-green-400"
|
|
275
|
-
/>
|
|
276
|
-
<StatCard
|
|
277
|
-
icon={AlertTriangle}
|
|
278
|
-
label="Slow"
|
|
279
|
-
value={stats.slowRequests}
|
|
280
|
-
color={stats.slowRequests > 0 ? 'text-red-400' : 'text-white/50'}
|
|
281
|
-
/>
|
|
282
|
-
</div>
|
|
283
|
-
|
|
284
|
-
{/* Mini Chart */}
|
|
285
|
-
{chartMetrics.length > 0 && (
|
|
286
|
-
<div className="px-4 py-3 border-b border-white/10">
|
|
287
|
-
<div className="flex items-end gap-1 h-16">
|
|
288
|
-
{chartMetrics.map((metric) => (
|
|
289
|
-
<MiniBar
|
|
290
|
-
key={metric.id}
|
|
291
|
-
height={((metric.duration || 0) / maxDuration) * 100}
|
|
292
|
-
color={getDurationBgColor(metric.duration)}
|
|
293
|
-
label={`${metric.name}: ${metric.duration?.toFixed(1)}ms`}
|
|
294
|
-
/>
|
|
295
|
-
))}
|
|
296
|
-
</div>
|
|
297
|
-
<div className="flex justify-between mt-1 text-xs text-white/40">
|
|
298
|
-
<span>Recent requests</span>
|
|
299
|
-
<span>0-{maxDuration.toFixed(0)}ms</span>
|
|
300
|
-
</div>
|
|
301
|
-
</div>
|
|
302
|
-
)}
|
|
303
|
-
|
|
304
|
-
{/* Filters */}
|
|
305
|
-
<div className="flex gap-1 px-4 py-2 border-b border-white/10">
|
|
306
|
-
<FilterToggle label="Network" active={filters.network} color="bg-blue-500" onClick={() => toggleFilter('network')} />
|
|
307
|
-
<FilterToggle label="Query" active={filters.query} color="bg-orange-500" onClick={() => toggleFilter('query')} />
|
|
308
|
-
<FilterToggle label="Mutation" active={filters.mutation} color="bg-red-500" onClick={() => toggleFilter('mutation')} />
|
|
309
|
-
<FilterToggle label="Render" active={filters.render} color="bg-purple-500" onClick={() => toggleFilter('render')} />
|
|
310
|
-
<FilterToggle label="Route" active={filters.route} color="bg-green-500" onClick={() => toggleFilter('route')} />
|
|
311
|
-
</div>
|
|
312
|
-
|
|
313
|
-
{/* Metrics List */}
|
|
314
|
-
<div
|
|
315
|
-
ref={listRef}
|
|
316
|
-
className="flex-1 overflow-y-auto px-3 py-2 space-y-1 min-h-[100px] max-h-[180px]"
|
|
317
|
-
>
|
|
318
|
-
{filteredMetrics.length === 0 ? (
|
|
319
|
-
<div className="flex items-center justify-center py-8 text-sm text-white/30">
|
|
320
|
-
No metrics recorded yet
|
|
321
|
-
</div>
|
|
322
|
-
) : (
|
|
323
|
-
filteredMetrics.map((metric) => (
|
|
324
|
-
<MetricRow key={metric.id} metric={metric} />
|
|
325
|
-
))
|
|
326
|
-
)}
|
|
327
|
-
</div>
|
|
328
|
-
</div>
|
|
329
|
-
)
|
|
330
|
-
})
|
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
// @geenius-tools/devtools-react — src/context/DevModeContext.tsx
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
createContext,
|
|
5
|
-
useContext,
|
|
6
|
-
useState,
|
|
7
|
-
useCallback,
|
|
8
|
-
useEffect,
|
|
9
|
-
type ReactNode,
|
|
10
|
-
memo,
|
|
11
|
-
} from 'react'
|
|
12
|
-
|
|
13
|
-
const DEV_MODE_STORAGE_KEY = 'geenius-dev-mode-state'
|
|
14
|
-
|
|
15
|
-
export interface ComponentDetails {
|
|
16
|
-
name: string
|
|
17
|
-
file?: string
|
|
18
|
-
selector: string
|
|
19
|
-
key?: string
|
|
20
|
-
props?: Record<string, unknown>
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
interface DevModeState {
|
|
24
|
-
isDevMode: boolean
|
|
25
|
-
isSidebarOpen: boolean
|
|
26
|
-
isInspectorMode: boolean
|
|
27
|
-
issueDialog: {
|
|
28
|
-
isOpen: boolean
|
|
29
|
-
type: 'bug' | 'feature'
|
|
30
|
-
initialDescription?: string
|
|
31
|
-
componentDetails?: ComponentDetails[]
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export interface DevModeContextValue extends DevModeState {
|
|
36
|
-
toggleDevMode: () => void
|
|
37
|
-
toggleSidebar: () => void
|
|
38
|
-
toggleInspector: () => void
|
|
39
|
-
setDevMode: (enabled: boolean) => void
|
|
40
|
-
setSidebarOpen: (open: boolean) => void
|
|
41
|
-
setInspectorMode: (enabled: boolean) => void
|
|
42
|
-
openIssueDialog: (
|
|
43
|
-
type: 'bug' | 'feature',
|
|
44
|
-
description?: string,
|
|
45
|
-
componentDetails?: ComponentDetails[],
|
|
46
|
-
) => void
|
|
47
|
-
closeIssueDialog: () => void
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const defaultState: DevModeState = {
|
|
51
|
-
isDevMode: false,
|
|
52
|
-
isSidebarOpen: false,
|
|
53
|
-
isInspectorMode: false,
|
|
54
|
-
issueDialog: {
|
|
55
|
-
isOpen: false,
|
|
56
|
-
type: 'bug',
|
|
57
|
-
initialDescription: '',
|
|
58
|
-
},
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const DevModeContext = createContext<DevModeContextValue | undefined>(undefined)
|
|
62
|
-
|
|
63
|
-
export function useDevMode() {
|
|
64
|
-
const context = useContext(DevModeContext)
|
|
65
|
-
if (!context) {
|
|
66
|
-
throw new Error('useDevMode must be used within a DevModeProvider')
|
|
67
|
-
}
|
|
68
|
-
return context
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export function useDevModeOptional(): DevModeContextValue | null {
|
|
72
|
-
return useContext(DevModeContext) ?? null
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export interface DevModeProviderProps {
|
|
76
|
-
children: ReactNode
|
|
77
|
-
/** Whether dev tools are allowed. Default: checks import.meta.env.DEV */
|
|
78
|
-
isAllowed?: boolean
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export const DevModeProvider = memo(function DevModeProvider({
|
|
82
|
-
children,
|
|
83
|
-
isAllowed,
|
|
84
|
-
}: DevModeProviderProps) {
|
|
85
|
-
const resolvedAllowed = isAllowed ?? resolveDevAllowed()
|
|
86
|
-
|
|
87
|
-
const [state, setState] = useState<DevModeState>(() => {
|
|
88
|
-
if (!resolvedAllowed || typeof window === 'undefined') return defaultState
|
|
89
|
-
|
|
90
|
-
try {
|
|
91
|
-
const stored = localStorage.getItem(DEV_MODE_STORAGE_KEY)
|
|
92
|
-
if (stored) {
|
|
93
|
-
const parsed = JSON.parse(stored) as Partial<DevModeState>
|
|
94
|
-
return {
|
|
95
|
-
isDevMode: parsed.isDevMode ?? false,
|
|
96
|
-
isSidebarOpen: false,
|
|
97
|
-
isInspectorMode: false,
|
|
98
|
-
issueDialog: defaultState.issueDialog,
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
} catch {
|
|
102
|
-
// Ignore parse errors
|
|
103
|
-
}
|
|
104
|
-
return defaultState
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
useEffect(() => {
|
|
108
|
-
if (!resolvedAllowed || typeof window === 'undefined') return
|
|
109
|
-
|
|
110
|
-
try {
|
|
111
|
-
localStorage.setItem(
|
|
112
|
-
DEV_MODE_STORAGE_KEY,
|
|
113
|
-
JSON.stringify({ isDevMode: state.isDevMode }),
|
|
114
|
-
)
|
|
115
|
-
} catch {
|
|
116
|
-
// Ignore storage errors
|
|
117
|
-
}
|
|
118
|
-
}, [state.isDevMode, resolvedAllowed])
|
|
119
|
-
|
|
120
|
-
const toggleDevMode = useCallback(() => {
|
|
121
|
-
setState((prev) => ({
|
|
122
|
-
...prev,
|
|
123
|
-
isDevMode: !prev.isDevMode,
|
|
124
|
-
isSidebarOpen: prev.isDevMode ? false : prev.isSidebarOpen,
|
|
125
|
-
isInspectorMode: prev.isDevMode ? false : prev.isInspectorMode,
|
|
126
|
-
}))
|
|
127
|
-
}, [])
|
|
128
|
-
|
|
129
|
-
const toggleSidebar = useCallback(() => {
|
|
130
|
-
setState((prev) => ({ ...prev, isSidebarOpen: !prev.isSidebarOpen }))
|
|
131
|
-
}, [])
|
|
132
|
-
|
|
133
|
-
const toggleInspector = useCallback(() => {
|
|
134
|
-
setState((prev) => ({
|
|
135
|
-
...prev,
|
|
136
|
-
isInspectorMode: !prev.isInspectorMode,
|
|
137
|
-
}))
|
|
138
|
-
}, [])
|
|
139
|
-
|
|
140
|
-
const setDevMode = useCallback((enabled: boolean) => {
|
|
141
|
-
setState((prev) => ({
|
|
142
|
-
...prev,
|
|
143
|
-
isDevMode: enabled,
|
|
144
|
-
isSidebarOpen: enabled ? prev.isSidebarOpen : false,
|
|
145
|
-
isInspectorMode: enabled ? prev.isInspectorMode : false,
|
|
146
|
-
}))
|
|
147
|
-
}, [])
|
|
148
|
-
|
|
149
|
-
const setSidebarOpen = useCallback((open: boolean) => {
|
|
150
|
-
setState((prev) => ({ ...prev, isSidebarOpen: open }))
|
|
151
|
-
}, [])
|
|
152
|
-
|
|
153
|
-
const setInspectorMode = useCallback((enabled: boolean) => {
|
|
154
|
-
setState((prev) => ({ ...prev, isInspectorMode: enabled }))
|
|
155
|
-
}, [])
|
|
156
|
-
|
|
157
|
-
const openIssueDialog = useCallback(
|
|
158
|
-
(
|
|
159
|
-
type: 'bug' | 'feature',
|
|
160
|
-
description?: string,
|
|
161
|
-
componentDetails?: ComponentDetails[],
|
|
162
|
-
) => {
|
|
163
|
-
setState((prev) => ({
|
|
164
|
-
...prev,
|
|
165
|
-
issueDialog: {
|
|
166
|
-
isOpen: true,
|
|
167
|
-
type,
|
|
168
|
-
initialDescription: description,
|
|
169
|
-
componentDetails,
|
|
170
|
-
},
|
|
171
|
-
}))
|
|
172
|
-
},
|
|
173
|
-
[],
|
|
174
|
-
)
|
|
175
|
-
|
|
176
|
-
const closeIssueDialog = useCallback(() => {
|
|
177
|
-
setState((prev) => ({
|
|
178
|
-
...prev,
|
|
179
|
-
issueDialog: { ...prev.issueDialog, isOpen: false },
|
|
180
|
-
}))
|
|
181
|
-
}, [])
|
|
182
|
-
|
|
183
|
-
if (!resolvedAllowed) {
|
|
184
|
-
return <>{children}</>
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
return (
|
|
188
|
-
<DevModeContext.Provider
|
|
189
|
-
value={{
|
|
190
|
-
...state,
|
|
191
|
-
toggleDevMode,
|
|
192
|
-
toggleSidebar,
|
|
193
|
-
toggleInspector,
|
|
194
|
-
setDevMode,
|
|
195
|
-
setSidebarOpen,
|
|
196
|
-
setInspectorMode,
|
|
197
|
-
openIssueDialog,
|
|
198
|
-
closeIssueDialog,
|
|
199
|
-
}}
|
|
200
|
-
>
|
|
201
|
-
{children}
|
|
202
|
-
</DevModeContext.Provider>
|
|
203
|
-
)
|
|
204
|
-
})
|
|
205
|
-
|
|
206
|
-
export function useIsDevToolsVisible(): boolean {
|
|
207
|
-
const context = useDevModeOptional()
|
|
208
|
-
if (!context) return false
|
|
209
|
-
return context.isDevMode
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
export function useIsDevAllowed(isAllowed?: boolean): boolean {
|
|
213
|
-
return isAllowed ?? resolveDevAllowed()
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
function resolveDevAllowed(): boolean {
|
|
217
|
-
try {
|
|
218
|
-
// @ts-expect-error — Vite env
|
|
219
|
-
if (import.meta?.env?.VITE_CONVEX_IS_DEV === 'true') return true
|
|
220
|
-
// @ts-expect-error — Vite env
|
|
221
|
-
if (import.meta?.env?.DEV) return true
|
|
222
|
-
} catch {
|
|
223
|
-
// Not in Vite
|
|
224
|
-
}
|
|
225
|
-
return false
|
|
226
|
-
}
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
// @geenius-tools/devtools-react — src/context/PerformanceContext.tsx
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
createContext,
|
|
5
|
-
useContext,
|
|
6
|
-
useState,
|
|
7
|
-
useEffect,
|
|
8
|
-
useCallback,
|
|
9
|
-
type ReactNode,
|
|
10
|
-
memo,
|
|
11
|
-
} from 'react'
|
|
12
|
-
import { metricsStore, type PerformanceMetric } from '@geenius-tools/logger'
|
|
13
|
-
|
|
14
|
-
const MAX_METRICS = 100
|
|
15
|
-
|
|
16
|
-
interface PerformanceContextValue {
|
|
17
|
-
isPerformancePanelOpen: boolean
|
|
18
|
-
metrics: PerformanceMetric[]
|
|
19
|
-
filters: {
|
|
20
|
-
network: boolean
|
|
21
|
-
query: boolean
|
|
22
|
-
mutation: boolean
|
|
23
|
-
render: boolean
|
|
24
|
-
route: boolean
|
|
25
|
-
}
|
|
26
|
-
stats: {
|
|
27
|
-
totalRequests: number
|
|
28
|
-
avgDuration: number
|
|
29
|
-
slowRequests: number
|
|
30
|
-
fastRequests: number
|
|
31
|
-
}
|
|
32
|
-
togglePerformancePanel: () => void
|
|
33
|
-
clearMetrics: () => void
|
|
34
|
-
toggleFilter: (filter: keyof PerformanceContextValue['filters']) => void
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const PerformanceContext = createContext<PerformanceContextValue | undefined>(
|
|
38
|
-
undefined,
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
export function usePerformanceContext() {
|
|
42
|
-
const context = useContext(PerformanceContext)
|
|
43
|
-
if (!context) {
|
|
44
|
-
throw new Error(
|
|
45
|
-
'usePerformanceContext must be used within PerformanceProvider',
|
|
46
|
-
)
|
|
47
|
-
}
|
|
48
|
-
return context
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export function usePerformanceContextOptional(): PerformanceContextValue | null {
|
|
52
|
-
return useContext(PerformanceContext) ?? null
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
interface PerformanceProviderProps {
|
|
56
|
-
children: ReactNode
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export const PerformanceProvider = memo(function PerformanceProvider({
|
|
60
|
-
children,
|
|
61
|
-
}: PerformanceProviderProps) {
|
|
62
|
-
const [isPerformancePanelOpen, setIsPerformancePanelOpen] = useState(false)
|
|
63
|
-
const [metrics, setMetrics] = useState<PerformanceMetric[]>([])
|
|
64
|
-
const [filters, setFilters] = useState({
|
|
65
|
-
network: true,
|
|
66
|
-
query: true,
|
|
67
|
-
mutation: true,
|
|
68
|
-
render: true,
|
|
69
|
-
route: true,
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
useEffect(() => {
|
|
73
|
-
const unsubscribe = metricsStore.subscribe((newMetrics) => {
|
|
74
|
-
setMetrics((prev) => {
|
|
75
|
-
const combined = [...prev, ...newMetrics]
|
|
76
|
-
if (combined.length > MAX_METRICS) {
|
|
77
|
-
return combined.slice(-MAX_METRICS)
|
|
78
|
-
}
|
|
79
|
-
return combined
|
|
80
|
-
})
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
return () => unsubscribe()
|
|
84
|
-
}, [])
|
|
85
|
-
|
|
86
|
-
const stats = useCallback(() => {
|
|
87
|
-
const filtered = metrics.filter((m) => m.duration !== undefined)
|
|
88
|
-
const total = filtered.length
|
|
89
|
-
|
|
90
|
-
if (total === 0) {
|
|
91
|
-
return {
|
|
92
|
-
totalRequests: 0,
|
|
93
|
-
avgDuration: 0,
|
|
94
|
-
slowRequests: 0,
|
|
95
|
-
fastRequests: 0,
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const durations = filtered.map((m) => m.duration!)
|
|
100
|
-
const avg = durations.reduce((a, b) => a + b, 0) / total
|
|
101
|
-
const slow = durations.filter((d) => d > 100).length
|
|
102
|
-
const fast = durations.filter((d) => d < 50).length
|
|
103
|
-
|
|
104
|
-
return {
|
|
105
|
-
totalRequests: total,
|
|
106
|
-
avgDuration: Math.round(avg * 100) / 100,
|
|
107
|
-
slowRequests: slow,
|
|
108
|
-
fastRequests: fast,
|
|
109
|
-
}
|
|
110
|
-
}, [metrics])
|
|
111
|
-
|
|
112
|
-
const togglePerformancePanel = useCallback(() => {
|
|
113
|
-
setIsPerformancePanelOpen((prev) => !prev)
|
|
114
|
-
}, [])
|
|
115
|
-
|
|
116
|
-
const clearMetrics = useCallback(() => {
|
|
117
|
-
setMetrics([])
|
|
118
|
-
metricsStore.clear()
|
|
119
|
-
}, [])
|
|
120
|
-
|
|
121
|
-
const toggleFilter = useCallback((filter: keyof typeof filters) => {
|
|
122
|
-
setFilters((prev) => ({
|
|
123
|
-
...prev,
|
|
124
|
-
[filter]: !prev[filter],
|
|
125
|
-
}))
|
|
126
|
-
}, [])
|
|
127
|
-
|
|
128
|
-
return (
|
|
129
|
-
<PerformanceContext.Provider
|
|
130
|
-
value={{
|
|
131
|
-
isPerformancePanelOpen,
|
|
132
|
-
metrics,
|
|
133
|
-
filters,
|
|
134
|
-
stats: stats(),
|
|
135
|
-
togglePerformancePanel,
|
|
136
|
-
clearMetrics,
|
|
137
|
-
toggleFilter,
|
|
138
|
-
}}
|
|
139
|
-
>
|
|
140
|
-
{children}
|
|
141
|
-
</PerformanceContext.Provider>
|
|
142
|
-
)
|
|
143
|
-
})
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
// @geenius-tools/devtools — data/designs.ts
|
|
2
|
-
|
|
3
|
-
export interface Design {
|
|
4
|
-
id: string
|
|
5
|
-
name: string
|
|
6
|
-
path: string
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export const designs: Design[] = Array.from({ length: 21 }, (_, i) => ({
|
|
10
|
-
id: String(i + 1),
|
|
11
|
-
name: `Design ${i + 1}`,
|
|
12
|
-
path: `/dev/design/${i + 1}`,
|
|
13
|
-
}))
|