@qwickapps/server 1.7.0 → 1.7.1
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/CHANGELOG.md +53 -0
- package/README.md +13 -116
- package/dist/src/core/control-panel.d.ts.map +1 -1
- package/dist/src/core/control-panel.js +6 -4
- package/dist/src/core/control-panel.js.map +1 -1
- package/dist/src/core/gateway.d.ts.map +1 -1
- package/dist/src/core/gateway.js +24 -2
- package/dist/src/core/gateway.js.map +1 -1
- package/dist/src/core/plugin-registry.d.ts +15 -2
- package/dist/src/core/plugin-registry.d.ts.map +1 -1
- package/dist/src/core/plugin-registry.js.map +1 -1
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +9 -3
- package/dist/src/index.js.map +1 -1
- package/dist/src/plugins/api-keys/stores/postgres-store.d.ts.map +1 -1
- package/dist/src/plugins/api-keys/stores/postgres-store.js +29 -0
- package/dist/src/plugins/api-keys/stores/postgres-store.js.map +1 -1
- package/dist/src/plugins/auth/auth-plugin.d.ts.map +1 -1
- package/dist/src/plugins/auth/auth-plugin.js +4 -2
- package/dist/src/plugins/auth/auth-plugin.js.map +1 -1
- package/dist/src/plugins/auth/env-config.d.ts.map +1 -1
- package/dist/src/plugins/auth/env-config.js +1 -0
- package/dist/src/plugins/auth/env-config.js.map +1 -1
- package/dist/src/plugins/bans/index.d.ts +1 -1
- package/dist/src/plugins/bans/index.d.ts.map +1 -1
- package/dist/src/plugins/bans/index.js +1 -1
- package/dist/src/plugins/bans/index.js.map +1 -1
- package/dist/src/plugins/bans/stores/in-memory-store.d.ts +34 -0
- package/dist/src/plugins/bans/stores/in-memory-store.d.ts.map +1 -0
- package/dist/src/plugins/bans/stores/in-memory-store.js +97 -0
- package/dist/src/plugins/bans/stores/in-memory-store.js.map +1 -0
- package/dist/src/plugins/bans/stores/index.d.ts +1 -0
- package/dist/src/plugins/bans/stores/index.d.ts.map +1 -1
- package/dist/src/plugins/bans/stores/index.js +1 -0
- package/dist/src/plugins/bans/stores/index.js.map +1 -1
- package/dist/src/plugins/cache-plugin.d.ts +35 -16
- package/dist/src/plugins/cache-plugin.d.ts.map +1 -1
- package/dist/src/plugins/cache-plugin.js +299 -20
- package/dist/src/plugins/cache-plugin.js.map +1 -1
- package/dist/src/plugins/cms/cms-plugin.d.ts.map +1 -1
- package/dist/src/plugins/cms/cms-plugin.js +3 -1
- package/dist/src/plugins/cms/cms-plugin.js.map +1 -1
- package/dist/src/plugins/entitlements/index.d.ts +1 -1
- package/dist/src/plugins/entitlements/index.d.ts.map +1 -1
- package/dist/src/plugins/entitlements/index.js +1 -1
- package/dist/src/plugins/entitlements/index.js.map +1 -1
- package/dist/src/plugins/entitlements/sources/in-memory-source.d.ts +9 -0
- package/dist/src/plugins/entitlements/sources/in-memory-source.d.ts.map +1 -0
- package/dist/src/plugins/entitlements/sources/in-memory-source.js +65 -0
- package/dist/src/plugins/entitlements/sources/in-memory-source.js.map +1 -0
- package/dist/src/plugins/entitlements/sources/index.d.ts +1 -0
- package/dist/src/plugins/entitlements/sources/index.d.ts.map +1 -1
- package/dist/src/plugins/entitlements/sources/index.js +1 -0
- package/dist/src/plugins/entitlements/sources/index.js.map +1 -1
- package/dist/src/plugins/health-plugin.d.ts.map +1 -1
- package/dist/src/plugins/health-plugin.js +1 -0
- package/dist/src/plugins/health-plugin.js.map +1 -1
- package/dist/src/plugins/index.d.ts +4 -4
- package/dist/src/plugins/index.d.ts.map +1 -1
- package/dist/src/plugins/index.js +4 -4
- package/dist/src/plugins/index.js.map +1 -1
- package/dist/src/plugins/logs-plugin.d.ts.map +1 -1
- package/dist/src/plugins/logs-plugin.js +49 -1
- package/dist/src/plugins/logs-plugin.js.map +1 -1
- package/dist/src/plugins/maintenance-plugin.d.ts.map +1 -1
- package/dist/src/plugins/maintenance-plugin.js +39 -0
- package/dist/src/plugins/maintenance-plugin.js.map +1 -1
- package/dist/src/plugins/notifications/notifications-plugin.d.ts.map +1 -1
- package/dist/src/plugins/notifications/notifications-plugin.js +1 -0
- package/dist/src/plugins/notifications/notifications-plugin.js.map +1 -1
- package/dist/src/plugins/postgres-plugin.d.ts +3 -1
- package/dist/src/plugins/postgres-plugin.d.ts.map +1 -1
- package/dist/src/plugins/postgres-plugin.js +18 -8
- package/dist/src/plugins/postgres-plugin.js.map +1 -1
- package/dist/src/plugins/tenants/index.d.ts +1 -1
- package/dist/src/plugins/tenants/index.d.ts.map +1 -1
- package/dist/src/plugins/tenants/index.js +1 -1
- package/dist/src/plugins/tenants/index.js.map +1 -1
- package/dist/src/plugins/tenants/stores/in-memory-store.d.ts +59 -0
- package/dist/src/plugins/tenants/stores/in-memory-store.d.ts.map +1 -0
- package/dist/src/plugins/tenants/stores/in-memory-store.js +257 -0
- package/dist/src/plugins/tenants/stores/in-memory-store.js.map +1 -0
- package/dist/src/plugins/tenants/stores/index.d.ts +8 -0
- package/dist/src/plugins/tenants/stores/index.d.ts.map +1 -0
- package/dist/src/plugins/tenants/stores/index.js +8 -0
- package/dist/src/plugins/tenants/stores/index.js.map +1 -0
- package/dist/src/plugins/tenants/tenants-plugin.js +3 -3
- package/dist/src/plugins/tenants/tenants-plugin.js.map +1 -1
- package/dist/src/plugins/users/index.d.ts +1 -1
- package/dist/src/plugins/users/index.d.ts.map +1 -1
- package/dist/src/plugins/users/index.js +1 -1
- package/dist/src/plugins/users/index.js.map +1 -1
- package/dist/src/plugins/users/stores/in-memory-store.d.ts +36 -0
- package/dist/src/plugins/users/stores/in-memory-store.d.ts.map +1 -0
- package/dist/src/plugins/users/stores/in-memory-store.js +122 -0
- package/dist/src/plugins/users/stores/in-memory-store.js.map +1 -0
- package/dist/src/plugins/users/stores/index.d.ts +1 -0
- package/dist/src/plugins/users/stores/index.d.ts.map +1 -1
- package/dist/src/plugins/users/stores/index.js +1 -0
- package/dist/src/plugins/users/stores/index.js.map +1 -1
- package/dist/ui/src/api/controlPanelApi.d.ts +10 -1
- package/dist/ui/src/api/controlPanelApi.d.ts.map +1 -1
- package/dist/ui/src/api/controlPanelApi.js.map +1 -1
- package/dist/ui/src/dashboard/PluginWidgetRenderer.d.ts +3 -1
- package/dist/ui/src/dashboard/PluginWidgetRenderer.d.ts.map +1 -1
- package/dist/ui/src/dashboard/PluginWidgetRenderer.js +5 -1
- package/dist/ui/src/dashboard/PluginWidgetRenderer.js.map +1 -1
- package/dist/ui/src/dashboard/builtInWidgets.d.ts.map +1 -1
- package/dist/ui/src/dashboard/builtInWidgets.js +13 -1
- package/dist/ui/src/dashboard/builtInWidgets.js.map +1 -1
- package/dist/ui/src/dashboard/widgets/CacheMaintenanceWidget.d.ts +11 -0
- package/dist/ui/src/dashboard/widgets/CacheMaintenanceWidget.d.ts.map +1 -0
- package/dist/ui/src/dashboard/widgets/CacheMaintenanceWidget.js +77 -0
- package/dist/ui/src/dashboard/widgets/CacheMaintenanceWidget.js.map +1 -0
- package/dist/ui/src/dashboard/widgets/DatabaseOpsWidget.d.ts +10 -0
- package/dist/ui/src/dashboard/widgets/DatabaseOpsWidget.d.ts.map +1 -0
- package/dist/ui/src/dashboard/widgets/DatabaseOpsWidget.js +14 -0
- package/dist/ui/src/dashboard/widgets/DatabaseOpsWidget.js.map +1 -0
- package/dist/ui/src/dashboard/widgets/EnvironmentConfigWidget.d.ts +10 -0
- package/dist/ui/src/dashboard/widgets/EnvironmentConfigWidget.d.ts.map +1 -0
- package/dist/ui/src/dashboard/widgets/EnvironmentConfigWidget.js +14 -0
- package/dist/ui/src/dashboard/widgets/EnvironmentConfigWidget.js.map +1 -0
- package/dist/ui/src/dashboard/widgets/LogsMaintenanceWidget.d.ts +11 -0
- package/dist/ui/src/dashboard/widgets/LogsMaintenanceWidget.d.ts.map +1 -0
- package/dist/ui/src/dashboard/widgets/LogsMaintenanceWidget.js +96 -0
- package/dist/ui/src/dashboard/widgets/LogsMaintenanceWidget.js.map +1 -0
- package/dist/ui/src/dashboard/widgets/SeedManagementWidget.d.ts +10 -0
- package/dist/ui/src/dashboard/widgets/SeedManagementWidget.d.ts.map +1 -0
- package/dist/ui/src/dashboard/widgets/SeedManagementWidget.js +55 -0
- package/dist/ui/src/dashboard/widgets/SeedManagementWidget.js.map +1 -0
- package/dist/ui/src/dashboard/widgets/ServiceControlWidget.d.ts +10 -0
- package/dist/ui/src/dashboard/widgets/ServiceControlWidget.d.ts.map +1 -0
- package/dist/ui/src/dashboard/widgets/ServiceControlWidget.js +14 -0
- package/dist/ui/src/dashboard/widgets/ServiceControlWidget.js.map +1 -0
- package/dist/ui/src/dashboard/widgets/index.d.ts +6 -0
- package/dist/ui/src/dashboard/widgets/index.d.ts.map +1 -1
- package/dist/ui/src/dashboard/widgets/index.js +6 -0
- package/dist/ui/src/dashboard/widgets/index.js.map +1 -1
- package/dist/ui/src/pages/DashboardPage.js +1 -1
- package/dist/ui/src/pages/DashboardPage.js.map +1 -1
- package/dist-ui/assets/{index-lm1yX6UD.js → index-8y0jDGcd.js} +112 -112
- package/dist-ui/assets/{index-lm1yX6UD.js.map → index-8y0jDGcd.js.map} +1 -1
- package/dist-ui/index.html +1 -1
- package/dist-ui-lib/index.js +3109 -2774
- package/dist-ui-lib/index.js.map +1 -1
- package/dist-ui-lib/src/api/controlPanelApi.d.ts +10 -1
- package/dist-ui-lib/src/dashboard/PluginWidgetRenderer.d.ts +3 -1
- package/dist-ui-lib/src/dashboard/widgets/CacheMaintenanceWidget.d.ts +10 -0
- package/dist-ui-lib/src/dashboard/widgets/DatabaseOpsWidget.d.ts +9 -0
- package/dist-ui-lib/src/dashboard/widgets/EnvironmentConfigWidget.d.ts +9 -0
- package/dist-ui-lib/src/dashboard/widgets/LogsMaintenanceWidget.d.ts +10 -0
- package/dist-ui-lib/src/dashboard/widgets/SeedManagementWidget.d.ts +9 -0
- package/dist-ui-lib/src/dashboard/widgets/ServiceControlWidget.d.ts +9 -0
- package/dist-ui-lib/src/dashboard/widgets/index.d.ts +6 -0
- package/package.json +5 -2
- package/src/core/control-panel.ts +6 -4
- package/src/core/gateway.ts +25 -2
- package/src/core/plugin-registry.ts +15 -2
- package/src/index.ts +53 -0
- package/src/plugins/api-keys/stores/postgres-store.ts +30 -0
- package/src/plugins/auth/auth-plugin.ts +4 -2
- package/src/plugins/auth/env-config.ts +1 -0
- package/src/plugins/bans/index.ts +1 -1
- package/src/plugins/bans/stores/in-memory-store.ts +106 -0
- package/src/plugins/bans/stores/index.ts +1 -0
- package/src/plugins/cache-plugin.test.ts +2 -2
- package/src/plugins/cache-plugin.ts +331 -30
- package/src/plugins/cms/cms-plugin.ts +3 -1
- package/src/plugins/entitlements/index.ts +1 -1
- package/src/plugins/entitlements/sources/in-memory-source.ts +76 -0
- package/src/plugins/entitlements/sources/index.ts +1 -0
- package/src/plugins/health-plugin.ts +1 -0
- package/src/plugins/index.ts +4 -1
- package/src/plugins/logs-plugin.ts +55 -1
- package/src/plugins/maintenance-plugin.ts +43 -0
- package/src/plugins/notifications/notifications-plugin.ts +1 -0
- package/src/plugins/postgres-plugin.test.ts +2 -2
- package/src/plugins/postgres-plugin.ts +20 -9
- package/src/plugins/tenants/index.ts +1 -1
- package/src/plugins/tenants/stores/in-memory-store.ts +335 -0
- package/src/plugins/tenants/stores/index.ts +13 -0
- package/src/plugins/tenants/tenants-plugin.ts +3 -3
- package/src/plugins/users/index.ts +1 -1
- package/src/plugins/users/stores/in-memory-store.ts +140 -0
- package/src/plugins/users/stores/index.ts +1 -0
- package/src/testing/index.ts +1 -0
- package/src/testing/pg-mem-pool.ts +33 -0
- package/ui/src/api/controlPanelApi.ts +10 -1
- package/ui/src/dashboard/PluginWidgetRenderer.tsx +8 -0
- package/ui/src/dashboard/builtInWidgets.tsx +19 -1
- package/ui/src/dashboard/widgets/CacheMaintenanceWidget.tsx +195 -0
- package/ui/src/dashboard/widgets/DatabaseOpsWidget.tsx +29 -0
- package/ui/src/dashboard/widgets/EnvironmentConfigWidget.tsx +29 -0
- package/ui/src/dashboard/widgets/LogsMaintenanceWidget.tsx +247 -0
- package/ui/src/dashboard/widgets/SeedManagementWidget.tsx +128 -0
- package/ui/src/dashboard/widgets/ServiceControlWidget.tsx +29 -0
- package/ui/src/dashboard/widgets/index.ts +6 -0
- package/ui/src/pages/DashboardPage.tsx +2 -2
- package/ui/src/pages/MaintenancePage.tsx +1 -1
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory User Store for Demo/Testing
|
|
3
|
+
*
|
|
4
|
+
* Implements the UserStore interface with in-memory storage.
|
|
5
|
+
* Pre-populated with demo users for testing and showcase purposes.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export function createInMemoryUserStore() {
|
|
9
|
+
const users = new Map<string, any>();
|
|
10
|
+
let idCounter = 1;
|
|
11
|
+
|
|
12
|
+
// Pre-populate demo users
|
|
13
|
+
const demoUsers = [
|
|
14
|
+
{ email: 'demo@example.com', name: 'Demo User' },
|
|
15
|
+
{ email: 'pro@example.com', name: 'Pro User' },
|
|
16
|
+
{ email: 'enterprise@example.com', name: 'Enterprise User' },
|
|
17
|
+
{ email: 'basic@example.com', name: 'Basic User' },
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
demoUsers.forEach((u) => {
|
|
21
|
+
const id = String(idCounter++);
|
|
22
|
+
users.set(id, {
|
|
23
|
+
id,
|
|
24
|
+
email: u.email,
|
|
25
|
+
name: u.name,
|
|
26
|
+
created_at: new Date(),
|
|
27
|
+
updated_at: new Date(),
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
name: 'in-memory',
|
|
33
|
+
|
|
34
|
+
async initialize() {
|
|
35
|
+
console.log('[InMemoryUserStore] Initialized with demo users');
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
async getById(id: string) {
|
|
39
|
+
return users.get(id) || null;
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
async getByEmail(email: string) {
|
|
43
|
+
for (const user of users.values()) {
|
|
44
|
+
if (user.email === email.toLowerCase()) {
|
|
45
|
+
return user;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
async getByExternalId(externalId: string, provider: string) {
|
|
52
|
+
for (const user of users.values()) {
|
|
53
|
+
if (user.external_id === externalId && user.provider === provider) {
|
|
54
|
+
return user;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
async create(input: any) {
|
|
61
|
+
const id = String(idCounter++);
|
|
62
|
+
const user = {
|
|
63
|
+
id,
|
|
64
|
+
email: input.email.toLowerCase(),
|
|
65
|
+
name: input.name || null,
|
|
66
|
+
external_id: input.external_id,
|
|
67
|
+
provider: input.provider,
|
|
68
|
+
picture: input.picture,
|
|
69
|
+
created_at: new Date(),
|
|
70
|
+
updated_at: new Date(),
|
|
71
|
+
metadata: input.metadata || {},
|
|
72
|
+
};
|
|
73
|
+
users.set(id, user);
|
|
74
|
+
return user;
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
async update(id: string, input: any) {
|
|
78
|
+
const user = users.get(id);
|
|
79
|
+
if (!user) return null;
|
|
80
|
+
Object.assign(user, input, { updated_at: new Date() });
|
|
81
|
+
return user;
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
async delete(id: string) {
|
|
85
|
+
return users.delete(id);
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
async search(params: any = {}) {
|
|
89
|
+
let result = Array.from(users.values());
|
|
90
|
+
|
|
91
|
+
if (params.query) {
|
|
92
|
+
const query = params.query.toLowerCase();
|
|
93
|
+
result = result.filter(
|
|
94
|
+
(u) =>
|
|
95
|
+
u.email.toLowerCase().includes(query) ||
|
|
96
|
+
(u.name && u.name.toLowerCase().includes(query))
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (params.provider) {
|
|
101
|
+
result = result.filter((u) => u.provider === params.provider);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const sortBy = params.sortBy || 'created_at';
|
|
105
|
+
const sortOrder = params.sortOrder || 'desc';
|
|
106
|
+
result.sort((a, b) => {
|
|
107
|
+
const aVal = a[sortBy];
|
|
108
|
+
const bVal = b[sortBy];
|
|
109
|
+
if (aVal < bVal) return sortOrder === 'asc' ? -1 : 1;
|
|
110
|
+
if (aVal > bVal) return sortOrder === 'asc' ? 1 : -1;
|
|
111
|
+
return 0;
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
const total = result.length;
|
|
115
|
+
const page = params.page || 1;
|
|
116
|
+
const limit = params.limit || 20;
|
|
117
|
+
const offset = (page - 1) * limit;
|
|
118
|
+
result = result.slice(offset, offset + limit);
|
|
119
|
+
|
|
120
|
+
return {
|
|
121
|
+
users: result,
|
|
122
|
+
total,
|
|
123
|
+
page,
|
|
124
|
+
limit,
|
|
125
|
+
totalPages: Math.ceil(total / limit),
|
|
126
|
+
};
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
async updateLastLogin(id: string) {
|
|
130
|
+
const user = users.get(id);
|
|
131
|
+
if (user) {
|
|
132
|
+
user.last_login_at = new Date();
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
async shutdown() {
|
|
137
|
+
console.log('[InMemoryUserStore] Shutdown');
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createPgMemPool } from './pg-mem-pool.js';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pg-mem Pool Adapter
|
|
3
|
+
*
|
|
4
|
+
* Provides a pg.Pool-compatible interface for pg-mem (in-memory PostgreSQL).
|
|
5
|
+
* Used by demos to run without requiring an actual PostgreSQL installation.
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { newDb } from 'pg-mem';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Create an in-memory PostgreSQL database with a Pool-compatible interface
|
|
14
|
+
*
|
|
15
|
+
* @returns Pool-compatible interface backed by pg-mem
|
|
16
|
+
*/
|
|
17
|
+
export function createPgMemPool() {
|
|
18
|
+
const db = newDb();
|
|
19
|
+
|
|
20
|
+
// Get the Pool-compatible adapter from pg-mem
|
|
21
|
+
const { Pool } = db.adapters.createPg();
|
|
22
|
+
const pool = new Pool();
|
|
23
|
+
|
|
24
|
+
// Add a fake connection string for plugins that need it (like notifications)
|
|
25
|
+
// pg-mem doesn't use connection strings, but some plugins try to extract it
|
|
26
|
+
(pool as any).options = {
|
|
27
|
+
connectionString: 'postgresql://localhost/pgmem',
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
console.log('[pg-mem] In-memory PostgreSQL database created');
|
|
31
|
+
|
|
32
|
+
return pool;
|
|
33
|
+
}
|
|
@@ -304,9 +304,18 @@ export interface WidgetContribution {
|
|
|
304
304
|
title: string;
|
|
305
305
|
/** Component name to render (matched by frontend widget registry) */
|
|
306
306
|
component: string;
|
|
307
|
+
/**
|
|
308
|
+
* Widget type/category - determines which page(s) can display this widget
|
|
309
|
+
* - 'status': System health, service status, monitoring metrics (Dashboard)
|
|
310
|
+
* - 'maintenance': Operational tasks like seeding, service control, config (Maintenance page)
|
|
311
|
+
* - 'analytics': Charts, graphs, usage metrics (Dashboard or Analytics page)
|
|
312
|
+
* - 'monitoring': Performance, logs, real-time data (Monitoring page)
|
|
313
|
+
* - 'custom': Custom widgets for specific use cases
|
|
314
|
+
*/
|
|
315
|
+
type: 'status' | 'maintenance' | 'analytics' | 'monitoring' | 'custom';
|
|
307
316
|
/** Priority for ordering (lower = first, default: 100) */
|
|
308
317
|
priority?: number;
|
|
309
|
-
/** Whether this widget is shown by default */
|
|
318
|
+
/** Whether this widget is shown by default on its designated page */
|
|
310
319
|
showByDefault?: boolean;
|
|
311
320
|
pluginId: string;
|
|
312
321
|
}
|
|
@@ -19,12 +19,15 @@ interface WidgetContribution {
|
|
|
19
19
|
id: string;
|
|
20
20
|
title: string;
|
|
21
21
|
component: string;
|
|
22
|
+
type: 'status' | 'maintenance' | 'analytics' | 'monitoring' | 'custom';
|
|
22
23
|
priority?: number;
|
|
23
24
|
showByDefault?: boolean;
|
|
24
25
|
pluginId: string;
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
interface PluginWidgetRendererProps {
|
|
29
|
+
/** Filter widgets by type (e.g., 'status' for dashboard, 'maintenance' for maintenance page) */
|
|
30
|
+
widgetType?: 'status' | 'maintenance' | 'analytics' | 'monitoring' | 'custom';
|
|
28
31
|
/** Only show widgets marked as showByDefault (default: true) */
|
|
29
32
|
defaultOnly?: boolean;
|
|
30
33
|
/** Additional widget IDs to show (beyond showByDefault) */
|
|
@@ -35,6 +38,7 @@ interface PluginWidgetRendererProps {
|
|
|
35
38
|
* Renders widgets from plugins that have registered them via the server API
|
|
36
39
|
*/
|
|
37
40
|
export function PluginWidgetRenderer({
|
|
41
|
+
widgetType,
|
|
38
42
|
defaultOnly = true,
|
|
39
43
|
additionalWidgetIds = [],
|
|
40
44
|
}: PluginWidgetRendererProps) {
|
|
@@ -78,6 +82,10 @@ export function PluginWidgetRenderer({
|
|
|
78
82
|
// Filter widgets to show
|
|
79
83
|
const visibleWidgets = widgets
|
|
80
84
|
.filter(widget => {
|
|
85
|
+
// Filter by widget type if specified
|
|
86
|
+
if (widgetType && widget.type !== widgetType) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
81
89
|
// Show if marked as default, or if in additionalWidgetIds
|
|
82
90
|
if (defaultOnly) {
|
|
83
91
|
return widget.showByDefault || additionalWidgetIds.includes(widget.id);
|
|
@@ -16,7 +16,13 @@ import {
|
|
|
16
16
|
AuthStatusWidget,
|
|
17
17
|
NotificationsStatsWidget,
|
|
18
18
|
CMSStatusWidget,
|
|
19
|
-
CMSMaintenanceWidget
|
|
19
|
+
CMSMaintenanceWidget,
|
|
20
|
+
SeedManagementWidget,
|
|
21
|
+
ServiceControlWidget,
|
|
22
|
+
EnvironmentConfigWidget,
|
|
23
|
+
DatabaseOpsWidget,
|
|
24
|
+
LogsMaintenanceWidget,
|
|
25
|
+
CacheMaintenanceWidget,
|
|
20
26
|
} from './widgets';
|
|
21
27
|
import { PreferencesPage } from '../pages/PreferencesPage';
|
|
22
28
|
import type { WidgetComponent } from './WidgetComponentRegistry';
|
|
@@ -32,6 +38,12 @@ export const builtInWidgetComponents: Record<string, React.ComponentType> = {
|
|
|
32
38
|
NotificationsStatsWidget: NotificationsStatsWidget,
|
|
33
39
|
CMSStatusWidget: CMSStatusWidget,
|
|
34
40
|
CMSMaintenanceWidget: CMSMaintenanceWidget,
|
|
41
|
+
SeedManagementWidget: SeedManagementWidget,
|
|
42
|
+
ServiceControlWidget: ServiceControlWidget,
|
|
43
|
+
EnvironmentConfigWidget: EnvironmentConfigWidget,
|
|
44
|
+
DatabaseOpsWidget: DatabaseOpsWidget,
|
|
45
|
+
LogsMaintenanceWidget: LogsMaintenanceWidget,
|
|
46
|
+
CacheMaintenanceWidget: CacheMaintenanceWidget,
|
|
35
47
|
PreferencesPage: PreferencesPage,
|
|
36
48
|
};
|
|
37
49
|
|
|
@@ -50,6 +62,12 @@ export function getBuiltInWidgetComponents(): WidgetComponent[] {
|
|
|
50
62
|
{ name: 'NotificationsStatsWidget', component: NotificationsStatsWidget },
|
|
51
63
|
{ name: 'CMSStatusWidget', component: CMSStatusWidget },
|
|
52
64
|
{ name: 'CMSMaintenanceWidget', component: CMSMaintenanceWidget },
|
|
65
|
+
{ name: 'SeedManagementWidget', component: SeedManagementWidget },
|
|
66
|
+
{ name: 'ServiceControlWidget', component: ServiceControlWidget },
|
|
67
|
+
{ name: 'EnvironmentConfigWidget', component: EnvironmentConfigWidget },
|
|
68
|
+
{ name: 'DatabaseOpsWidget', component: DatabaseOpsWidget },
|
|
69
|
+
{ name: 'LogsMaintenanceWidget', component: LogsMaintenanceWidget },
|
|
70
|
+
{ name: 'CacheMaintenanceWidget', component: CacheMaintenanceWidget },
|
|
53
71
|
{ name: 'PreferencesPage', component: PreferencesPage },
|
|
54
72
|
];
|
|
55
73
|
}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cache Maintenance Widget
|
|
3
|
+
*
|
|
4
|
+
* Provides cache management operations:
|
|
5
|
+
* - View cache statistics
|
|
6
|
+
* - Clear cache (flush all keys)
|
|
7
|
+
*
|
|
8
|
+
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { useState, useEffect } from 'react';
|
|
12
|
+
import {
|
|
13
|
+
Card,
|
|
14
|
+
CardContent,
|
|
15
|
+
Typography,
|
|
16
|
+
Button,
|
|
17
|
+
Alert,
|
|
18
|
+
Box,
|
|
19
|
+
Dialog,
|
|
20
|
+
DialogTitle,
|
|
21
|
+
DialogContent,
|
|
22
|
+
DialogContentText,
|
|
23
|
+
DialogActions,
|
|
24
|
+
CircularProgress,
|
|
25
|
+
Chip,
|
|
26
|
+
} from '@mui/material';
|
|
27
|
+
import DeleteIcon from '@mui/icons-material/Delete';
|
|
28
|
+
import RefreshIcon from '@mui/icons-material/Refresh';
|
|
29
|
+
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
|
|
30
|
+
import ErrorIcon from '@mui/icons-material/Error';
|
|
31
|
+
|
|
32
|
+
interface CacheStats {
|
|
33
|
+
connected: boolean;
|
|
34
|
+
keyCount: number;
|
|
35
|
+
usedMemory?: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function CacheMaintenanceWidget() {
|
|
39
|
+
const [stats, setStats] = useState<CacheStats | null>(null);
|
|
40
|
+
const [loading, setLoading] = useState(true);
|
|
41
|
+
const [flushing, setFlushing] = useState(false);
|
|
42
|
+
const [error, setError] = useState<string | null>(null);
|
|
43
|
+
const [success, setSuccess] = useState<string | null>(null);
|
|
44
|
+
const [confirmOpen, setConfirmOpen] = useState(false);
|
|
45
|
+
|
|
46
|
+
const fetchStats = async () => {
|
|
47
|
+
setLoading(true);
|
|
48
|
+
setError(null);
|
|
49
|
+
try {
|
|
50
|
+
const response = await fetch('/api/cache:default/stats');
|
|
51
|
+
if (!response.ok) {
|
|
52
|
+
if (response.status === 404) {
|
|
53
|
+
throw new Error('Cache plugin not configured');
|
|
54
|
+
}
|
|
55
|
+
throw new Error('Failed to fetch cache stats');
|
|
56
|
+
}
|
|
57
|
+
const data = await response.json();
|
|
58
|
+
setStats(data);
|
|
59
|
+
} catch (err) {
|
|
60
|
+
setError(err instanceof Error ? err.message : 'Failed to fetch cache stats');
|
|
61
|
+
setStats(null);
|
|
62
|
+
} finally {
|
|
63
|
+
setLoading(false);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
fetchStats();
|
|
69
|
+
}, []);
|
|
70
|
+
|
|
71
|
+
const handleFlushCache = async () => {
|
|
72
|
+
setConfirmOpen(false);
|
|
73
|
+
setFlushing(true);
|
|
74
|
+
setError(null);
|
|
75
|
+
setSuccess(null);
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
const response = await fetch('/api/cache:default/flush', {
|
|
79
|
+
method: 'POST',
|
|
80
|
+
headers: { 'Content-Type': 'application/json' },
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
if (!response.ok) {
|
|
84
|
+
const data = await response.json();
|
|
85
|
+
throw new Error(data.error || 'Failed to flush cache');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const data = await response.json();
|
|
89
|
+
setSuccess(
|
|
90
|
+
data.message + (data.deletedCount !== undefined ? ` (${data.deletedCount} keys deleted)` : '')
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
// Refresh stats
|
|
94
|
+
await fetchStats();
|
|
95
|
+
} catch (err) {
|
|
96
|
+
setError(err instanceof Error ? err.message : 'Failed to flush cache');
|
|
97
|
+
} finally {
|
|
98
|
+
setFlushing(false);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
return (
|
|
103
|
+
<Card>
|
|
104
|
+
<CardContent>
|
|
105
|
+
<Typography variant="h6" gutterBottom>
|
|
106
|
+
Cache Management
|
|
107
|
+
</Typography>
|
|
108
|
+
<Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>
|
|
109
|
+
View cache statistics and clear cache
|
|
110
|
+
</Typography>
|
|
111
|
+
|
|
112
|
+
{error && (
|
|
113
|
+
<Alert severity="error" sx={{ mb: 2 }} onClose={() => setError(null)}>
|
|
114
|
+
{error}
|
|
115
|
+
</Alert>
|
|
116
|
+
)}
|
|
117
|
+
|
|
118
|
+
{success && (
|
|
119
|
+
<Alert severity="success" sx={{ mb: 2 }} onClose={() => setSuccess(null)}>
|
|
120
|
+
{success}
|
|
121
|
+
</Alert>
|
|
122
|
+
)}
|
|
123
|
+
|
|
124
|
+
{loading ? (
|
|
125
|
+
<Box sx={{ display: 'flex', justifyContent: 'center', p: 3 }}>
|
|
126
|
+
<CircularProgress size={30} />
|
|
127
|
+
</Box>
|
|
128
|
+
) : stats ? (
|
|
129
|
+
<Box sx={{ mb: 2 }}>
|
|
130
|
+
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 1 }}>
|
|
131
|
+
<Typography variant="body2" color="text.secondary">
|
|
132
|
+
<strong>Status:</strong>
|
|
133
|
+
</Typography>
|
|
134
|
+
<Chip
|
|
135
|
+
size="small"
|
|
136
|
+
icon={stats.connected ? <CheckCircleIcon /> : <ErrorIcon />}
|
|
137
|
+
label={stats.connected ? 'Connected' : 'Disconnected'}
|
|
138
|
+
color={stats.connected ? 'success' : 'error'}
|
|
139
|
+
/>
|
|
140
|
+
</Box>
|
|
141
|
+
|
|
142
|
+
<Typography variant="body2" color="text.secondary">
|
|
143
|
+
<strong>Key Count:</strong> {stats.keyCount.toLocaleString()}
|
|
144
|
+
</Typography>
|
|
145
|
+
|
|
146
|
+
{stats.usedMemory && (
|
|
147
|
+
<Typography variant="body2" color="text.secondary">
|
|
148
|
+
<strong>Memory Used:</strong> {stats.usedMemory}
|
|
149
|
+
</Typography>
|
|
150
|
+
)}
|
|
151
|
+
</Box>
|
|
152
|
+
) : null}
|
|
153
|
+
|
|
154
|
+
<Box sx={{ display: 'flex', gap: 1 }}>
|
|
155
|
+
<Button
|
|
156
|
+
variant="outlined"
|
|
157
|
+
color="primary"
|
|
158
|
+
size="small"
|
|
159
|
+
startIcon={<RefreshIcon />}
|
|
160
|
+
onClick={fetchStats}
|
|
161
|
+
disabled={loading}
|
|
162
|
+
>
|
|
163
|
+
Refresh
|
|
164
|
+
</Button>
|
|
165
|
+
<Button
|
|
166
|
+
variant="contained"
|
|
167
|
+
color="error"
|
|
168
|
+
size="small"
|
|
169
|
+
startIcon={flushing ? <CircularProgress size={16} color="inherit" /> : <DeleteIcon />}
|
|
170
|
+
onClick={() => setConfirmOpen(true)}
|
|
171
|
+
disabled={!stats || !stats.connected || flushing || loading}
|
|
172
|
+
>
|
|
173
|
+
Flush Cache
|
|
174
|
+
</Button>
|
|
175
|
+
</Box>
|
|
176
|
+
|
|
177
|
+
<Dialog open={confirmOpen} onClose={() => setConfirmOpen(false)}>
|
|
178
|
+
<DialogTitle>Flush Cache</DialogTitle>
|
|
179
|
+
<DialogContent>
|
|
180
|
+
<DialogContentText>
|
|
181
|
+
Are you sure you want to flush the cache? This will delete{' '}
|
|
182
|
+
{stats?.keyCount.toLocaleString()} keys. This action cannot be undone.
|
|
183
|
+
</DialogContentText>
|
|
184
|
+
</DialogContent>
|
|
185
|
+
<DialogActions>
|
|
186
|
+
<Button onClick={() => setConfirmOpen(false)}>Cancel</Button>
|
|
187
|
+
<Button onClick={handleFlushCache} color="error" variant="contained">
|
|
188
|
+
Flush
|
|
189
|
+
</Button>
|
|
190
|
+
</DialogActions>
|
|
191
|
+
</Dialog>
|
|
192
|
+
</CardContent>
|
|
193
|
+
</Card>
|
|
194
|
+
);
|
|
195
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database Operations Widget
|
|
3
|
+
*
|
|
4
|
+
* Provides database backup, restore, and maintenance operations.
|
|
5
|
+
* Part of the maintenance plugin.
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { Card, CardContent, Typography, Alert } from '@mui/material';
|
|
11
|
+
|
|
12
|
+
export function DatabaseOpsWidget() {
|
|
13
|
+
return (
|
|
14
|
+
<Card>
|
|
15
|
+
<CardContent>
|
|
16
|
+
<Typography variant="h6" gutterBottom>
|
|
17
|
+
Database Operations
|
|
18
|
+
</Typography>
|
|
19
|
+
<Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>
|
|
20
|
+
Backup, restore, and maintain database
|
|
21
|
+
</Typography>
|
|
22
|
+
|
|
23
|
+
<Alert severity="info">
|
|
24
|
+
Database operations UI coming soon. This will allow you to backup and restore your database.
|
|
25
|
+
</Alert>
|
|
26
|
+
</CardContent>
|
|
27
|
+
</Card>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment Configuration Widget
|
|
3
|
+
*
|
|
4
|
+
* Displays and allows editing environment variables.
|
|
5
|
+
* Part of the maintenance plugin.
|
|
6
|
+
*
|
|
7
|
+
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { Card, CardContent, Typography, Alert } from '@mui/material';
|
|
11
|
+
|
|
12
|
+
export function EnvironmentConfigWidget() {
|
|
13
|
+
return (
|
|
14
|
+
<Card>
|
|
15
|
+
<CardContent>
|
|
16
|
+
<Typography variant="h6" gutterBottom>
|
|
17
|
+
Environment Configuration
|
|
18
|
+
</Typography>
|
|
19
|
+
<Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>
|
|
20
|
+
View and manage environment variables
|
|
21
|
+
</Typography>
|
|
22
|
+
|
|
23
|
+
<Alert severity="info">
|
|
24
|
+
Environment configuration UI coming soon. This will allow you to view and edit environment variables.
|
|
25
|
+
</Alert>
|
|
26
|
+
</CardContent>
|
|
27
|
+
</Card>
|
|
28
|
+
);
|
|
29
|
+
}
|