@qwickapps/server 1.1.9 → 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.
- package/README.md +318 -0
- package/dist/core/control-panel.d.ts +7 -2
- package/dist/core/control-panel.d.ts.map +1 -1
- package/dist/core/control-panel.js +99 -60
- package/dist/core/control-panel.js.map +1 -1
- package/dist/core/gateway.d.ts +159 -79
- package/dist/core/gateway.d.ts.map +1 -1
- package/dist/core/gateway.js +683 -315
- package/dist/core/gateway.js.map +1 -1
- package/dist/core/index.d.ts +3 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +2 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/plugin-registry.d.ts +271 -0
- package/dist/core/plugin-registry.d.ts.map +1 -0
- package/dist/core/plugin-registry.js +326 -0
- package/dist/core/plugin-registry.js.map +1 -0
- package/dist/core/types.d.ts +16 -33
- package/dist/core/types.d.ts.map +1 -1
- package/dist/index.d.ts +8 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -7
- package/dist/index.js.map +1 -1
- package/dist/plugins/auth/adapters/auth0-adapter.d.ts +14 -0
- package/dist/plugins/auth/adapters/auth0-adapter.d.ts.map +1 -0
- package/dist/plugins/auth/adapters/auth0-adapter.js +179 -0
- package/dist/plugins/auth/adapters/auth0-adapter.js.map +1 -0
- package/dist/plugins/auth/adapters/basic-adapter.d.ts +13 -0
- package/dist/plugins/auth/adapters/basic-adapter.d.ts.map +1 -0
- package/dist/plugins/auth/adapters/basic-adapter.js +51 -0
- package/dist/plugins/auth/adapters/basic-adapter.js.map +1 -0
- package/dist/plugins/auth/adapters/index.d.ts +9 -0
- package/dist/plugins/auth/adapters/index.d.ts.map +1 -0
- package/dist/plugins/auth/adapters/index.js +9 -0
- package/dist/plugins/auth/adapters/index.js.map +1 -0
- package/dist/plugins/auth/adapters/supabase-adapter.d.ts +13 -0
- package/dist/plugins/auth/adapters/supabase-adapter.d.ts.map +1 -0
- package/dist/plugins/auth/adapters/supabase-adapter.js +109 -0
- package/dist/plugins/auth/adapters/supabase-adapter.js.map +1 -0
- package/dist/plugins/auth/auth-plugin.d.ts +40 -0
- package/dist/plugins/auth/auth-plugin.d.ts.map +1 -0
- package/dist/plugins/auth/auth-plugin.js +255 -0
- package/dist/plugins/auth/auth-plugin.js.map +1 -0
- package/dist/plugins/auth/auth-plugin.test.d.ts +9 -0
- package/dist/plugins/auth/auth-plugin.test.d.ts.map +1 -0
- package/dist/plugins/auth/auth-plugin.test.js +147 -0
- package/dist/plugins/auth/auth-plugin.test.js.map +1 -0
- package/dist/plugins/auth/index.d.ts +12 -0
- package/dist/plugins/auth/index.d.ts.map +1 -0
- package/dist/plugins/auth/index.js +13 -0
- package/dist/plugins/auth/index.js.map +1 -0
- package/dist/plugins/auth/types.d.ts +148 -0
- package/dist/plugins/auth/types.d.ts.map +1 -0
- package/dist/plugins/auth/types.js +14 -0
- package/dist/plugins/auth/types.js.map +1 -0
- package/dist/plugins/bans/bans-plugin.d.ts +59 -0
- package/dist/plugins/bans/bans-plugin.d.ts.map +1 -0
- package/dist/plugins/bans/bans-plugin.js +428 -0
- package/dist/plugins/bans/bans-plugin.js.map +1 -0
- package/dist/plugins/bans/index.d.ts +9 -0
- package/dist/plugins/bans/index.d.ts.map +1 -0
- package/dist/plugins/bans/index.js +10 -0
- package/dist/plugins/bans/index.js.map +1 -0
- package/dist/plugins/bans/stores/index.d.ts +7 -0
- package/dist/plugins/bans/stores/index.d.ts.map +1 -0
- package/dist/plugins/bans/stores/index.js +7 -0
- package/dist/plugins/bans/stores/index.js.map +1 -0
- package/dist/plugins/bans/stores/postgres-store.d.ts +29 -0
- package/dist/plugins/bans/stores/postgres-store.d.ts.map +1 -0
- package/dist/plugins/bans/stores/postgres-store.js +132 -0
- package/dist/plugins/bans/stores/postgres-store.js.map +1 -0
- package/dist/plugins/bans/types.d.ts +128 -0
- package/dist/plugins/bans/types.d.ts.map +1 -0
- package/dist/plugins/bans/types.js +11 -0
- package/dist/plugins/bans/types.js.map +1 -0
- package/dist/plugins/cache-plugin.d.ts +14 -3
- package/dist/plugins/cache-plugin.d.ts.map +1 -1
- package/dist/plugins/cache-plugin.js +27 -7
- package/dist/plugins/cache-plugin.js.map +1 -1
- package/dist/plugins/cache-plugin.test.js +96 -32
- package/dist/plugins/cache-plugin.test.js.map +1 -1
- package/dist/plugins/config-plugin.d.ts +3 -2
- package/dist/plugins/config-plugin.d.ts.map +1 -1
- package/dist/plugins/config-plugin.js +17 -10
- package/dist/plugins/config-plugin.js.map +1 -1
- package/dist/plugins/diagnostics-plugin.d.ts +2 -2
- package/dist/plugins/diagnostics-plugin.d.ts.map +1 -1
- package/dist/plugins/diagnostics-plugin.js +17 -10
- package/dist/plugins/diagnostics-plugin.js.map +1 -1
- package/dist/plugins/entitlements/entitlements-plugin.d.ts +95 -0
- package/dist/plugins/entitlements/entitlements-plugin.d.ts.map +1 -0
- package/dist/plugins/entitlements/entitlements-plugin.js +707 -0
- package/dist/plugins/entitlements/entitlements-plugin.js.map +1 -0
- package/dist/plugins/entitlements/index.d.ts +12 -0
- package/dist/plugins/entitlements/index.d.ts.map +1 -0
- package/dist/plugins/entitlements/index.js +16 -0
- package/dist/plugins/entitlements/index.js.map +1 -0
- package/dist/plugins/entitlements/sources/index.d.ts +9 -0
- package/dist/plugins/entitlements/sources/index.d.ts.map +1 -0
- package/dist/plugins/entitlements/sources/index.js +9 -0
- package/dist/plugins/entitlements/sources/index.js.map +1 -0
- package/dist/plugins/entitlements/sources/postgres-source.d.ts +29 -0
- package/dist/plugins/entitlements/sources/postgres-source.d.ts.map +1 -0
- package/dist/plugins/entitlements/sources/postgres-source.js +169 -0
- package/dist/plugins/entitlements/sources/postgres-source.js.map +1 -0
- package/dist/plugins/entitlements/types.d.ts +232 -0
- package/dist/plugins/entitlements/types.d.ts.map +1 -0
- package/dist/plugins/entitlements/types.js +11 -0
- package/dist/plugins/entitlements/types.js.map +1 -0
- package/dist/plugins/frontend-app-plugin.d.ts +9 -3
- package/dist/plugins/frontend-app-plugin.d.ts.map +1 -1
- package/dist/plugins/frontend-app-plugin.js +14 -9
- package/dist/plugins/frontend-app-plugin.js.map +1 -1
- package/dist/plugins/health-plugin.d.ts +5 -2
- package/dist/plugins/health-plugin.d.ts.map +1 -1
- package/dist/plugins/health-plugin.js +20 -5
- package/dist/plugins/health-plugin.js.map +1 -1
- package/dist/plugins/index.d.ts +8 -2
- package/dist/plugins/index.d.ts.map +1 -1
- package/dist/plugins/index.js +8 -2
- package/dist/plugins/index.js.map +1 -1
- package/dist/plugins/logs-plugin.d.ts +3 -2
- package/dist/plugins/logs-plugin.d.ts.map +1 -1
- package/dist/plugins/logs-plugin.js +21 -12
- package/dist/plugins/logs-plugin.js.map +1 -1
- package/dist/plugins/postgres-plugin.d.ts +3 -3
- package/dist/plugins/postgres-plugin.d.ts.map +1 -1
- package/dist/plugins/postgres-plugin.js +9 -7
- package/dist/plugins/postgres-plugin.js.map +1 -1
- package/dist/plugins/postgres-plugin.test.js +47 -29
- package/dist/plugins/postgres-plugin.test.js.map +1 -1
- package/dist/plugins/users/index.d.ts +12 -0
- package/dist/plugins/users/index.d.ts.map +1 -0
- package/dist/plugins/users/index.js +13 -0
- package/dist/plugins/users/index.js.map +1 -0
- package/dist/plugins/users/stores/index.d.ts +7 -0
- package/dist/plugins/users/stores/index.d.ts.map +1 -0
- package/dist/plugins/users/stores/index.js +7 -0
- package/dist/plugins/users/stores/index.js.map +1 -0
- package/dist/plugins/users/stores/postgres-store.d.ts +28 -0
- package/dist/plugins/users/stores/postgres-store.d.ts.map +1 -0
- package/dist/plugins/users/stores/postgres-store.js +157 -0
- package/dist/plugins/users/stores/postgres-store.js.map +1 -0
- package/dist/plugins/users/types.d.ts +189 -0
- package/dist/plugins/users/types.d.ts.map +1 -0
- package/dist/plugins/users/types.js +12 -0
- package/dist/plugins/users/types.js.map +1 -0
- package/dist/plugins/users/users-plugin.d.ts +39 -0
- package/dist/plugins/users/users-plugin.d.ts.map +1 -0
- package/dist/plugins/users/users-plugin.js +242 -0
- package/dist/plugins/users/users-plugin.js.map +1 -0
- package/dist-ui/assets/index-Bsp2ntcw.js +465 -0
- package/dist-ui/assets/index-Bsp2ntcw.js.map +1 -0
- package/dist-ui/index.html +1 -1
- package/dist-ui-lib/api/controlPanelApi.d.ts +232 -0
- package/dist-ui-lib/components/ControlPanelApp.d.ts +61 -0
- package/dist-ui-lib/components/index.d.ts +18 -0
- package/dist-ui-lib/config/AppConfig.d.ts +7 -0
- package/dist-ui-lib/dashboard/DashboardWidgetRegistry.d.ts +62 -0
- package/dist-ui-lib/dashboard/DashboardWidgetRenderer.d.ts +8 -0
- package/dist-ui-lib/dashboard/PluginWidgetRenderer.d.ts +19 -0
- package/dist-ui-lib/dashboard/WidgetComponentRegistry.d.ts +44 -0
- package/dist-ui-lib/dashboard/builtInWidgets.d.ts +19 -0
- package/dist-ui-lib/dashboard/index.d.ts +13 -0
- package/dist-ui-lib/dashboard/widgets/ServiceHealthWidget.d.ts +12 -0
- package/dist-ui-lib/dashboard/widgets/index.d.ts +6 -0
- package/dist-ui-lib/index.js +6441 -0
- package/dist-ui-lib/index.js.map +1 -0
- package/dist-ui-lib/pages/ConfigPage.d.ts +1 -0
- package/dist-ui-lib/pages/DashboardPage.d.ts +1 -0
- package/dist-ui-lib/pages/DiagnosticsPage.d.ts +1 -0
- package/dist-ui-lib/pages/EntitlementsPage.d.ts +17 -0
- package/dist-ui-lib/pages/LogsPage.d.ts +1 -0
- package/dist-ui-lib/pages/NotFoundPage.d.ts +1 -0
- package/dist-ui-lib/pages/PluginPage.d.ts +15 -0
- package/dist-ui-lib/pages/SystemPage.d.ts +1 -0
- package/dist-ui-lib/pages/UsersPage.d.ts +22 -0
- package/package.json +18 -6
- package/src/core/control-panel.ts +122 -68
- package/src/core/gateway.ts +870 -399
- package/src/core/index.ts +21 -2
- package/src/core/plugin-registry.ts +653 -0
- package/src/core/types.ts +31 -37
- package/src/index.ts +118 -19
- package/src/plugins/auth/adapters/auth0-adapter.ts +214 -0
- package/src/plugins/auth/adapters/basic-adapter.ts +61 -0
- package/src/plugins/auth/adapters/index.ts +9 -0
- package/src/plugins/auth/adapters/supabase-adapter.ts +141 -0
- package/src/plugins/auth/auth-plugin.test.ts +176 -0
- package/src/plugins/auth/auth-plugin.ts +303 -0
- package/src/plugins/auth/index.ts +33 -0
- package/src/plugins/auth/types.ts +165 -0
- package/src/plugins/bans/bans-plugin.ts +485 -0
- package/src/plugins/bans/index.ts +31 -0
- package/src/plugins/bans/stores/index.ts +7 -0
- package/src/plugins/bans/stores/postgres-store.ts +195 -0
- package/src/plugins/bans/types.ts +141 -0
- package/src/plugins/cache-plugin.test.ts +105 -32
- package/src/plugins/cache-plugin.ts +40 -9
- package/src/plugins/config-plugin.ts +23 -12
- package/src/plugins/diagnostics-plugin.ts +22 -12
- package/src/plugins/entitlements/entitlements-plugin.ts +820 -0
- package/src/plugins/entitlements/index.ts +51 -0
- package/src/plugins/entitlements/sources/index.ts +9 -0
- package/src/plugins/entitlements/sources/postgres-source.ts +253 -0
- package/src/plugins/entitlements/types.ts +256 -0
- package/src/plugins/frontend-app-plugin.ts +24 -12
- package/src/plugins/health-plugin.ts +27 -7
- package/src/plugins/index.ts +106 -4
- package/src/plugins/logs-plugin.ts +28 -14
- package/src/plugins/postgres-plugin.test.ts +49 -29
- package/src/plugins/postgres-plugin.ts +11 -9
- package/src/plugins/users/index.ts +35 -0
- package/src/plugins/users/stores/index.ts +7 -0
- package/src/plugins/users/stores/postgres-store.ts +225 -0
- package/src/plugins/users/types.ts +209 -0
- package/src/plugins/users/users-plugin.ts +281 -0
- package/ui/src/App.tsx +185 -31
- package/ui/src/api/controlPanelApi.ts +354 -1
- package/ui/src/components/ControlPanelApp.tsx +209 -0
- package/ui/src/components/index.ts +62 -0
- package/ui/src/dashboard/DashboardWidgetRegistry.tsx +129 -0
- package/ui/src/dashboard/DashboardWidgetRenderer.tsx +34 -0
- package/ui/src/dashboard/PluginWidgetRenderer.tsx +115 -0
- package/ui/src/dashboard/WidgetComponentRegistry.tsx +116 -0
- package/ui/src/dashboard/builtInWidgets.tsx +29 -0
- package/ui/src/dashboard/index.ts +35 -0
- package/ui/src/dashboard/widgets/ServiceHealthWidget.tsx +140 -0
- package/ui/src/dashboard/widgets/index.ts +7 -0
- package/ui/src/pages/DashboardPage.tsx +28 -149
- package/ui/src/pages/EntitlementsPage.tsx +557 -0
- package/ui/src/pages/LogsPage.tsx +174 -8
- package/ui/src/pages/PluginPage.tsx +148 -0
- package/ui/src/pages/SystemPage.tsx +445 -0
- package/ui/src/pages/UsersPage.tsx +837 -0
- package/ui/tsconfig.lib.json +11 -0
- package/ui/vite.lib.config.ts +51 -0
- package/dist-ui/assets/index-CW1BviRn.js +0 -465
- package/dist-ui/assets/index-CW1BviRn.js.map +0 -1
- package/ui/src/pages/HealthPage.tsx +0 -204
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard Module
|
|
3
|
+
*
|
|
4
|
+
* Exports the dashboard widget system for dynamic dashboard customization.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// Legacy context-based widget system (for backwards compatibility)
|
|
10
|
+
export {
|
|
11
|
+
DashboardWidgetProvider,
|
|
12
|
+
useDashboardWidgets,
|
|
13
|
+
useRegisterWidget,
|
|
14
|
+
type DashboardWidget,
|
|
15
|
+
type DashboardWidgetProviderProps,
|
|
16
|
+
} from './DashboardWidgetRegistry';
|
|
17
|
+
|
|
18
|
+
export { DashboardWidgetRenderer } from './DashboardWidgetRenderer';
|
|
19
|
+
|
|
20
|
+
// New plugin-based widget system
|
|
21
|
+
export {
|
|
22
|
+
WidgetComponentRegistryProvider,
|
|
23
|
+
useWidgetComponentRegistry,
|
|
24
|
+
type WidgetComponent,
|
|
25
|
+
type WidgetComponentRegistryProviderProps,
|
|
26
|
+
} from './WidgetComponentRegistry';
|
|
27
|
+
|
|
28
|
+
export { PluginWidgetRenderer } from './PluginWidgetRenderer';
|
|
29
|
+
|
|
30
|
+
// Built-in widgets
|
|
31
|
+
export { ServiceHealthWidget } from './widgets';
|
|
32
|
+
|
|
33
|
+
// Built-in widget component map (component name -> React component function)
|
|
34
|
+
// Product code should use getBuiltInWidgetComponents() to get the full list with JSX
|
|
35
|
+
export { builtInWidgetComponents, getBuiltInWidgetComponents } from './builtInWidgets';
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Service Health Widget
|
|
3
|
+
*
|
|
4
|
+
* Displays health check status with latency for all registered health checks.
|
|
5
|
+
* This is a built-in widget provided by qwickapps-server.
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { useState, useEffect } from 'react';
|
|
11
|
+
import { Box, Card, CardContent, Chip } from '@mui/material';
|
|
12
|
+
import { GridLayout, Text } from '@qwickapps/react-framework';
|
|
13
|
+
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
|
|
14
|
+
import ErrorIcon from '@mui/icons-material/Error';
|
|
15
|
+
import WarningIcon from '@mui/icons-material/Warning';
|
|
16
|
+
import { api, HealthResponse } from '../../api/controlPanelApi';
|
|
17
|
+
|
|
18
|
+
function getStatusIcon(status: string) {
|
|
19
|
+
switch (status) {
|
|
20
|
+
case 'healthy':
|
|
21
|
+
return <CheckCircleIcon sx={{ fontSize: 24, color: 'var(--theme-success)' }} />;
|
|
22
|
+
case 'degraded':
|
|
23
|
+
return <WarningIcon sx={{ fontSize: 24, color: 'var(--theme-warning)' }} />;
|
|
24
|
+
case 'unhealthy':
|
|
25
|
+
return <ErrorIcon sx={{ fontSize: 24, color: 'var(--theme-error)' }} />;
|
|
26
|
+
default:
|
|
27
|
+
return <WarningIcon sx={{ fontSize: 24, color: 'var(--theme-text-secondary)' }} />;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function getStatusColor(status: string): string {
|
|
32
|
+
switch (status) {
|
|
33
|
+
case 'healthy':
|
|
34
|
+
return 'var(--theme-success)';
|
|
35
|
+
case 'degraded':
|
|
36
|
+
return 'var(--theme-warning)';
|
|
37
|
+
case 'unhealthy':
|
|
38
|
+
return 'var(--theme-error)';
|
|
39
|
+
default:
|
|
40
|
+
return 'var(--theme-text-secondary)';
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Get grid columns count (1-4) based on item count */
|
|
45
|
+
function getGridColumns(count: number): 1 | 2 | 3 | 4 {
|
|
46
|
+
if (count <= 1) return 1;
|
|
47
|
+
if (count === 2) return 2;
|
|
48
|
+
if (count === 3) return 3;
|
|
49
|
+
return 4;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Service Health Widget Component
|
|
54
|
+
*/
|
|
55
|
+
export function ServiceHealthWidget() {
|
|
56
|
+
const [health, setHealth] = useState<HealthResponse | null>(null);
|
|
57
|
+
const [error, setError] = useState<string | null>(null);
|
|
58
|
+
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
const fetchHealth = async () => {
|
|
61
|
+
try {
|
|
62
|
+
const data = await api.getHealth();
|
|
63
|
+
setHealth(data);
|
|
64
|
+
setError(null);
|
|
65
|
+
} catch (err) {
|
|
66
|
+
setError(err instanceof Error ? err.message : 'Failed to fetch health');
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
fetchHealth();
|
|
71
|
+
const interval = setInterval(fetchHealth, 10000);
|
|
72
|
+
return () => clearInterval(interval);
|
|
73
|
+
}, []);
|
|
74
|
+
|
|
75
|
+
if (error) {
|
|
76
|
+
return (
|
|
77
|
+
<Card sx={{ bgcolor: 'var(--theme-surface)', border: '1px solid var(--theme-error)' }}>
|
|
78
|
+
<CardContent>
|
|
79
|
+
<Text variant="body2" customColor="var(--theme-error)" content={error} />
|
|
80
|
+
</CardContent>
|
|
81
|
+
</Card>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const healthChecks = health ? Object.entries(health.checks) : [];
|
|
86
|
+
|
|
87
|
+
if (healthChecks.length === 0) {
|
|
88
|
+
return (
|
|
89
|
+
<Card sx={{ bgcolor: 'var(--theme-surface)' }}>
|
|
90
|
+
<CardContent>
|
|
91
|
+
<Text variant="body2" customColor="var(--theme-text-secondary)" content="No health checks configured" />
|
|
92
|
+
</CardContent>
|
|
93
|
+
</Card>
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Determine grid columns based on number of health checks (max 4)
|
|
98
|
+
const columns = getGridColumns(healthChecks.length);
|
|
99
|
+
|
|
100
|
+
return (
|
|
101
|
+
<GridLayout columns={columns} spacing="medium" equalHeight>
|
|
102
|
+
{healthChecks.map(([name, check]) => (
|
|
103
|
+
<Card key={name} sx={{ bgcolor: 'var(--theme-surface)' }}>
|
|
104
|
+
<CardContent>
|
|
105
|
+
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
|
|
106
|
+
{getStatusIcon(check.status)}
|
|
107
|
+
<Box sx={{ flex: 1, minWidth: 0 }}>
|
|
108
|
+
<Text
|
|
109
|
+
variant="body1"
|
|
110
|
+
fontWeight="500"
|
|
111
|
+
content={name.charAt(0).toUpperCase() + name.slice(1)}
|
|
112
|
+
customColor="var(--theme-text-primary)"
|
|
113
|
+
/>
|
|
114
|
+
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mt: 0.5 }}>
|
|
115
|
+
<Chip
|
|
116
|
+
label={check.status}
|
|
117
|
+
size="small"
|
|
118
|
+
sx={{
|
|
119
|
+
bgcolor: getStatusColor(check.status) + '20',
|
|
120
|
+
color: getStatusColor(check.status),
|
|
121
|
+
fontSize: '0.75rem',
|
|
122
|
+
height: 20,
|
|
123
|
+
}}
|
|
124
|
+
/>
|
|
125
|
+
{check.latency !== undefined && (
|
|
126
|
+
<Text
|
|
127
|
+
variant="caption"
|
|
128
|
+
content={`${check.latency}ms`}
|
|
129
|
+
customColor="var(--theme-text-secondary)"
|
|
130
|
+
/>
|
|
131
|
+
)}
|
|
132
|
+
</Box>
|
|
133
|
+
</Box>
|
|
134
|
+
</Box>
|
|
135
|
+
</CardContent>
|
|
136
|
+
</Card>
|
|
137
|
+
))}
|
|
138
|
+
</GridLayout>
|
|
139
|
+
);
|
|
140
|
+
}
|
|
@@ -1,38 +1,19 @@
|
|
|
1
1
|
import { useState, useEffect } from 'react';
|
|
2
|
+
import { useNavigate } from 'react-router-dom';
|
|
2
3
|
import {
|
|
3
4
|
Box,
|
|
4
5
|
Card,
|
|
5
6
|
CardContent,
|
|
7
|
+
CardActionArea,
|
|
6
8
|
Typography,
|
|
7
|
-
Grid,
|
|
8
9
|
CircularProgress,
|
|
9
10
|
Chip,
|
|
10
11
|
} from '@mui/material';
|
|
11
12
|
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
|
|
12
13
|
import ErrorIcon from '@mui/icons-material/Error';
|
|
13
14
|
import WarningIcon from '@mui/icons-material/Warning';
|
|
14
|
-
import AccessTimeIcon from '@mui/icons-material/AccessTime';
|
|
15
|
-
import MemoryIcon from '@mui/icons-material/Memory';
|
|
16
|
-
import StorageIcon from '@mui/icons-material/Storage';
|
|
17
15
|
import { api, HealthResponse, InfoResponse } from '../api/controlPanelApi';
|
|
18
|
-
|
|
19
|
-
function formatUptime(ms: number): string {
|
|
20
|
-
const seconds = Math.floor(ms / 1000);
|
|
21
|
-
const minutes = Math.floor(seconds / 60);
|
|
22
|
-
const hours = Math.floor(minutes / 60);
|
|
23
|
-
const days = Math.floor(hours / 24);
|
|
24
|
-
|
|
25
|
-
if (days > 0) {
|
|
26
|
-
return `${days}d ${hours % 24}h ${minutes % 60}m`;
|
|
27
|
-
}
|
|
28
|
-
if (hours > 0) {
|
|
29
|
-
return `${hours}h ${minutes % 60}m`;
|
|
30
|
-
}
|
|
31
|
-
if (minutes > 0) {
|
|
32
|
-
return `${minutes}m ${seconds % 60}s`;
|
|
33
|
-
}
|
|
34
|
-
return `${seconds}s`;
|
|
35
|
-
}
|
|
16
|
+
import { DashboardWidgetRenderer, PluginWidgetRenderer } from '../dashboard';
|
|
36
17
|
|
|
37
18
|
function getStatusIcon(status: string) {
|
|
38
19
|
switch (status) {
|
|
@@ -61,6 +42,7 @@ function getStatusColor(status: string): string {
|
|
|
61
42
|
}
|
|
62
43
|
|
|
63
44
|
export function DashboardPage() {
|
|
45
|
+
const navigate = useNavigate();
|
|
64
46
|
const [health, setHealth] = useState<HealthResponse | null>(null);
|
|
65
47
|
const [info, setInfo] = useState<InfoResponse | null>(null);
|
|
66
48
|
const [loading, setLoading] = useState(true);
|
|
@@ -119,7 +101,7 @@ export function DashboardPage() {
|
|
|
119
101
|
Real-time overview of {info?.product || 'your service'}
|
|
120
102
|
</Typography>
|
|
121
103
|
|
|
122
|
-
{/* Status Banner */}
|
|
104
|
+
{/* Service Status Banner - clickable to navigate to Health page */}
|
|
123
105
|
<Card
|
|
124
106
|
sx={{
|
|
125
107
|
mb: 4,
|
|
@@ -127,138 +109,35 @@ export function DashboardPage() {
|
|
|
127
109
|
border: `2px solid ${getStatusColor(health?.status || 'unknown')}`,
|
|
128
110
|
}}
|
|
129
111
|
>
|
|
130
|
-
<
|
|
131
|
-
<
|
|
132
|
-
{
|
|
133
|
-
|
|
134
|
-
<
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
<Typography variant="body2" sx={{ color: 'var(--theme-text-secondary)' }}>
|
|
138
|
-
Last updated: {health?.timestamp ? new Date(health.timestamp).toLocaleString() : 'N/A'}
|
|
139
|
-
</Typography>
|
|
140
|
-
</Box>
|
|
141
|
-
</Box>
|
|
142
|
-
<Chip
|
|
143
|
-
label={`${healthyCount}/${totalCount} checks passing`}
|
|
144
|
-
sx={{
|
|
145
|
-
bgcolor: getStatusColor(health?.status || 'unknown') + '20',
|
|
146
|
-
color: getStatusColor(health?.status || 'unknown'),
|
|
147
|
-
}}
|
|
148
|
-
/>
|
|
149
|
-
</CardContent>
|
|
150
|
-
</Card>
|
|
151
|
-
|
|
152
|
-
{/* Stats Grid */}
|
|
153
|
-
<Grid container spacing={3} sx={{ mb: 4 }}>
|
|
154
|
-
<Grid size={{ xs: 12, sm: 6, md: 3 }}>
|
|
155
|
-
<Card sx={{ bgcolor: 'var(--theme-surface)', height: '100%' }}>
|
|
156
|
-
<CardContent>
|
|
157
|
-
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 2 }}>
|
|
158
|
-
<AccessTimeIcon sx={{ color: 'var(--theme-primary)' }} />
|
|
159
|
-
<Typography variant="body2" sx={{ color: 'var(--theme-text-secondary)' }}>
|
|
160
|
-
Uptime
|
|
112
|
+
<CardActionArea onClick={() => navigate('/health')}>
|
|
113
|
+
<CardContent sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
|
|
114
|
+
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
|
|
115
|
+
{getStatusIcon(health?.status || 'unknown')}
|
|
116
|
+
<Box>
|
|
117
|
+
<Typography variant="h6" sx={{ color: 'var(--theme-text-primary)' }}>
|
|
118
|
+
Service Status: {health?.status?.charAt(0).toUpperCase()}{health?.status?.slice(1)}
|
|
161
119
|
</Typography>
|
|
162
|
-
</Box>
|
|
163
|
-
<Typography variant="h4" sx={{ color: 'var(--theme-primary)' }}>
|
|
164
|
-
{health ? formatUptime(health.uptime) : 'N/A'}
|
|
165
|
-
</Typography>
|
|
166
|
-
</CardContent>
|
|
167
|
-
</Card>
|
|
168
|
-
</Grid>
|
|
169
|
-
|
|
170
|
-
<Grid size={{ xs: 12, sm: 6, md: 3 }}>
|
|
171
|
-
<Card sx={{ bgcolor: 'var(--theme-surface)', height: '100%' }}>
|
|
172
|
-
<CardContent>
|
|
173
|
-
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 2 }}>
|
|
174
|
-
<CheckCircleIcon sx={{ color: 'var(--theme-success)' }} />
|
|
175
120
|
<Typography variant="body2" sx={{ color: 'var(--theme-text-secondary)' }}>
|
|
176
|
-
|
|
121
|
+
Click to view detailed health information
|
|
177
122
|
</Typography>
|
|
178
123
|
</Box>
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
<MemoryIcon sx={{ color: 'var(--theme-warning)' }} />
|
|
191
|
-
<Typography variant="body2" sx={{ color: 'var(--theme-text-secondary)' }}>
|
|
192
|
-
Version
|
|
193
|
-
</Typography>
|
|
194
|
-
</Box>
|
|
195
|
-
<Typography variant="h4" sx={{ color: 'var(--theme-text-primary)' }}>
|
|
196
|
-
{info?.version || 'N/A'}
|
|
197
|
-
</Typography>
|
|
198
|
-
</CardContent>
|
|
199
|
-
</Card>
|
|
200
|
-
</Grid>
|
|
124
|
+
</Box>
|
|
125
|
+
<Chip
|
|
126
|
+
label={`${healthyCount}/${totalCount} checks passing`}
|
|
127
|
+
sx={{
|
|
128
|
+
bgcolor: getStatusColor(health?.status || 'unknown') + '20',
|
|
129
|
+
color: getStatusColor(health?.status || 'unknown'),
|
|
130
|
+
}}
|
|
131
|
+
/>
|
|
132
|
+
</CardContent>
|
|
133
|
+
</CardActionArea>
|
|
134
|
+
</Card>
|
|
201
135
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
<CardContent>
|
|
205
|
-
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 2 }}>
|
|
206
|
-
<StorageIcon sx={{ color: 'var(--theme-info)' }} />
|
|
207
|
-
<Typography variant="body2" sx={{ color: 'var(--theme-text-secondary)' }}>
|
|
208
|
-
Product
|
|
209
|
-
</Typography>
|
|
210
|
-
</Box>
|
|
211
|
-
<Typography variant="h5" sx={{ color: 'var(--theme-text-primary)' }}>
|
|
212
|
-
{info?.product || 'N/A'}
|
|
213
|
-
</Typography>
|
|
214
|
-
</CardContent>
|
|
215
|
-
</Card>
|
|
216
|
-
</Grid>
|
|
217
|
-
</Grid>
|
|
136
|
+
{/* Plugin widgets (from server-side widget contributions) */}
|
|
137
|
+
<PluginWidgetRenderer />
|
|
218
138
|
|
|
219
|
-
{/*
|
|
220
|
-
<
|
|
221
|
-
<CardContent>
|
|
222
|
-
<Typography variant="h6" sx={{ mb: 3, color: 'var(--theme-text-primary)' }}>
|
|
223
|
-
Health Checks
|
|
224
|
-
</Typography>
|
|
225
|
-
<Grid container spacing={2}>
|
|
226
|
-
{healthChecks.map(([name, check]) => (
|
|
227
|
-
<Grid size={{ xs: 12, sm: 6, md: 4 }} key={name}>
|
|
228
|
-
<Box
|
|
229
|
-
sx={{
|
|
230
|
-
p: 2,
|
|
231
|
-
borderRadius: 1,
|
|
232
|
-
bgcolor: 'var(--theme-background)',
|
|
233
|
-
border: `1px solid ${getStatusColor(check.status)}40`,
|
|
234
|
-
}}
|
|
235
|
-
>
|
|
236
|
-
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', mb: 1 }}>
|
|
237
|
-
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
|
238
|
-
{getStatusIcon(check.status)}
|
|
239
|
-
<Typography sx={{ color: 'var(--theme-text-primary)', fontWeight: 500 }}>
|
|
240
|
-
{name}
|
|
241
|
-
</Typography>
|
|
242
|
-
</Box>
|
|
243
|
-
{check.latency !== undefined && (
|
|
244
|
-
<Chip
|
|
245
|
-
label={`${check.latency}ms`}
|
|
246
|
-
size="small"
|
|
247
|
-
sx={{ bgcolor: 'var(--theme-surface)', color: 'var(--theme-text-secondary)' }}
|
|
248
|
-
/>
|
|
249
|
-
)}
|
|
250
|
-
</Box>
|
|
251
|
-
{check.error && (
|
|
252
|
-
<Typography variant="caption" sx={{ color: 'var(--theme-error)' }}>
|
|
253
|
-
{check.error}
|
|
254
|
-
</Typography>
|
|
255
|
-
)}
|
|
256
|
-
</Box>
|
|
257
|
-
</Grid>
|
|
258
|
-
))}
|
|
259
|
-
</Grid>
|
|
260
|
-
</CardContent>
|
|
261
|
-
</Card>
|
|
139
|
+
{/* Legacy widgets from context (for backwards compatibility) */}
|
|
140
|
+
<DashboardWidgetRenderer />
|
|
262
141
|
</Box>
|
|
263
142
|
);
|
|
264
143
|
}
|