@qwickapps/server 1.0.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 (81) hide show
  1. package/LICENSE +45 -0
  2. package/README.md +321 -0
  3. package/dist/core/control-panel.d.ts +21 -0
  4. package/dist/core/control-panel.d.ts.map +1 -0
  5. package/dist/core/control-panel.js +416 -0
  6. package/dist/core/control-panel.js.map +1 -0
  7. package/dist/core/gateway.d.ts +133 -0
  8. package/dist/core/gateway.d.ts.map +1 -0
  9. package/dist/core/gateway.js +270 -0
  10. package/dist/core/gateway.js.map +1 -0
  11. package/dist/core/health-manager.d.ts +52 -0
  12. package/dist/core/health-manager.d.ts.map +1 -0
  13. package/dist/core/health-manager.js +192 -0
  14. package/dist/core/health-manager.js.map +1 -0
  15. package/dist/core/index.d.ts +10 -0
  16. package/dist/core/index.d.ts.map +1 -0
  17. package/dist/core/index.js +8 -0
  18. package/dist/core/index.js.map +1 -0
  19. package/dist/core/logging.d.ts +83 -0
  20. package/dist/core/logging.d.ts.map +1 -0
  21. package/dist/core/logging.js +191 -0
  22. package/dist/core/logging.js.map +1 -0
  23. package/dist/core/types.d.ts +195 -0
  24. package/dist/core/types.d.ts.map +1 -0
  25. package/dist/core/types.js +7 -0
  26. package/dist/core/types.js.map +1 -0
  27. package/dist/index.d.ts +18 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +17 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/plugins/config-plugin.d.ts +15 -0
  32. package/dist/plugins/config-plugin.d.ts.map +1 -0
  33. package/dist/plugins/config-plugin.js +96 -0
  34. package/dist/plugins/config-plugin.js.map +1 -0
  35. package/dist/plugins/diagnostics-plugin.d.ts +29 -0
  36. package/dist/plugins/diagnostics-plugin.d.ts.map +1 -0
  37. package/dist/plugins/diagnostics-plugin.js +142 -0
  38. package/dist/plugins/diagnostics-plugin.js.map +1 -0
  39. package/dist/plugins/health-plugin.d.ts +17 -0
  40. package/dist/plugins/health-plugin.d.ts.map +1 -0
  41. package/dist/plugins/health-plugin.js +25 -0
  42. package/dist/plugins/health-plugin.js.map +1 -0
  43. package/dist/plugins/index.d.ts +14 -0
  44. package/dist/plugins/index.d.ts.map +1 -0
  45. package/dist/plugins/index.js +10 -0
  46. package/dist/plugins/index.js.map +1 -0
  47. package/dist/plugins/logs-plugin.d.ts +22 -0
  48. package/dist/plugins/logs-plugin.d.ts.map +1 -0
  49. package/dist/plugins/logs-plugin.js +242 -0
  50. package/dist/plugins/logs-plugin.js.map +1 -0
  51. package/dist-ui/assets/index-Bk7ypbI4.js +465 -0
  52. package/dist-ui/assets/index-Bk7ypbI4.js.map +1 -0
  53. package/dist-ui/assets/index-CiizQQnb.css +1 -0
  54. package/dist-ui/index.html +13 -0
  55. package/package.json +98 -0
  56. package/src/core/control-panel.ts +493 -0
  57. package/src/core/gateway.ts +421 -0
  58. package/src/core/health-manager.ts +227 -0
  59. package/src/core/index.ts +25 -0
  60. package/src/core/logging.ts +234 -0
  61. package/src/core/types.ts +218 -0
  62. package/src/index.ts +55 -0
  63. package/src/plugins/config-plugin.ts +117 -0
  64. package/src/plugins/diagnostics-plugin.ts +178 -0
  65. package/src/plugins/health-plugin.ts +35 -0
  66. package/src/plugins/index.ts +17 -0
  67. package/src/plugins/logs-plugin.ts +314 -0
  68. package/ui/index.html +12 -0
  69. package/ui/src/App.tsx +65 -0
  70. package/ui/src/api/controlPanelApi.ts +148 -0
  71. package/ui/src/config/AppConfig.ts +18 -0
  72. package/ui/src/index.css +29 -0
  73. package/ui/src/index.tsx +11 -0
  74. package/ui/src/pages/ConfigPage.tsx +199 -0
  75. package/ui/src/pages/DashboardPage.tsx +264 -0
  76. package/ui/src/pages/DiagnosticsPage.tsx +315 -0
  77. package/ui/src/pages/HealthPage.tsx +204 -0
  78. package/ui/src/pages/LogsPage.tsx +267 -0
  79. package/ui/src/pages/NotFoundPage.tsx +41 -0
  80. package/ui/tsconfig.json +19 -0
  81. package/ui/vite.config.ts +21 -0
@@ -0,0 +1,267 @@
1
+ import { useState, useEffect } from 'react';
2
+ import {
3
+ Box,
4
+ Card,
5
+ CardContent,
6
+ Typography,
7
+ Table,
8
+ TableBody,
9
+ TableCell,
10
+ TableContainer,
11
+ TableHead,
12
+ TableRow,
13
+ Chip,
14
+ CircularProgress,
15
+ TextField,
16
+ FormControl,
17
+ InputLabel,
18
+ Select,
19
+ MenuItem,
20
+ IconButton,
21
+ Pagination,
22
+ } from '@mui/material';
23
+ import RefreshIcon from '@mui/icons-material/Refresh';
24
+ import SearchIcon from '@mui/icons-material/Search';
25
+ import { api, LogEntry, LogSource } from '../api/controlPanelApi';
26
+
27
+ function getLevelColor(level: string): string {
28
+ switch (level.toLowerCase()) {
29
+ case 'error':
30
+ return 'var(--theme-error)';
31
+ case 'warn':
32
+ case 'warning':
33
+ return 'var(--theme-warning)';
34
+ case 'info':
35
+ return 'var(--theme-info)';
36
+ case 'debug':
37
+ return 'var(--theme-text-secondary)';
38
+ default:
39
+ return 'var(--theme-text-primary)';
40
+ }
41
+ }
42
+
43
+ export function LogsPage() {
44
+ const [logs, setLogs] = useState<LogEntry[]>([]);
45
+ const [sources, setSources] = useState<LogSource[]>([]);
46
+ const [loading, setLoading] = useState(true);
47
+ const [error, setError] = useState<string | null>(null);
48
+
49
+ // Filters
50
+ const [selectedSource, setSelectedSource] = useState<string>('');
51
+ const [selectedLevel, setSelectedLevel] = useState<string>('');
52
+ const [searchQuery, setSearchQuery] = useState<string>('');
53
+ const [page, setPage] = useState(1);
54
+ const [total, setTotal] = useState(0);
55
+ const limit = 50;
56
+
57
+ const fetchLogs = async () => {
58
+ setLoading(true);
59
+ try {
60
+ const data = await api.getLogs({
61
+ source: selectedSource || undefined,
62
+ level: selectedLevel || undefined,
63
+ search: searchQuery || undefined,
64
+ limit,
65
+ page,
66
+ });
67
+ setLogs(data.logs);
68
+ setTotal(data.total);
69
+ setError(null);
70
+ } catch (err) {
71
+ setError(err instanceof Error ? err.message : 'Failed to fetch logs');
72
+ } finally {
73
+ setLoading(false);
74
+ }
75
+ };
76
+
77
+ const fetchSources = async () => {
78
+ try {
79
+ const data = await api.getLogSources();
80
+ setSources(data);
81
+ } catch {
82
+ // Sources endpoint might not be available
83
+ }
84
+ };
85
+
86
+ useEffect(() => {
87
+ fetchSources();
88
+ }, []);
89
+
90
+ useEffect(() => {
91
+ fetchLogs();
92
+ }, [selectedSource, selectedLevel, page]);
93
+
94
+ const handleSearch = () => {
95
+ setPage(1);
96
+ fetchLogs();
97
+ };
98
+
99
+ const totalPages = Math.ceil(total / limit);
100
+
101
+ return (
102
+ <Box>
103
+ <Typography variant="h4" sx={{ mb: 1, color: 'var(--theme-text-primary)' }}>
104
+ Logs
105
+ </Typography>
106
+ <Typography variant="body2" sx={{ mb: 4, color: 'var(--theme-text-secondary)' }}>
107
+ View and search application logs
108
+ </Typography>
109
+
110
+ {/* Filters */}
111
+ <Card sx={{ mb: 3, bgcolor: 'var(--theme-surface)' }}>
112
+ <CardContent>
113
+ <Box sx={{ display: 'flex', gap: 2, flexWrap: 'wrap', alignItems: 'center' }}>
114
+ {sources.length > 0 && (
115
+ <FormControl size="small" sx={{ minWidth: 150 }}>
116
+ <InputLabel sx={{ color: 'var(--theme-text-secondary)' }}>Source</InputLabel>
117
+ <Select
118
+ value={selectedSource}
119
+ label="Source"
120
+ onChange={(e) => setSelectedSource(e.target.value)}
121
+ sx={{ color: 'var(--theme-text-primary)' }}
122
+ >
123
+ <MenuItem value="">All Sources</MenuItem>
124
+ {sources.map((source) => (
125
+ <MenuItem key={source.name} value={source.name}>
126
+ {source.name}
127
+ </MenuItem>
128
+ ))}
129
+ </Select>
130
+ </FormControl>
131
+ )}
132
+
133
+ <FormControl size="small" sx={{ minWidth: 120 }}>
134
+ <InputLabel sx={{ color: 'var(--theme-text-secondary)' }}>Level</InputLabel>
135
+ <Select
136
+ value={selectedLevel}
137
+ label="Level"
138
+ onChange={(e) => setSelectedLevel(e.target.value)}
139
+ sx={{ color: 'var(--theme-text-primary)' }}
140
+ >
141
+ <MenuItem value="">All Levels</MenuItem>
142
+ <MenuItem value="error">Error</MenuItem>
143
+ <MenuItem value="warn">Warning</MenuItem>
144
+ <MenuItem value="info">Info</MenuItem>
145
+ <MenuItem value="debug">Debug</MenuItem>
146
+ </Select>
147
+ </FormControl>
148
+
149
+ <TextField
150
+ size="small"
151
+ placeholder="Search logs..."
152
+ value={searchQuery}
153
+ onChange={(e) => setSearchQuery(e.target.value)}
154
+ onKeyPress={(e) => e.key === 'Enter' && handleSearch()}
155
+ sx={{
156
+ flex: 1,
157
+ minWidth: 200,
158
+ '& .MuiInputBase-input': { color: 'var(--theme-text-primary)' },
159
+ }}
160
+ InputProps={{
161
+ startAdornment: <SearchIcon sx={{ mr: 1, color: 'var(--theme-text-secondary)' }} />,
162
+ }}
163
+ />
164
+
165
+ <IconButton onClick={fetchLogs} sx={{ color: 'var(--theme-primary)' }}>
166
+ <RefreshIcon />
167
+ </IconButton>
168
+ </Box>
169
+ </CardContent>
170
+ </Card>
171
+
172
+ {/* Error State */}
173
+ {error && (
174
+ <Card sx={{ mb: 3, bgcolor: 'var(--theme-surface)', border: '1px solid var(--theme-error)' }}>
175
+ <CardContent>
176
+ <Typography color="error">{error}</Typography>
177
+ </CardContent>
178
+ </Card>
179
+ )}
180
+
181
+ {/* Logs Table */}
182
+ <Card sx={{ bgcolor: 'var(--theme-surface)' }}>
183
+ {loading ? (
184
+ <Box sx={{ display: 'flex', justifyContent: 'center', p: 4 }}>
185
+ <CircularProgress />
186
+ </Box>
187
+ ) : logs.length === 0 ? (
188
+ <CardContent>
189
+ <Typography sx={{ color: 'var(--theme-text-secondary)', textAlign: 'center' }}>
190
+ No logs found
191
+ </Typography>
192
+ </CardContent>
193
+ ) : (
194
+ <>
195
+ <TableContainer>
196
+ <Table size="small">
197
+ <TableHead>
198
+ <TableRow>
199
+ <TableCell sx={{ color: 'var(--theme-text-secondary)', borderColor: 'var(--theme-border)', width: 180 }}>
200
+ Timestamp
201
+ </TableCell>
202
+ <TableCell sx={{ color: 'var(--theme-text-secondary)', borderColor: 'var(--theme-border)', width: 100 }}>
203
+ Level
204
+ </TableCell>
205
+ {sources.length > 0 && (
206
+ <TableCell sx={{ color: 'var(--theme-text-secondary)', borderColor: 'var(--theme-border)', width: 120 }}>
207
+ Source
208
+ </TableCell>
209
+ )}
210
+ <TableCell sx={{ color: 'var(--theme-text-secondary)', borderColor: 'var(--theme-border)' }}>
211
+ Message
212
+ </TableCell>
213
+ </TableRow>
214
+ </TableHead>
215
+ <TableBody>
216
+ {logs.map((log, index) => (
217
+ <TableRow key={index} hover>
218
+ <TableCell sx={{ color: 'var(--theme-text-secondary)', borderColor: 'var(--theme-border)', fontFamily: 'monospace', fontSize: '0.75rem' }}>
219
+ {new Date(log.timestamp).toLocaleString()}
220
+ </TableCell>
221
+ <TableCell sx={{ borderColor: 'var(--theme-border)' }}>
222
+ <Chip
223
+ label={log.level.toUpperCase()}
224
+ size="small"
225
+ sx={{
226
+ bgcolor: getLevelColor(log.level) + '20',
227
+ color: getLevelColor(log.level),
228
+ fontSize: '0.65rem',
229
+ height: 20,
230
+ }}
231
+ />
232
+ </TableCell>
233
+ {sources.length > 0 && (
234
+ <TableCell sx={{ color: 'var(--theme-text-secondary)', borderColor: 'var(--theme-border)' }}>
235
+ {log.source || '-'}
236
+ </TableCell>
237
+ )}
238
+ <TableCell sx={{ color: 'var(--theme-text-primary)', borderColor: 'var(--theme-border)', fontFamily: 'monospace', fontSize: '0.8rem', whiteSpace: 'pre-wrap', wordBreak: 'break-all' }}>
239
+ {log.message}
240
+ </TableCell>
241
+ </TableRow>
242
+ ))}
243
+ </TableBody>
244
+ </Table>
245
+ </TableContainer>
246
+
247
+ {/* Pagination */}
248
+ {totalPages > 1 && (
249
+ <Box sx={{ display: 'flex', justifyContent: 'center', p: 2 }}>
250
+ <Pagination
251
+ count={totalPages}
252
+ page={page}
253
+ onChange={(_, value) => setPage(value)}
254
+ sx={{
255
+ '& .MuiPaginationItem-root': {
256
+ color: 'var(--theme-text-primary)',
257
+ },
258
+ }}
259
+ />
260
+ </Box>
261
+ )}
262
+ </>
263
+ )}
264
+ </Card>
265
+ </Box>
266
+ );
267
+ }
@@ -0,0 +1,41 @@
1
+ import { Box, Typography, Button } from '@mui/material';
2
+ import { useNavigate } from 'react-router-dom';
3
+ import HomeIcon from '@mui/icons-material/Home';
4
+
5
+ export function NotFoundPage() {
6
+ const navigate = useNavigate();
7
+
8
+ return (
9
+ <Box
10
+ sx={{
11
+ display: 'flex',
12
+ flexDirection: 'column',
13
+ alignItems: 'center',
14
+ justifyContent: 'center',
15
+ minHeight: '50vh',
16
+ textAlign: 'center',
17
+ }}
18
+ >
19
+ <Typography variant="h1" sx={{ color: 'var(--theme-primary)', mb: 2 }}>
20
+ 404
21
+ </Typography>
22
+ <Typography variant="h5" sx={{ color: 'var(--theme-text-primary)', mb: 1 }}>
23
+ Page Not Found
24
+ </Typography>
25
+ <Typography sx={{ color: 'var(--theme-text-secondary)', mb: 4 }}>
26
+ The page you're looking for doesn't exist or has been moved.
27
+ </Typography>
28
+ <Button
29
+ variant="contained"
30
+ startIcon={<HomeIcon />}
31
+ onClick={() => navigate('/')}
32
+ sx={{
33
+ bgcolor: 'var(--theme-primary)',
34
+ '&:hover': { bgcolor: 'var(--theme-primary)' },
35
+ }}
36
+ >
37
+ Back to Dashboard
38
+ </Button>
39
+ </Box>
40
+ );
41
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
5
+ "module": "ESNext",
6
+ "skipLibCheck": true,
7
+ "moduleResolution": "bundler",
8
+ "allowImportingTsExtensions": true,
9
+ "resolveJsonModule": true,
10
+ "isolatedModules": true,
11
+ "noEmit": true,
12
+ "jsx": "react-jsx",
13
+ "strict": true,
14
+ "noUnusedLocals": true,
15
+ "noUnusedParameters": true,
16
+ "noFallthroughCasesInSwitch": true
17
+ },
18
+ "include": ["src"]
19
+ }
@@ -0,0 +1,21 @@
1
+ import { defineConfig } from 'vite';
2
+ import react from '@vitejs/plugin-react';
3
+
4
+ export default defineConfig({
5
+ plugins: [react()],
6
+ root: '.',
7
+ build: {
8
+ outDir: '../dist-ui',
9
+ emptyOutDir: true,
10
+ sourcemap: true,
11
+ },
12
+ server: {
13
+ port: 3102,
14
+ proxy: {
15
+ '/api': {
16
+ target: 'http://localhost:3101',
17
+ changeOrigin: true,
18
+ },
19
+ },
20
+ },
21
+ });