webspresso 0.0.97 → 0.0.99
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/.agents/ADMIN.md +163 -5
- package/.agents/AGENTS.md +1 -1
- package/.agents/ARCHITECTURE.md +10 -0
- package/.agents/AUTH.md +169 -0
- package/.agents/CLI.md +195 -1
- package/.agents/ORM.md +88 -4
- package/.agents/PLUGINS.md +221 -9
- package/.agents/QUEUE.md +127 -0
- package/.agents/ROUTING.md +127 -7
- package/AGENTS.md +1 -0
- package/bin/commands/add-esbuild.js +80 -0
- package/bin/commands/add-tailwind.js +76 -31
- package/bin/commands/analytics-prune.js +57 -0
- package/bin/commands/api.js +207 -15
- package/bin/commands/build.js +99 -0
- package/bin/commands/dev.js +64 -35
- package/bin/commands/doctor.js +26 -0
- package/bin/commands/email-prune.js +47 -0
- package/bin/commands/make-job.js +86 -0
- package/bin/commands/make-model.js +250 -0
- package/bin/commands/new.js +45 -28
- package/bin/commands/openapi.js +102 -0
- package/bin/commands/page.js +6 -3
- package/bin/commands/queue-prune.js +59 -0
- package/bin/commands/routes.js +52 -0
- package/bin/commands/service.js +6 -3
- package/bin/commands/typegen.js +106 -0
- package/bin/commands/upload-prune.js +79 -0
- package/bin/webspresso.js +22 -0
- package/core/applySchema.js +13 -6
- package/core/auth/hash.js +21 -12
- package/core/auth/index.js +60 -0
- package/core/auth/manager.js +134 -0
- package/core/auth/middleware.js +88 -0
- package/core/auth/oauth.js +517 -0
- package/core/auth/qrcode.js +499 -0
- package/core/auth/totp.js +504 -0
- package/core/compression/middleware.js +23 -17
- package/core/openapi/build-from-api-routes.js +160 -29
- package/core/orm/cache/fingerprint.js +15 -1
- package/core/orm/cache/memory-provider.js +27 -2
- package/core/orm/eager-loader.js +144 -10
- package/core/orm/index.js +20 -7
- package/core/orm/model.js +53 -7
- package/core/orm/query-builder.js +90 -4
- package/core/orm/repository.js +44 -3
- package/core/orm/search.js +213 -0
- package/core/queue/adapters/database.js +94 -0
- package/core/queue/adapters/memory.js +62 -0
- package/core/queue/adapters/redis.js +80 -0
- package/core/queue/cron.js +331 -0
- package/core/queue/index.js +8 -1
- package/core/queue/manager.js +205 -1
- package/core/queue/scheduler.js +359 -0
- package/core/sse/index.js +19 -0
- package/core/sse/stream.js +430 -0
- package/core/ssr/stream.js +11 -0
- package/index.d.ts +1188 -10
- package/index.js +88 -96
- package/package.json +1 -1
- package/plugins/admin-panel/api.js +279 -17
- package/plugins/admin-panel/app.js +114 -22
- package/plugins/admin-panel/client/parts/01-state-api-breadcrumb.js +314 -9
- package/plugins/admin-panel/client/parts/04-field-renderers.js +264 -67
- package/plugins/admin-panel/client/parts/05-rich-text-file-helpers.js +333 -36
- package/plugins/admin-panel/client/parts/06-login-setup-forms.js +119 -28
- package/plugins/admin-panel/client/parts/07-model-list.js +49 -8
- package/plugins/admin-panel/client/parts/08-record-list.js +248 -23
- package/plugins/admin-panel/client/parts/09-record-form.js +59 -12
- package/plugins/admin-panel/client/parts/10-export-registry.js +23 -0
- package/plugins/admin-panel/client/verify-spa-parts.js +2 -0
- package/plugins/admin-panel/core/admin-module.js +13 -7
- package/plugins/admin-panel/core/api-extensions.js +30 -2
- package/plugins/admin-panel/core/registry.js +96 -16
- package/plugins/admin-panel/field-renderers/file-upload.js +187 -104
- package/plugins/admin-panel/field-renderers/index.js +2 -0
- package/plugins/admin-panel/index.js +96 -0
- package/plugins/admin-panel/lib/login-rate-limiter.js +119 -0
- package/plugins/admin-panel/modules/admin-users.js +16 -1
- package/plugins/admin-panel/modules/bulk-actions.js +13 -5
- package/plugins/admin-panel/modules/custom-pages.js +492 -3
- package/plugins/admin-panel/modules/dashboard.js +283 -0
- package/plugins/admin-panel/modules/menu.js +56 -18
- package/plugins/admin-panel/modules/user-management.js +24 -6
- package/plugins/api-key/crypto.js +101 -0
- package/plugins/api-key/index.js +288 -0
- package/plugins/api-key/middleware.js +461 -0
- package/plugins/api-key/migration-template.js +48 -0
- package/plugins/api-key/model.js +50 -0
- package/plugins/api-key/scopes.js +125 -0
- package/plugins/audit-log/admin-component.js +487 -59
- package/plugins/audit-log/api-handlers.js +148 -0
- package/plugins/audit-log/index.js +153 -3
- package/plugins/audit-log/purge.js +60 -10
- package/plugins/dashboard/app.js +152 -27
- package/plugins/dashboard/index.js +143 -39
- package/plugins/dashboard/styles.js +78 -0
- package/plugins/data-exchange/export-xlsx.js +9 -2
- package/plugins/data-exchange/import.js +9 -2
- package/plugins/data-exchange/index.js +6 -3
- package/plugins/email/index.js +132 -2
- package/plugins/email/purge.js +60 -10
- package/plugins/file-manager/admin-component.js +20 -4
- package/plugins/file-manager/index.js +21 -4
- package/plugins/index.js +10 -0
- package/plugins/oauth/index.js +338 -0
- package/plugins/orm-cache-admin/index.js +4 -2
- package/plugins/queue/index.js +15 -0
- package/plugins/schema-explorer/admin-component.js +714 -0
- package/plugins/schema-explorer/relations-graph.js +205 -0
- package/plugins/schema-explorer.js +248 -69
- package/plugins/site-analytics/admin-component.js +23 -0
- package/plugins/site-analytics/api-handlers.js +42 -0
- package/plugins/site-analytics/index.js +147 -2
- package/plugins/site-analytics/purge.js +168 -0
- package/plugins/swagger.js +261 -13
- package/plugins/upload/index.js +26 -0
- package/plugins/upload/orphan-pruner.js +292 -0
- package/src/api/api-loader.js +4 -1
- package/src/bundle/index.js +517 -0
- package/src/bundle/manifest.js +165 -0
- package/src/dev/banner.js +296 -0
- package/src/dev/colors.js +70 -0
- package/src/dev/index.js +62 -0
- package/src/dev/profiler.js +354 -0
- package/src/dev/typegen.js +497 -0
- package/src/dev-reload/index.js +611 -0
- package/src/discovery/file-route-parser.js +44 -1
- package/src/discovery/scan-routes.js +2 -2
- package/src/file-router.js +347 -162
- package/src/helpers.js +967 -98
- package/src/njk-frontmatter.js +12 -0
- package/src/pages/page-loader.js +61 -11
- package/src/routing/cascading.js +378 -0
- package/src/routing/middleware-resolver.js +92 -0
- package/src/server.js +635 -63
package/plugins/email/index.js
CHANGED
|
@@ -29,10 +29,21 @@ const { emailPluginOptionsFromManifest } = require('./manifest');
|
|
|
29
29
|
* @param {Object} [options.authEmails] - Auth email bridge config
|
|
30
30
|
* @param {Object} [options.emailTemplates] - Precompiled templates from build manifest
|
|
31
31
|
* @param {Object} [options.manifest] - Full build manifest (uses emailTemplates field)
|
|
32
|
+
* @param {Object|boolean} [options.retention] - Retention policy configuration (set false to disable)
|
|
33
|
+
* @param {number} [options.retention.days=90] - Days to retain email logs
|
|
34
|
+
* @param {number} [options.retention.intervalMs=86400000] - Auto-cleanup timer frequency (24h)
|
|
35
|
+
* @param {boolean} [options.retention.runOnStart=true] - Run initial purge shortly after startup
|
|
36
|
+
* @param {number} [options.retentionDays=90] - Shorthand for retention.days
|
|
37
|
+
* @param {number} [options.cleanupIntervalMs=86400000] - Shorthand for retention.intervalMs
|
|
38
|
+
* @param {boolean} [options.autoCleanup=true] - Enable automatic background cleanup
|
|
39
|
+
* @param {boolean} [options.cleanupOnStart=true] - Run initial purge on start
|
|
40
|
+
* @param {number} [options.cleanupStartDelayMs] - Delay in ms before start purge
|
|
32
41
|
*/
|
|
33
42
|
function emailPlugin(options = {}) {
|
|
34
43
|
const {
|
|
35
44
|
db,
|
|
45
|
+
title,
|
|
46
|
+
adminTitle,
|
|
36
47
|
transport,
|
|
37
48
|
smtp,
|
|
38
49
|
defaults = {},
|
|
@@ -48,6 +59,8 @@ function emailPlugin(options = {}) {
|
|
|
48
59
|
manifest,
|
|
49
60
|
} = options;
|
|
50
61
|
|
|
62
|
+
const pageTitle = title || adminTitle || 'Email';
|
|
63
|
+
|
|
51
64
|
const logToDb = options.logToDb !== undefined ? options.logToDb : !!db;
|
|
52
65
|
const knex = db ? (db.knex || db) : null;
|
|
53
66
|
|
|
@@ -55,6 +68,90 @@ function emailPlugin(options = {}) {
|
|
|
55
68
|
console.warn('[email] logToDb is enabled but no db was passed — logging disabled');
|
|
56
69
|
}
|
|
57
70
|
|
|
71
|
+
// Retention configuration
|
|
72
|
+
const retentionOption = options.retention;
|
|
73
|
+
const isRetentionDisabled =
|
|
74
|
+
retentionOption === false ||
|
|
75
|
+
(typeof retentionOption === 'object' && retentionOption.enabled === false) ||
|
|
76
|
+
options.retentionDays === null ||
|
|
77
|
+
options.retentionDays === 0 ||
|
|
78
|
+
!logToDb ||
|
|
79
|
+
!knex;
|
|
80
|
+
|
|
81
|
+
const autoCleanupEnabled =
|
|
82
|
+
!isRetentionDisabled &&
|
|
83
|
+
options.autoCleanup !== false &&
|
|
84
|
+
(typeof retentionOption !== 'object' || retentionOption.autoCleanup !== false);
|
|
85
|
+
|
|
86
|
+
const retentionConfig = {
|
|
87
|
+
enabled: !isRetentionDisabled,
|
|
88
|
+
autoCleanup: autoCleanupEnabled,
|
|
89
|
+
days: (typeof options.retentionDays === 'number' && options.retentionDays > 0)
|
|
90
|
+
? options.retentionDays
|
|
91
|
+
: (typeof retentionOption === 'object' && retentionOption?.days ? retentionOption.days : 90),
|
|
92
|
+
intervalMs: (typeof options.cleanupIntervalMs === 'number' && options.cleanupIntervalMs > 0)
|
|
93
|
+
? options.cleanupIntervalMs
|
|
94
|
+
: (typeof retentionOption === 'object' && retentionOption?.intervalMs ? retentionOption.intervalMs : 24 * 60 * 60 * 1000),
|
|
95
|
+
runOnStart: (typeof retentionOption === 'object' && retentionOption?.runOnStart !== undefined)
|
|
96
|
+
? !!retentionOption.runOnStart
|
|
97
|
+
: (options.cleanupOnStart !== undefined ? !!options.cleanupOnStart : true),
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
let cleanupInterval = null;
|
|
101
|
+
let cleanupStartTimeout = null;
|
|
102
|
+
|
|
103
|
+
async function runCleanup() {
|
|
104
|
+
if (!knex) return 0;
|
|
105
|
+
try {
|
|
106
|
+
return await purgeEmailLogs(knex, {
|
|
107
|
+
tableName,
|
|
108
|
+
days: retentionConfig.days,
|
|
109
|
+
});
|
|
110
|
+
} catch (err) {
|
|
111
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
112
|
+
console.warn('[email] Failed to run retention cleanup:', err.message);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function startCleanup(customIntervalMs) {
|
|
118
|
+
stopCleanup();
|
|
119
|
+
if (!retentionConfig.enabled || !knex) return;
|
|
120
|
+
if (typeof customIntervalMs === 'number' && customIntervalMs > 0) {
|
|
121
|
+
retentionConfig.intervalMs = customIntervalMs;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (retentionConfig.runOnStart) {
|
|
125
|
+
const delayMs = typeof options.cleanupStartDelayMs === 'number'
|
|
126
|
+
? options.cleanupStartDelayMs
|
|
127
|
+
: (process.env.NODE_ENV === 'test' ? 50 : 5000);
|
|
128
|
+
cleanupStartTimeout = setTimeout(() => {
|
|
129
|
+
runCleanup();
|
|
130
|
+
}, delayMs);
|
|
131
|
+
if (cleanupStartTimeout && cleanupStartTimeout.unref) {
|
|
132
|
+
cleanupStartTimeout.unref();
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
cleanupInterval = setInterval(() => {
|
|
137
|
+
runCleanup();
|
|
138
|
+
}, retentionConfig.intervalMs);
|
|
139
|
+
if (cleanupInterval && cleanupInterval.unref) {
|
|
140
|
+
cleanupInterval.unref();
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function stopCleanup() {
|
|
145
|
+
if (cleanupStartTimeout) {
|
|
146
|
+
clearTimeout(cleanupStartTimeout);
|
|
147
|
+
cleanupStartTimeout = null;
|
|
148
|
+
}
|
|
149
|
+
if (cleanupInterval) {
|
|
150
|
+
clearInterval(cleanupInterval);
|
|
151
|
+
cleanupInterval = null;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
58
155
|
const registry = new TemplateRegistry();
|
|
59
156
|
|
|
60
157
|
const manifestChunks = emailTemplatesOpt
|
|
@@ -81,7 +178,7 @@ function emailPlugin(options = {}) {
|
|
|
81
178
|
return {
|
|
82
179
|
name: 'email',
|
|
83
180
|
version: '1.0.0',
|
|
84
|
-
description: 'MJML + Nodemailer email sending with optional admin UI and
|
|
181
|
+
description: 'MJML + Nodemailer email sending with optional admin UI, auth integration, and retention cleanup',
|
|
85
182
|
dependencies: includeAdminPage ? { 'admin-panel': '*' } : {},
|
|
86
183
|
|
|
87
184
|
api: {
|
|
@@ -92,13 +189,29 @@ function emailPlugin(options = {}) {
|
|
|
92
189
|
listTemplates: () => registry.list(),
|
|
93
190
|
verifyConnection: () => emailService.verifyConnection(),
|
|
94
191
|
queryLogs: (filters) => emailService.queryLogs(filters),
|
|
192
|
+
purge: (opts = {}) => {
|
|
193
|
+
if (!knex) throw new Error('Database is required for purge');
|
|
194
|
+
return purgeEmailLogs(knex, {
|
|
195
|
+
tableName: opts.tableName || tableName,
|
|
196
|
+
days: opts.days !== undefined ? opts.days : (opts.retentionDays !== undefined ? opts.retentionDays : retentionConfig.days),
|
|
197
|
+
olderThan: opts.olderThan,
|
|
198
|
+
...opts,
|
|
199
|
+
});
|
|
200
|
+
},
|
|
95
201
|
purgeLogs: (opts = {}) => {
|
|
96
202
|
if (!knex) throw new Error('Database is required for purgeLogs');
|
|
97
203
|
return purgeEmailLogs(knex, {
|
|
98
204
|
tableName: opts.tableName || tableName,
|
|
99
205
|
olderThan: opts.olderThan,
|
|
206
|
+
days: opts.days !== undefined ? opts.days : (opts.retentionDays !== undefined ? opts.retentionDays : retentionConfig.days),
|
|
207
|
+
...opts,
|
|
100
208
|
});
|
|
101
209
|
},
|
|
210
|
+
startCleanup,
|
|
211
|
+
stopCleanup,
|
|
212
|
+
getRetentionConfig() {
|
|
213
|
+
return { ...retentionConfig };
|
|
214
|
+
},
|
|
102
215
|
getMigrationTemplate: (name) => generateEmailLogsMigration(name || tableName),
|
|
103
216
|
isTransportReady: () => emailService.isTransportReady(),
|
|
104
217
|
loadFromManifest: (chunks) => registry.loadFromManifest(chunks),
|
|
@@ -120,6 +233,22 @@ function emailPlugin(options = {}) {
|
|
|
120
233
|
}
|
|
121
234
|
}
|
|
122
235
|
}
|
|
236
|
+
|
|
237
|
+
if (retentionConfig.enabled && autoCleanupEnabled) {
|
|
238
|
+
startCleanup();
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return () => {
|
|
242
|
+
stopCleanup();
|
|
243
|
+
};
|
|
244
|
+
},
|
|
245
|
+
|
|
246
|
+
dispose() {
|
|
247
|
+
stopCleanup();
|
|
248
|
+
},
|
|
249
|
+
|
|
250
|
+
shutdown() {
|
|
251
|
+
stopCleanup();
|
|
123
252
|
},
|
|
124
253
|
|
|
125
254
|
onRoutesReady(ctx) {
|
|
@@ -159,10 +288,11 @@ function emailPlugin(options = {}) {
|
|
|
159
288
|
|
|
160
289
|
adminApi.registerModule({
|
|
161
290
|
id: 'email',
|
|
291
|
+
title: pageTitle,
|
|
162
292
|
|
|
163
293
|
pages: [{
|
|
164
294
|
id: 'email',
|
|
165
|
-
title:
|
|
295
|
+
title: pageTitle,
|
|
166
296
|
path: '/email',
|
|
167
297
|
icon: 'mail',
|
|
168
298
|
component: generateEmailComponent({ apiPrefix }),
|
package/plugins/email/purge.js
CHANGED
|
@@ -3,24 +3,74 @@
|
|
|
3
3
|
* @module plugins/email/purge
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
6
8
|
/**
|
|
7
9
|
* @param {import('knex').Knex} knex
|
|
8
|
-
* @param {Object} options
|
|
10
|
+
* @param {Object} [options={}]
|
|
9
11
|
* @param {string} [options.tableName='email_logs']
|
|
10
|
-
* @param {Date|string} options.olderThan
|
|
11
|
-
* @
|
|
12
|
+
* @param {Date|string|number} [options.olderThan] - Rows with created_at strictly before this are removed
|
|
13
|
+
* @param {number} [options.days] - Number of days of email logs to keep
|
|
14
|
+
* @param {number} [options.retentionDays=90] - Alias for days
|
|
15
|
+
* @returns {Promise<number>} Deleted row count
|
|
12
16
|
*/
|
|
13
|
-
async function purgeEmailLogs(knex, options) {
|
|
17
|
+
async function purgeEmailLogs(knex, options = {}) {
|
|
18
|
+
if (!knex) {
|
|
19
|
+
throw new Error('purgeEmailLogs requires a database (knex) instance');
|
|
20
|
+
}
|
|
21
|
+
|
|
14
22
|
const tableName = options.tableName || 'email_logs';
|
|
15
|
-
const olderThan = options.olderThan instanceof Date
|
|
16
|
-
? options.olderThan
|
|
17
|
-
: new Date(options.olderThan);
|
|
18
23
|
|
|
19
|
-
|
|
20
|
-
|
|
24
|
+
let olderThan;
|
|
25
|
+
if (options.olderThan !== undefined) {
|
|
26
|
+
olderThan = options.olderThan instanceof Date
|
|
27
|
+
? options.olderThan
|
|
28
|
+
: new Date(options.olderThan);
|
|
29
|
+
|
|
30
|
+
if (Number.isNaN(olderThan.getTime())) {
|
|
31
|
+
throw new Error('purgeEmailLogs: invalid olderThan date');
|
|
32
|
+
}
|
|
33
|
+
} else {
|
|
34
|
+
const rawDays = options.days !== undefined ? options.days : (options.retentionDays !== undefined ? options.retentionDays : 90);
|
|
35
|
+
const days = typeof rawDays === 'number' ? rawDays : Number(rawDays);
|
|
36
|
+
if (Number.isNaN(days) || days <= 0) {
|
|
37
|
+
throw new Error('purgeEmailLogs: days must be a positive number');
|
|
38
|
+
}
|
|
39
|
+
olderThan = new Date(Date.now() - days * 24 * 60 * 60 * 1000);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
let hasTable = true;
|
|
43
|
+
if (knex.schema && typeof knex.schema.hasTable === 'function') {
|
|
44
|
+
try {
|
|
45
|
+
hasTable = await knex.schema.hasTable(tableName);
|
|
46
|
+
} catch {
|
|
47
|
+
hasTable = false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (!hasTable) {
|
|
52
|
+
return 0;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const client = knex?.client?.config?.client;
|
|
56
|
+
const isSqlite = client === 'sqlite3' || client === 'better-sqlite3';
|
|
57
|
+
|
|
58
|
+
let query = knex(tableName);
|
|
59
|
+
if (isSqlite) {
|
|
60
|
+
const iso = olderThan.toISOString();
|
|
61
|
+
const cutoffMs = olderThan.getTime();
|
|
62
|
+
query = query.where((builder) => {
|
|
63
|
+
builder.whereRaw(
|
|
64
|
+
"((typeof(created_at) = 'integer' and created_at < ?) or (typeof(created_at) = 'text' and created_at < ?))",
|
|
65
|
+
[cutoffMs, iso]
|
|
66
|
+
);
|
|
67
|
+
});
|
|
68
|
+
} else {
|
|
69
|
+
query = query.where('created_at', '<', olderThan);
|
|
21
70
|
}
|
|
22
71
|
|
|
23
|
-
|
|
72
|
+
const deleted = await query.delete();
|
|
73
|
+
return Number(deleted) || 0;
|
|
24
74
|
}
|
|
25
75
|
|
|
26
76
|
module.exports = {
|
|
@@ -569,30 +569,46 @@ function generateFileManagerComponent(options = {}) {
|
|
|
569
569
|
var onSelect = opts.onSelect;
|
|
570
570
|
var accept = opts.accept || '';
|
|
571
571
|
|
|
572
|
+
var existing = document.getElementById('file-manager-picker-modal-root');
|
|
573
|
+
if (existing && existing.parentNode) {
|
|
574
|
+
m.mount(existing, null);
|
|
575
|
+
existing.parentNode.removeChild(existing);
|
|
576
|
+
}
|
|
577
|
+
|
|
572
578
|
var modalContainer = document.createElement('div');
|
|
573
579
|
modalContainer.id = 'file-manager-picker-modal-root';
|
|
574
580
|
document.body.appendChild(modalContainer);
|
|
575
581
|
|
|
576
582
|
function cleanup() {
|
|
583
|
+
document.removeEventListener('keydown', onKeyDown);
|
|
577
584
|
if (modalContainer && modalContainer.parentNode) {
|
|
578
585
|
m.mount(modalContainer, null);
|
|
579
586
|
modalContainer.parentNode.removeChild(modalContainer);
|
|
580
587
|
}
|
|
581
588
|
}
|
|
582
589
|
|
|
590
|
+
function onKeyDown(e) {
|
|
591
|
+
if (e.key === 'Escape') cleanup();
|
|
592
|
+
}
|
|
593
|
+
document.addEventListener('keydown', onKeyDown);
|
|
594
|
+
|
|
583
595
|
var PickerModalComponent = {
|
|
584
596
|
view: function() {
|
|
585
|
-
return m('div.fixed.inset-0.bg-black/60.flex.items-center.justify-center.z-[9999].p-4.backdrop-blur-sm',
|
|
597
|
+
return m('div.fixed.inset-0.bg-black/60.flex.items-center.justify-center.z-[9999].p-4.backdrop-blur-sm', {
|
|
598
|
+
onclick: function(e) {
|
|
599
|
+
if (e.target === e.currentTarget) cleanup();
|
|
600
|
+
}
|
|
601
|
+
}, [
|
|
586
602
|
m('div.bg-white.dark:bg-slate-900.rounded-2xl.shadow-2xl.max-w-4xl.w-full.max-h-[90vh].flex.flex-col.overflow-hidden.border.border-gray-200.dark:border-slate-700', [
|
|
587
603
|
m('div.flex.items-center.justify-between.p-4.border-b.border-gray-200.dark:border-slate-700.bg-gray-50.dark:bg-slate-800', [
|
|
588
|
-
m('h2.text-base.font-bold.text-gray-900.dark:text-slate-100', opts.title || '
|
|
604
|
+
m('h2.text-base.font-bold.text-gray-900.dark:text-slate-100', opts.title || 'Choose from Media Library'),
|
|
589
605
|
m('button.text-gray-400.hover:text-gray-600.dark:hover:text-slate-200.text-xl', {
|
|
590
606
|
onclick: cleanup
|
|
591
607
|
}, '✕')
|
|
592
608
|
]),
|
|
593
609
|
m('div.p-4.overflow-y-auto.flex-1', [
|
|
594
|
-
m(FileManagerView(true, function(selectedUrl) {
|
|
595
|
-
if (onSelect) onSelect(selectedUrl);
|
|
610
|
+
m(FileManagerView(true, function(selectedUrl, item) {
|
|
611
|
+
if (onSelect) onSelect(selectedUrl, item);
|
|
596
612
|
cleanup();
|
|
597
613
|
}, accept))
|
|
598
614
|
])
|
|
@@ -92,6 +92,26 @@ function fileManagerPlugin(options = {}) {
|
|
|
92
92
|
return;
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
+
const componentCode = generateFileManagerComponent({
|
|
96
|
+
apiPrefix,
|
|
97
|
+
publicBasePath,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// Always configure fileManager in admin settings and register client component
|
|
101
|
+
// so window.__openFileManagerPicker is available across all admin pages (models, records, rich-text)
|
|
102
|
+
if (typeof adminApi.getRegistry === 'function') {
|
|
103
|
+
const registry = adminApi.getRegistry();
|
|
104
|
+
registry.configure({
|
|
105
|
+
fileManager: {
|
|
106
|
+
enabled: true,
|
|
107
|
+
apiPrefix,
|
|
108
|
+
publicBasePath,
|
|
109
|
+
pageTitle,
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
registry.registerClientComponent('files', componentCode);
|
|
113
|
+
}
|
|
114
|
+
|
|
95
115
|
adminApi.registerModule({
|
|
96
116
|
id: 'files',
|
|
97
117
|
pages: includePage
|
|
@@ -100,10 +120,7 @@ function fileManagerPlugin(options = {}) {
|
|
|
100
120
|
title: pageTitle,
|
|
101
121
|
path: '/files',
|
|
102
122
|
icon: 'folder',
|
|
103
|
-
component:
|
|
104
|
-
apiPrefix,
|
|
105
|
-
publicBasePath,
|
|
106
|
-
}),
|
|
123
|
+
component: componentCode,
|
|
107
124
|
}]
|
|
108
125
|
: [],
|
|
109
126
|
|
package/plugins/index.js
CHANGED
|
@@ -7,6 +7,8 @@ module.exports = {
|
|
|
7
7
|
get sitemapPlugin() { return require('./sitemap'); },
|
|
8
8
|
get analyticsPlugin() { return require('./analytics'); },
|
|
9
9
|
get dashboardPlugin() { return require('./dashboard/index'); },
|
|
10
|
+
get devToolbarPlugin() { return require('./dashboard/index').devToolbarPlugin; },
|
|
11
|
+
get devtoolsPlugin() { return require('./dashboard/index').devtoolsPlugin; },
|
|
10
12
|
get schemaExplorerPlugin() { return require('./schema-explorer'); },
|
|
11
13
|
get adminPanelPlugin() { return require('./admin-panel'); },
|
|
12
14
|
get seoCheckerPlugin() { return require('./seo-checker'); },
|
|
@@ -14,6 +16,8 @@ module.exports = {
|
|
|
14
16
|
get auditLogPlugin() { return require('./audit-log'); },
|
|
15
17
|
get recaptchaPlugin() { return require('./recaptcha'); },
|
|
16
18
|
get swaggerPlugin() { return require('./swagger'); },
|
|
19
|
+
get openapiPlugin() { return require('./swagger'); },
|
|
20
|
+
get apiDocsPlugin() { return require('./swagger'); },
|
|
17
21
|
get healthCheckPlugin() { return require('./health-check'); },
|
|
18
22
|
get restResourcePlugin() { return require('./rest-resources'); },
|
|
19
23
|
get ormCacheAdminPlugin() { return require('./orm-cache-admin'); },
|
|
@@ -49,6 +53,12 @@ module.exports = {
|
|
|
49
53
|
get xlsx() { return require('./xlsx').xlsx; },
|
|
50
54
|
get csvPlugin() { return require('./csv').csvPlugin; },
|
|
51
55
|
get csv() { return require('./csv').csv; },
|
|
56
|
+
get oauthPlugin() { return require('./oauth'); },
|
|
57
|
+
get OAuthClient() { return require('./oauth').OAuthClient; },
|
|
58
|
+
get OAuthError() { return require('./oauth').OAuthError; },
|
|
59
|
+
get createOAuthClient() { return require('./oauth').createOAuthClient; },
|
|
60
|
+
get apiKeyPlugin() { return require('./api-key').apiKeyPlugin; },
|
|
61
|
+
get createApiKeyMiddleware() { return require('./api-key').createApiKeyMiddleware; },
|
|
52
62
|
};
|
|
53
63
|
|
|
54
64
|
|