@qwickapps/server 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (240) hide show
  1. package/README.md +238 -0
  2. package/dist/core/control-panel.d.ts +7 -2
  3. package/dist/core/control-panel.d.ts.map +1 -1
  4. package/dist/core/control-panel.js +92 -54
  5. package/dist/core/control-panel.js.map +1 -1
  6. package/dist/core/gateway.d.ts +159 -79
  7. package/dist/core/gateway.d.ts.map +1 -1
  8. package/dist/core/gateway.js +679 -319
  9. package/dist/core/gateway.js.map +1 -1
  10. package/dist/core/index.d.ts +3 -1
  11. package/dist/core/index.d.ts.map +1 -1
  12. package/dist/core/index.js +2 -0
  13. package/dist/core/index.js.map +1 -1
  14. package/dist/core/plugin-registry.d.ts +271 -0
  15. package/dist/core/plugin-registry.d.ts.map +1 -0
  16. package/dist/core/plugin-registry.js +326 -0
  17. package/dist/core/plugin-registry.js.map +1 -0
  18. package/dist/core/types.d.ts +16 -33
  19. package/dist/core/types.d.ts.map +1 -1
  20. package/dist/index.d.ts +8 -5
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +15 -7
  23. package/dist/index.js.map +1 -1
  24. package/dist/plugins/auth/adapters/auth0-adapter.d.ts +14 -0
  25. package/dist/plugins/auth/adapters/auth0-adapter.d.ts.map +1 -0
  26. package/dist/plugins/auth/adapters/auth0-adapter.js +179 -0
  27. package/dist/plugins/auth/adapters/auth0-adapter.js.map +1 -0
  28. package/dist/plugins/auth/adapters/basic-adapter.d.ts +13 -0
  29. package/dist/plugins/auth/adapters/basic-adapter.d.ts.map +1 -0
  30. package/dist/plugins/auth/adapters/basic-adapter.js +51 -0
  31. package/dist/plugins/auth/adapters/basic-adapter.js.map +1 -0
  32. package/dist/plugins/auth/adapters/index.d.ts +9 -0
  33. package/dist/plugins/auth/adapters/index.d.ts.map +1 -0
  34. package/dist/plugins/auth/adapters/index.js +9 -0
  35. package/dist/plugins/auth/adapters/index.js.map +1 -0
  36. package/dist/plugins/auth/adapters/supabase-adapter.d.ts +13 -0
  37. package/dist/plugins/auth/adapters/supabase-adapter.d.ts.map +1 -0
  38. package/dist/plugins/auth/adapters/supabase-adapter.js +109 -0
  39. package/dist/plugins/auth/adapters/supabase-adapter.js.map +1 -0
  40. package/dist/plugins/auth/auth-plugin.d.ts +40 -0
  41. package/dist/plugins/auth/auth-plugin.d.ts.map +1 -0
  42. package/dist/plugins/auth/auth-plugin.js +255 -0
  43. package/dist/plugins/auth/auth-plugin.js.map +1 -0
  44. package/dist/plugins/auth/auth-plugin.test.d.ts +9 -0
  45. package/dist/plugins/auth/auth-plugin.test.d.ts.map +1 -0
  46. package/dist/plugins/auth/auth-plugin.test.js +147 -0
  47. package/dist/plugins/auth/auth-plugin.test.js.map +1 -0
  48. package/dist/plugins/auth/index.d.ts +12 -0
  49. package/dist/plugins/auth/index.d.ts.map +1 -0
  50. package/dist/plugins/auth/index.js +13 -0
  51. package/dist/plugins/auth/index.js.map +1 -0
  52. package/dist/plugins/auth/types.d.ts +148 -0
  53. package/dist/plugins/auth/types.d.ts.map +1 -0
  54. package/dist/plugins/auth/types.js +14 -0
  55. package/dist/plugins/auth/types.js.map +1 -0
  56. package/dist/plugins/bans/bans-plugin.d.ts +59 -0
  57. package/dist/plugins/bans/bans-plugin.d.ts.map +1 -0
  58. package/dist/plugins/bans/bans-plugin.js +428 -0
  59. package/dist/plugins/bans/bans-plugin.js.map +1 -0
  60. package/dist/plugins/bans/index.d.ts +9 -0
  61. package/dist/plugins/bans/index.d.ts.map +1 -0
  62. package/dist/plugins/bans/index.js +10 -0
  63. package/dist/plugins/bans/index.js.map +1 -0
  64. package/dist/plugins/bans/stores/index.d.ts +7 -0
  65. package/dist/plugins/bans/stores/index.d.ts.map +1 -0
  66. package/dist/plugins/bans/stores/index.js +7 -0
  67. package/dist/plugins/bans/stores/index.js.map +1 -0
  68. package/dist/plugins/bans/stores/postgres-store.d.ts +29 -0
  69. package/dist/plugins/bans/stores/postgres-store.d.ts.map +1 -0
  70. package/dist/plugins/bans/stores/postgres-store.js +132 -0
  71. package/dist/plugins/bans/stores/postgres-store.js.map +1 -0
  72. package/dist/plugins/bans/types.d.ts +128 -0
  73. package/dist/plugins/bans/types.d.ts.map +1 -0
  74. package/dist/plugins/bans/types.js +11 -0
  75. package/dist/plugins/bans/types.js.map +1 -0
  76. package/dist/plugins/cache-plugin.d.ts +14 -3
  77. package/dist/plugins/cache-plugin.d.ts.map +1 -1
  78. package/dist/plugins/cache-plugin.js +27 -7
  79. package/dist/plugins/cache-plugin.js.map +1 -1
  80. package/dist/plugins/cache-plugin.test.js +96 -32
  81. package/dist/plugins/cache-plugin.test.js.map +1 -1
  82. package/dist/plugins/config-plugin.d.ts +3 -2
  83. package/dist/plugins/config-plugin.d.ts.map +1 -1
  84. package/dist/plugins/config-plugin.js +17 -10
  85. package/dist/plugins/config-plugin.js.map +1 -1
  86. package/dist/plugins/diagnostics-plugin.d.ts +2 -2
  87. package/dist/plugins/diagnostics-plugin.d.ts.map +1 -1
  88. package/dist/plugins/diagnostics-plugin.js +17 -10
  89. package/dist/plugins/diagnostics-plugin.js.map +1 -1
  90. package/dist/plugins/entitlements/entitlements-plugin.d.ts +95 -0
  91. package/dist/plugins/entitlements/entitlements-plugin.d.ts.map +1 -0
  92. package/dist/plugins/entitlements/entitlements-plugin.js +707 -0
  93. package/dist/plugins/entitlements/entitlements-plugin.js.map +1 -0
  94. package/dist/plugins/entitlements/index.d.ts +12 -0
  95. package/dist/plugins/entitlements/index.d.ts.map +1 -0
  96. package/dist/plugins/entitlements/index.js +16 -0
  97. package/dist/plugins/entitlements/index.js.map +1 -0
  98. package/dist/plugins/entitlements/sources/index.d.ts +9 -0
  99. package/dist/plugins/entitlements/sources/index.d.ts.map +1 -0
  100. package/dist/plugins/entitlements/sources/index.js +9 -0
  101. package/dist/plugins/entitlements/sources/index.js.map +1 -0
  102. package/dist/plugins/entitlements/sources/postgres-source.d.ts +29 -0
  103. package/dist/plugins/entitlements/sources/postgres-source.d.ts.map +1 -0
  104. package/dist/plugins/entitlements/sources/postgres-source.js +169 -0
  105. package/dist/plugins/entitlements/sources/postgres-source.js.map +1 -0
  106. package/dist/plugins/entitlements/types.d.ts +232 -0
  107. package/dist/plugins/entitlements/types.d.ts.map +1 -0
  108. package/dist/plugins/entitlements/types.js +11 -0
  109. package/dist/plugins/entitlements/types.js.map +1 -0
  110. package/dist/plugins/frontend-app-plugin.d.ts +9 -3
  111. package/dist/plugins/frontend-app-plugin.d.ts.map +1 -1
  112. package/dist/plugins/frontend-app-plugin.js +14 -9
  113. package/dist/plugins/frontend-app-plugin.js.map +1 -1
  114. package/dist/plugins/health-plugin.d.ts +5 -2
  115. package/dist/plugins/health-plugin.d.ts.map +1 -1
  116. package/dist/plugins/health-plugin.js +20 -5
  117. package/dist/plugins/health-plugin.js.map +1 -1
  118. package/dist/plugins/index.d.ts +8 -2
  119. package/dist/plugins/index.d.ts.map +1 -1
  120. package/dist/plugins/index.js +8 -2
  121. package/dist/plugins/index.js.map +1 -1
  122. package/dist/plugins/logs-plugin.d.ts +3 -2
  123. package/dist/plugins/logs-plugin.d.ts.map +1 -1
  124. package/dist/plugins/logs-plugin.js +21 -12
  125. package/dist/plugins/logs-plugin.js.map +1 -1
  126. package/dist/plugins/postgres-plugin.d.ts +3 -3
  127. package/dist/plugins/postgres-plugin.d.ts.map +1 -1
  128. package/dist/plugins/postgres-plugin.js +9 -7
  129. package/dist/plugins/postgres-plugin.js.map +1 -1
  130. package/dist/plugins/postgres-plugin.test.js +47 -29
  131. package/dist/plugins/postgres-plugin.test.js.map +1 -1
  132. package/dist/plugins/users/index.d.ts +12 -0
  133. package/dist/plugins/users/index.d.ts.map +1 -0
  134. package/dist/plugins/users/index.js +13 -0
  135. package/dist/plugins/users/index.js.map +1 -0
  136. package/dist/plugins/users/stores/index.d.ts +7 -0
  137. package/dist/plugins/users/stores/index.d.ts.map +1 -0
  138. package/dist/plugins/users/stores/index.js +7 -0
  139. package/dist/plugins/users/stores/index.js.map +1 -0
  140. package/dist/plugins/users/stores/postgres-store.d.ts +28 -0
  141. package/dist/plugins/users/stores/postgres-store.d.ts.map +1 -0
  142. package/dist/plugins/users/stores/postgres-store.js +157 -0
  143. package/dist/plugins/users/stores/postgres-store.js.map +1 -0
  144. package/dist/plugins/users/types.d.ts +189 -0
  145. package/dist/plugins/users/types.d.ts.map +1 -0
  146. package/dist/plugins/users/types.js +12 -0
  147. package/dist/plugins/users/types.js.map +1 -0
  148. package/dist/plugins/users/users-plugin.d.ts +39 -0
  149. package/dist/plugins/users/users-plugin.d.ts.map +1 -0
  150. package/dist/plugins/users/users-plugin.js +242 -0
  151. package/dist/plugins/users/users-plugin.js.map +1 -0
  152. package/dist-ui/assets/index-Bsp2ntcw.js +465 -0
  153. package/dist-ui/assets/index-Bsp2ntcw.js.map +1 -0
  154. package/dist-ui/index.html +1 -1
  155. package/dist-ui-lib/api/controlPanelApi.d.ts +232 -0
  156. package/dist-ui-lib/components/ControlPanelApp.d.ts +61 -0
  157. package/dist-ui-lib/components/index.d.ts +18 -0
  158. package/dist-ui-lib/config/AppConfig.d.ts +7 -0
  159. package/dist-ui-lib/dashboard/DashboardWidgetRegistry.d.ts +62 -0
  160. package/dist-ui-lib/dashboard/DashboardWidgetRenderer.d.ts +8 -0
  161. package/dist-ui-lib/dashboard/PluginWidgetRenderer.d.ts +19 -0
  162. package/dist-ui-lib/dashboard/WidgetComponentRegistry.d.ts +44 -0
  163. package/dist-ui-lib/dashboard/builtInWidgets.d.ts +19 -0
  164. package/dist-ui-lib/dashboard/index.d.ts +13 -0
  165. package/dist-ui-lib/dashboard/widgets/ServiceHealthWidget.d.ts +12 -0
  166. package/dist-ui-lib/dashboard/widgets/index.d.ts +6 -0
  167. package/dist-ui-lib/index.js +6441 -0
  168. package/dist-ui-lib/index.js.map +1 -0
  169. package/dist-ui-lib/pages/ConfigPage.d.ts +1 -0
  170. package/dist-ui-lib/pages/DashboardPage.d.ts +1 -0
  171. package/dist-ui-lib/pages/DiagnosticsPage.d.ts +1 -0
  172. package/dist-ui-lib/pages/EntitlementsPage.d.ts +17 -0
  173. package/dist-ui-lib/pages/LogsPage.d.ts +1 -0
  174. package/dist-ui-lib/pages/NotFoundPage.d.ts +1 -0
  175. package/dist-ui-lib/pages/PluginPage.d.ts +15 -0
  176. package/dist-ui-lib/pages/SystemPage.d.ts +1 -0
  177. package/dist-ui-lib/pages/UsersPage.d.ts +22 -0
  178. package/package.json +18 -6
  179. package/src/core/control-panel.ts +114 -61
  180. package/src/core/gateway.ts +863 -403
  181. package/src/core/index.ts +21 -2
  182. package/src/core/plugin-registry.ts +653 -0
  183. package/src/core/types.ts +31 -37
  184. package/src/index.ts +118 -19
  185. package/src/plugins/auth/adapters/auth0-adapter.ts +214 -0
  186. package/src/plugins/auth/adapters/basic-adapter.ts +61 -0
  187. package/src/plugins/auth/adapters/index.ts +9 -0
  188. package/src/plugins/auth/adapters/supabase-adapter.ts +141 -0
  189. package/src/plugins/auth/auth-plugin.test.ts +176 -0
  190. package/src/plugins/auth/auth-plugin.ts +303 -0
  191. package/src/plugins/auth/index.ts +33 -0
  192. package/src/plugins/auth/types.ts +165 -0
  193. package/src/plugins/bans/bans-plugin.ts +485 -0
  194. package/src/plugins/bans/index.ts +31 -0
  195. package/src/plugins/bans/stores/index.ts +7 -0
  196. package/src/plugins/bans/stores/postgres-store.ts +195 -0
  197. package/src/plugins/bans/types.ts +141 -0
  198. package/src/plugins/cache-plugin.test.ts +105 -32
  199. package/src/plugins/cache-plugin.ts +40 -9
  200. package/src/plugins/config-plugin.ts +23 -12
  201. package/src/plugins/diagnostics-plugin.ts +22 -12
  202. package/src/plugins/entitlements/entitlements-plugin.ts +820 -0
  203. package/src/plugins/entitlements/index.ts +51 -0
  204. package/src/plugins/entitlements/sources/index.ts +9 -0
  205. package/src/plugins/entitlements/sources/postgres-source.ts +253 -0
  206. package/src/plugins/entitlements/types.ts +256 -0
  207. package/src/plugins/frontend-app-plugin.ts +24 -12
  208. package/src/plugins/health-plugin.ts +27 -7
  209. package/src/plugins/index.ts +106 -4
  210. package/src/plugins/logs-plugin.ts +28 -14
  211. package/src/plugins/postgres-plugin.test.ts +49 -29
  212. package/src/plugins/postgres-plugin.ts +11 -9
  213. package/src/plugins/users/index.ts +35 -0
  214. package/src/plugins/users/stores/index.ts +7 -0
  215. package/src/plugins/users/stores/postgres-store.ts +225 -0
  216. package/src/plugins/users/types.ts +209 -0
  217. package/src/plugins/users/users-plugin.ts +281 -0
  218. package/ui/src/App.tsx +185 -31
  219. package/ui/src/api/controlPanelApi.ts +354 -1
  220. package/ui/src/components/ControlPanelApp.tsx +209 -0
  221. package/ui/src/components/index.ts +62 -0
  222. package/ui/src/dashboard/DashboardWidgetRegistry.tsx +129 -0
  223. package/ui/src/dashboard/DashboardWidgetRenderer.tsx +34 -0
  224. package/ui/src/dashboard/PluginWidgetRenderer.tsx +115 -0
  225. package/ui/src/dashboard/WidgetComponentRegistry.tsx +116 -0
  226. package/ui/src/dashboard/builtInWidgets.tsx +29 -0
  227. package/ui/src/dashboard/index.ts +35 -0
  228. package/ui/src/dashboard/widgets/ServiceHealthWidget.tsx +140 -0
  229. package/ui/src/dashboard/widgets/index.ts +7 -0
  230. package/ui/src/pages/DashboardPage.tsx +28 -149
  231. package/ui/src/pages/EntitlementsPage.tsx +557 -0
  232. package/ui/src/pages/LogsPage.tsx +174 -8
  233. package/ui/src/pages/PluginPage.tsx +148 -0
  234. package/ui/src/pages/SystemPage.tsx +445 -0
  235. package/ui/src/pages/UsersPage.tsx +837 -0
  236. package/ui/tsconfig.lib.json +11 -0
  237. package/ui/vite.lib.config.ts +51 -0
  238. package/dist-ui/assets/index-CW1BviRn.js +0 -465
  239. package/dist-ui/assets/index-CW1BviRn.js.map +0 -1
  240. package/ui/src/pages/HealthPage.tsx +0 -204
@@ -0,0 +1,445 @@
1
+ import { useState, useEffect } from 'react';
2
+ import {
3
+ Box,
4
+ Card,
5
+ CardContent,
6
+ Typography,
7
+ Grid,
8
+ CircularProgress,
9
+ Chip,
10
+ IconButton,
11
+ Tooltip,
12
+ Snackbar,
13
+ Alert,
14
+ LinearProgress,
15
+ Table,
16
+ TableBody,
17
+ TableCell,
18
+ TableContainer,
19
+ TableHead,
20
+ TableRow,
21
+ } from '@mui/material';
22
+ import ContentCopyIcon from '@mui/icons-material/ContentCopy';
23
+ import RefreshIcon from '@mui/icons-material/Refresh';
24
+ import MemoryIcon from '@mui/icons-material/Memory';
25
+ import ComputerIcon from '@mui/icons-material/Computer';
26
+ import StorageIcon from '@mui/icons-material/Storage';
27
+ import AccessTimeIcon from '@mui/icons-material/AccessTime';
28
+ import CheckCircleIcon from '@mui/icons-material/CheckCircle';
29
+ import ErrorIcon from '@mui/icons-material/Error';
30
+ import WarningIcon from '@mui/icons-material/Warning';
31
+ import FavoriteIcon from '@mui/icons-material/Favorite';
32
+ import { api, DiagnosticsResponse, HealthResponse } from '../api/controlPanelApi';
33
+
34
+ function formatBytes(bytes: number): string {
35
+ if (bytes === 0) return '0 B';
36
+ const k = 1024;
37
+ const sizes = ['B', 'KB', 'MB', 'GB'];
38
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
39
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
40
+ }
41
+
42
+ function formatUptime(ms: number): string {
43
+ const seconds = Math.floor(ms / 1000);
44
+ const minutes = Math.floor(seconds / 60);
45
+ const hours = Math.floor(minutes / 60);
46
+ const days = Math.floor(hours / 24);
47
+
48
+ if (days > 0) {
49
+ return `${days}d ${hours % 24}h ${minutes % 60}m`;
50
+ }
51
+ if (hours > 0) {
52
+ return `${hours}h ${minutes % 60}m ${seconds % 60}s`;
53
+ }
54
+ if (minutes > 0) {
55
+ return `${minutes}m ${seconds % 60}s`;
56
+ }
57
+ return `${seconds}s`;
58
+ }
59
+
60
+ function getHealthStatusIcon(status: string, size = 20) {
61
+ switch (status) {
62
+ case 'healthy':
63
+ return <CheckCircleIcon sx={{ color: 'var(--theme-success)', fontSize: size }} />;
64
+ case 'degraded':
65
+ return <WarningIcon sx={{ color: 'var(--theme-warning)', fontSize: size }} />;
66
+ case 'unhealthy':
67
+ return <ErrorIcon sx={{ color: 'var(--theme-error)', fontSize: size }} />;
68
+ default:
69
+ return <CircularProgress size={size} />;
70
+ }
71
+ }
72
+
73
+ function getHealthStatusColor(status: string): string {
74
+ switch (status) {
75
+ case 'healthy':
76
+ return 'var(--theme-success)';
77
+ case 'degraded':
78
+ return 'var(--theme-warning)';
79
+ case 'unhealthy':
80
+ return 'var(--theme-error)';
81
+ default:
82
+ return 'var(--theme-text-secondary)';
83
+ }
84
+ }
85
+
86
+ function formatLatency(latency?: number): string {
87
+ if (latency === undefined) return '-';
88
+ if (latency < 1000) return `${latency}ms`;
89
+ return `${(latency / 1000).toFixed(2)}s`;
90
+ }
91
+
92
+ export function SystemPage() {
93
+ const [diagnostics, setDiagnostics] = useState<DiagnosticsResponse | null>(null);
94
+ const [health, setHealth] = useState<HealthResponse | null>(null);
95
+ const [loading, setLoading] = useState(true);
96
+ const [error, setError] = useState<string | null>(null);
97
+ const [snackbar, setSnackbar] = useState<{ open: boolean; message: string }>({
98
+ open: false,
99
+ message: '',
100
+ });
101
+
102
+ const fetchData = async () => {
103
+ setLoading(true);
104
+ try {
105
+ const [diagData, healthData] = await Promise.all([
106
+ api.getDiagnostics(),
107
+ api.getHealth().catch(() => null), // Health might not be available
108
+ ]);
109
+ setDiagnostics(diagData);
110
+ setHealth(healthData);
111
+ setError(null);
112
+ } catch (err) {
113
+ setError(err instanceof Error ? err.message : 'Failed to fetch diagnostics');
114
+ } finally {
115
+ setLoading(false);
116
+ }
117
+ };
118
+
119
+ useEffect(() => {
120
+ fetchData();
121
+ const interval = setInterval(fetchData, 30000);
122
+ return () => clearInterval(interval);
123
+ }, []);
124
+
125
+ const handleCopyAll = () => {
126
+ navigator.clipboard.writeText(JSON.stringify(diagnostics, null, 2));
127
+ setSnackbar({ open: true, message: 'Diagnostics copied to clipboard' });
128
+ };
129
+
130
+ if (loading && !diagnostics) {
131
+ return (
132
+ <Box sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center', minHeight: '50vh' }}>
133
+ <CircularProgress />
134
+ </Box>
135
+ );
136
+ }
137
+
138
+ if (error) {
139
+ return (
140
+ <Card sx={{ bgcolor: 'var(--theme-surface)', border: '1px solid var(--theme-error)' }}>
141
+ <CardContent>
142
+ <Typography color="error">{error}</Typography>
143
+ </CardContent>
144
+ </Card>
145
+ );
146
+ }
147
+
148
+ const memoryUsedPercent = diagnostics
149
+ ? (diagnostics.system.memory.used / diagnostics.system.memory.total) * 100
150
+ : 0;
151
+
152
+ return (
153
+ <Box>
154
+ <Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 1 }}>
155
+ <Typography variant="h4" sx={{ color: 'var(--theme-text-primary)' }}>
156
+ System
157
+ </Typography>
158
+ <Box sx={{ display: 'flex', gap: 1 }}>
159
+ <Tooltip title="Copy diagnostics JSON">
160
+ <IconButton onClick={handleCopyAll} sx={{ color: 'var(--theme-primary)' }}>
161
+ <ContentCopyIcon />
162
+ </IconButton>
163
+ </Tooltip>
164
+ <Tooltip title="Refresh">
165
+ <IconButton onClick={fetchData} sx={{ color: 'var(--theme-primary)' }}>
166
+ <RefreshIcon />
167
+ </IconButton>
168
+ </Tooltip>
169
+ </Box>
170
+ </Box>
171
+ <Typography variant="body2" sx={{ mb: 4, color: 'var(--theme-text-secondary)' }}>
172
+ System information and diagnostics
173
+ </Typography>
174
+
175
+ <Grid container spacing={3}>
176
+ {/* System Info */}
177
+ <Grid size={{ xs: 12, md: 6 }}>
178
+ <Card sx={{ bgcolor: 'var(--theme-surface)', height: '100%' }}>
179
+ <CardContent>
180
+ <Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 3 }}>
181
+ <ComputerIcon sx={{ color: 'var(--theme-primary)' }} />
182
+ <Typography variant="h6" sx={{ color: 'var(--theme-text-primary)' }}>
183
+ System Information
184
+ </Typography>
185
+ </Box>
186
+ <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
187
+ <Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
188
+ <Typography sx={{ color: 'var(--theme-text-secondary)' }}>QwickApps Server</Typography>
189
+ <Chip
190
+ label={diagnostics?.frameworkVersion ? `v${diagnostics.frameworkVersion}` : 'N/A'}
191
+ size="small"
192
+ sx={{ bgcolor: 'var(--theme-primary)20', color: 'var(--theme-primary)' }}
193
+ />
194
+ </Box>
195
+ <Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
196
+ <Typography sx={{ color: 'var(--theme-text-secondary)' }}>Node.js</Typography>
197
+ <Chip
198
+ label={diagnostics?.system.nodeVersion}
199
+ size="small"
200
+ sx={{ bgcolor: 'var(--theme-background)', color: 'var(--theme-text-primary)' }}
201
+ />
202
+ </Box>
203
+ <Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
204
+ <Typography sx={{ color: 'var(--theme-text-secondary)' }}>Platform</Typography>
205
+ <Chip
206
+ label={diagnostics?.system.platform}
207
+ size="small"
208
+ sx={{ bgcolor: 'var(--theme-background)', color: 'var(--theme-text-primary)' }}
209
+ />
210
+ </Box>
211
+ <Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
212
+ <Typography sx={{ color: 'var(--theme-text-secondary)' }}>Architecture</Typography>
213
+ <Chip
214
+ label={diagnostics?.system.arch}
215
+ size="small"
216
+ sx={{ bgcolor: 'var(--theme-background)', color: 'var(--theme-text-primary)' }}
217
+ />
218
+ </Box>
219
+ </Box>
220
+ </CardContent>
221
+ </Card>
222
+ </Grid>
223
+
224
+ {/* Memory Usage */}
225
+ <Grid size={{ xs: 12, md: 6 }}>
226
+ <Card sx={{ bgcolor: 'var(--theme-surface)', height: '100%' }}>
227
+ <CardContent>
228
+ <Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 3 }}>
229
+ <MemoryIcon sx={{ color: 'var(--theme-warning)' }} />
230
+ <Typography variant="h6" sx={{ color: 'var(--theme-text-primary)' }}>
231
+ Memory Usage
232
+ </Typography>
233
+ </Box>
234
+ <Box sx={{ mb: 2 }}>
235
+ <Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 1 }}>
236
+ <Typography sx={{ color: 'var(--theme-text-secondary)' }}>
237
+ Heap Used
238
+ </Typography>
239
+ <Typography sx={{ color: 'var(--theme-text-primary)' }}>
240
+ {formatBytes(diagnostics?.system.memory.used || 0)}
241
+ </Typography>
242
+ </Box>
243
+ <LinearProgress
244
+ variant="determinate"
245
+ value={memoryUsedPercent}
246
+ sx={{
247
+ height: 8,
248
+ borderRadius: 4,
249
+ bgcolor: 'var(--theme-background)',
250
+ '& .MuiLinearProgress-bar': {
251
+ bgcolor: memoryUsedPercent > 80 ? 'var(--theme-error)' : 'var(--theme-warning)',
252
+ borderRadius: 4,
253
+ },
254
+ }}
255
+ />
256
+ </Box>
257
+ <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
258
+ <Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
259
+ <Typography sx={{ color: 'var(--theme-text-secondary)' }}>Heap Total</Typography>
260
+ <Typography sx={{ color: 'var(--theme-text-primary)' }}>
261
+ {formatBytes(diagnostics?.system.memory.total || 0)}
262
+ </Typography>
263
+ </Box>
264
+ <Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
265
+ <Typography sx={{ color: 'var(--theme-text-secondary)' }}>Heap Free</Typography>
266
+ <Typography sx={{ color: 'var(--theme-text-primary)' }}>
267
+ {formatBytes(diagnostics?.system.memory.free || 0)}
268
+ </Typography>
269
+ </Box>
270
+ </Box>
271
+ </CardContent>
272
+ </Card>
273
+ </Grid>
274
+
275
+ {/* Service Info */}
276
+ <Grid size={{ xs: 12, md: 6 }}>
277
+ <Card sx={{ bgcolor: 'var(--theme-surface)', height: '100%' }}>
278
+ <CardContent>
279
+ <Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 3 }}>
280
+ <StorageIcon sx={{ color: 'var(--theme-info)' }} />
281
+ <Typography variant="h6" sx={{ color: 'var(--theme-text-primary)' }}>
282
+ Service Info
283
+ </Typography>
284
+ </Box>
285
+ <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
286
+ <Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
287
+ <Typography sx={{ color: 'var(--theme-text-secondary)' }}>Product</Typography>
288
+ <Typography sx={{ color: 'var(--theme-text-primary)' }}>
289
+ {diagnostics?.product}
290
+ </Typography>
291
+ </Box>
292
+ <Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
293
+ <Typography sx={{ color: 'var(--theme-text-secondary)' }}>Version</Typography>
294
+ <Chip
295
+ label={diagnostics?.version || 'N/A'}
296
+ size="small"
297
+ sx={{ bgcolor: 'var(--theme-primary)20', color: 'var(--theme-primary)' }}
298
+ />
299
+ </Box>
300
+ <Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
301
+ <Typography sx={{ color: 'var(--theme-text-secondary)' }}>Timestamp</Typography>
302
+ <Typography sx={{ color: 'var(--theme-text-primary)', fontSize: '0.875rem' }}>
303
+ {diagnostics?.timestamp ? new Date(diagnostics.timestamp).toLocaleString() : 'N/A'}
304
+ </Typography>
305
+ </Box>
306
+ </Box>
307
+ </CardContent>
308
+ </Card>
309
+ </Grid>
310
+
311
+ {/* Uptime */}
312
+ <Grid size={{ xs: 12, md: 6 }}>
313
+ <Card sx={{ bgcolor: 'var(--theme-surface)', height: '100%' }}>
314
+ <CardContent>
315
+ <Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 3 }}>
316
+ <AccessTimeIcon sx={{ color: 'var(--theme-success)' }} />
317
+ <Typography variant="h6" sx={{ color: 'var(--theme-text-primary)' }}>
318
+ Uptime
319
+ </Typography>
320
+ </Box>
321
+ <Typography variant="h3" sx={{ color: 'var(--theme-success)', mb: 1 }}>
322
+ {formatUptime(diagnostics?.uptime || 0)}
323
+ </Typography>
324
+ <Typography sx={{ color: 'var(--theme-text-secondary)' }}>
325
+ Service has been running without interruption
326
+ </Typography>
327
+ </CardContent>
328
+ </Card>
329
+ </Grid>
330
+
331
+ {/* Health Checks */}
332
+ {health && (
333
+ <Grid size={{ xs: 12 }}>
334
+ <Card sx={{ bgcolor: 'var(--theme-surface)' }}>
335
+ <CardContent>
336
+ <Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 3 }}>
337
+ <FavoriteIcon sx={{ color: getHealthStatusColor(health.status) }} />
338
+ <Typography variant="h6" sx={{ color: 'var(--theme-text-primary)' }}>
339
+ Health Checks
340
+ </Typography>
341
+ <Chip
342
+ label={health.status}
343
+ size="small"
344
+ sx={{
345
+ bgcolor: getHealthStatusColor(health.status) + '20',
346
+ color: getHealthStatusColor(health.status),
347
+ textTransform: 'capitalize',
348
+ ml: 'auto',
349
+ }}
350
+ />
351
+ </Box>
352
+ <TableContainer>
353
+ <Table size="small">
354
+ <TableHead>
355
+ <TableRow>
356
+ <TableCell sx={{ color: 'var(--theme-text-secondary)', borderColor: 'var(--theme-border)' }}>
357
+ Check
358
+ </TableCell>
359
+ <TableCell sx={{ color: 'var(--theme-text-secondary)', borderColor: 'var(--theme-border)' }}>
360
+ Status
361
+ </TableCell>
362
+ <TableCell sx={{ color: 'var(--theme-text-secondary)', borderColor: 'var(--theme-border)' }}>
363
+ Latency
364
+ </TableCell>
365
+ <TableCell sx={{ color: 'var(--theme-text-secondary)', borderColor: 'var(--theme-border)' }}>
366
+ Last Checked
367
+ </TableCell>
368
+ </TableRow>
369
+ </TableHead>
370
+ <TableBody>
371
+ {Object.entries(health.checks).map(([name, check]) => (
372
+ <TableRow key={name}>
373
+ <TableCell sx={{ color: 'var(--theme-text-primary)', borderColor: 'var(--theme-border)' }}>
374
+ <Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
375
+ {getHealthStatusIcon(check.status)}
376
+ <Typography fontWeight={500}>{name}</Typography>
377
+ </Box>
378
+ </TableCell>
379
+ <TableCell sx={{ borderColor: 'var(--theme-border)' }}>
380
+ <Chip
381
+ label={check.status}
382
+ size="small"
383
+ sx={{
384
+ bgcolor: getHealthStatusColor(check.status) + '20',
385
+ color: getHealthStatusColor(check.status),
386
+ textTransform: 'capitalize',
387
+ }}
388
+ />
389
+ </TableCell>
390
+ <TableCell sx={{ color: 'var(--theme-text-primary)', borderColor: 'var(--theme-border)' }}>
391
+ {formatLatency(check.latency)}
392
+ </TableCell>
393
+ <TableCell sx={{ color: 'var(--theme-text-secondary)', borderColor: 'var(--theme-border)' }}>
394
+ {new Date(check.lastChecked).toLocaleTimeString()}
395
+ </TableCell>
396
+ </TableRow>
397
+ ))}
398
+ </TableBody>
399
+ </Table>
400
+ </TableContainer>
401
+ </CardContent>
402
+ </Card>
403
+ </Grid>
404
+ )}
405
+
406
+ {/* Raw JSON */}
407
+ <Grid size={{ xs: 12 }}>
408
+ <Card sx={{ bgcolor: 'var(--theme-surface)' }}>
409
+ <CardContent>
410
+ <Typography variant="h6" sx={{ color: 'var(--theme-text-primary)', mb: 2 }}>
411
+ Raw Diagnostics JSON (for AI agents)
412
+ </Typography>
413
+ <Box
414
+ component="pre"
415
+ sx={{
416
+ bgcolor: 'var(--theme-background)',
417
+ p: 2,
418
+ borderRadius: 1,
419
+ overflow: 'auto',
420
+ maxHeight: 300,
421
+ color: 'var(--theme-text-primary)',
422
+ fontFamily: 'monospace',
423
+ fontSize: '0.75rem',
424
+ }}
425
+ >
426
+ {JSON.stringify(diagnostics, null, 2)}
427
+ </Box>
428
+ </CardContent>
429
+ </Card>
430
+ </Grid>
431
+ </Grid>
432
+
433
+ <Snackbar
434
+ open={snackbar.open}
435
+ autoHideDuration={2000}
436
+ onClose={() => setSnackbar({ ...snackbar, open: false })}
437
+ anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
438
+ >
439
+ <Alert severity="success" variant="filled">
440
+ {snackbar.message}
441
+ </Alert>
442
+ </Snackbar>
443
+ </Box>
444
+ );
445
+ }