domma-cms 1.10.32 → 1.10.33
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 +4 -0
- package/package.json +1 -1
- package/server/services/hooks.js +13 -6
- package/server/services/sidebar-migration.js +33 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.10.33] - 2026-10-26
|
|
4
|
+
|
|
5
|
+
- Group newer Tools into purpose-based submenus, including business, marketing, publishing, maintenance and games. Upgrade saved loose entries once while preserving labels, visibility, permissions and custom submenus.
|
|
6
|
+
|
|
3
7
|
## [1.10.32] - 2026-10-26
|
|
4
8
|
|
|
5
9
|
- Add clickable (?) explanations throughout the Forms editor, including submission actions, triggers, conditions, field options and chooser controls. Newly added controls receive help immediately; help buttons preserve checkbox and panel state.
|
package/package.json
CHANGED
package/server/services/hooks.js
CHANGED
|
@@ -98,14 +98,21 @@ const _registeredSidebarItems = [];
|
|
|
98
98
|
* Unknown plugins remain directly in Tools until they declare their own group.
|
|
99
99
|
*/
|
|
100
100
|
const TOOL_GROUPS = new Map(Object.entries({
|
|
101
|
-
Productivity: ['#/notes', '#/todo', '#/calculator', '#/plugins/calendar', '#/plugins/waypoint-pro'],
|
|
101
|
+
Productivity: ['#/notes', '#/todo', '#/calculator', '#/plugins/calendar', '#/plugins/waypoint-pro', '#/plugins/sheets'],
|
|
102
102
|
Communication: ['#/contacts', '#/plugins/contacts-pro', '#/plugins/mail-reader', '#/plugins/email-pro', '#/plugins/messages'],
|
|
103
|
-
Marketing: ['#/analytics', '#/seo', '#/plugins/analytics-pro/dashboard', '#/plugins/social', '#/plugins/feedback', '#/plugins/surveys'],
|
|
104
|
-
Publishing: ['#/plugins/blog', '#/plugins/blog-pro', '#/plugins/docs', '#/plugins/theme-roller'],
|
|
105
|
-
Business: ['#/plugins/shopping-cart', '#/plugins/booking', '#/plugins/invoice', '#/job-board', '#/plugins/garage'],
|
|
106
|
-
Maintenance: ['#/plugins/security', '#/plugins/security-pro', '#/plugins/security-pro/my-2fa', '#/plugins/backup-pro', '#/plugins/data-transfer', '#/wordpress-import']
|
|
103
|
+
Marketing: ['#/analytics', '#/seo', '#/plugins/analytics-pro/dashboard', '#/plugins/social', '#/plugins/feedback', '#/plugins/surveys', '#/plugins/campaigns-pro', '#/plugins/ecards'],
|
|
104
|
+
Publishing: ['#/plugins/blog', '#/plugins/blog-pro', '#/plugins/docs', '#/plugins/theme-roller', '#/plugins/wiki', '#/plugins/wiki-pro', '#/plugins/scraper', '#/plugins/scraper-pro'],
|
|
105
|
+
Business: ['#/plugins/shopping-cart', '#/plugins/booking', '#/plugins/booking-pro', '#/plugins/invoice', '#/job-board', '#/plugins/garage', '#/plugins/takeaway', '#/plugins/support', '#/plugins/onboard-pro'],
|
|
106
|
+
Maintenance: ['#/plugins/security', '#/plugins/security-pro', '#/plugins/security-pro/my-2fa', '#/plugins/backup-pro', '#/plugins/data-transfer', '#/wordpress-import', '#/plugins/site-manager/backups'],
|
|
107
|
+
Manage: ['#/plugins/site-manager/dashboard', '#/plugins/site-manager/server', '#/plugins/site-manager/injector-library'],
|
|
108
|
+
Games: ['#/plugins/crossword', '#/plugins/daily-word', '#/plugins/quiz', '#/plugins/word-search']
|
|
107
109
|
}).flatMap(([group, urls]) => urls.map(url => [url, group])));
|
|
108
110
|
|
|
111
|
+
/** Default category for a known Tool URL, also used when upgrading saved menus. */
|
|
112
|
+
export function defaultToolGroup(url) {
|
|
113
|
+
return TOOL_GROUPS.get(url);
|
|
114
|
+
}
|
|
115
|
+
|
|
109
116
|
/**
|
|
110
117
|
* Register a Tool's sidebar entry. Entries are placed into the rendered admin
|
|
111
118
|
* sidebar at render time - they are NOT persisted into menu JSON - so plugins
|
|
@@ -130,7 +137,7 @@ export function registerSidebarItem(opts) {
|
|
|
130
137
|
}
|
|
131
138
|
const {folder: itemFolder, group: itemGroup, ...item} = opts.item;
|
|
132
139
|
const folder = opts.folder || itemFolder || DEFAULT_TOOL_FOLDER;
|
|
133
|
-
const defaultGroup = folder === DEFAULT_TOOL_FOLDER && !opts.parent ?
|
|
140
|
+
const defaultGroup = folder === DEFAULT_TOOL_FOLDER && !opts.parent ? defaultToolGroup(item.url) : undefined;
|
|
134
141
|
const group = [opts.group, itemGroup, defaultGroup].find(g => typeof g === 'string' && g.trim());
|
|
135
142
|
_registeredSidebarItems.push({
|
|
136
143
|
parent: opts.parent || null,
|
|
@@ -15,6 +15,7 @@ import fs from 'fs/promises';
|
|
|
15
15
|
import path from 'path';
|
|
16
16
|
import {fileURLToPath} from 'url';
|
|
17
17
|
import {invalidateMenuIndex} from './menus.js';
|
|
18
|
+
import {defaultToolGroup} from './hooks.js';
|
|
18
19
|
|
|
19
20
|
const __filename = fileURLToPath(import.meta.url);
|
|
20
21
|
const DEFAULT_CONFIG_DIR = path.resolve(path.dirname(__filename), '..', '..', 'config');
|
|
@@ -482,6 +483,38 @@ export async function ensureFolderKeys(opts = {}) {
|
|
|
482
483
|
changed = true;
|
|
483
484
|
}
|
|
484
485
|
|
|
486
|
+
// Categorise only loose, known Tools once. Custom submenus and entries
|
|
487
|
+
// outside Tools keep their placement; later admin rearrangements win.
|
|
488
|
+
if (!menu.meta?.purposeToolGroups && items.length) {
|
|
489
|
+
const find = (nodes, test) => {
|
|
490
|
+
for (const node of nodes || []) {
|
|
491
|
+
if (test(node)) return node;
|
|
492
|
+
const nested = find(node?.items, test);
|
|
493
|
+
if (nested) return nested;
|
|
494
|
+
}
|
|
495
|
+
return null;
|
|
496
|
+
};
|
|
497
|
+
const tools = find(items, n => isFolder(n) && n.key === 'tools');
|
|
498
|
+
if (tools && Array.isArray(tools.items)) {
|
|
499
|
+
const loose = tools.items.filter(n => n?.url && defaultToolGroup(n.url));
|
|
500
|
+
for (const node of loose) {
|
|
501
|
+
const name = defaultToolGroup(node.url);
|
|
502
|
+
const key = `tools.${name.toLowerCase()}`;
|
|
503
|
+
let group = find(items, n => isFolder(n) && n.key === key)
|
|
504
|
+
|| tools.items.find(n => isFolder(n) && !n.key && String(n.text).toLowerCase() === name.toLowerCase());
|
|
505
|
+
if (!group) {
|
|
506
|
+
group = {text: name, key, icon: 'folder', items: []};
|
|
507
|
+
tools.items.push(group);
|
|
508
|
+
}
|
|
509
|
+
tools.items = tools.items.filter(n => n !== node);
|
|
510
|
+
if (!Array.isArray(group.items)) group.items = [];
|
|
511
|
+
group.items.push(node);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
menu.meta = {...(menu.meta || {}), purposeToolGroups: true};
|
|
515
|
+
changed = true;
|
|
516
|
+
}
|
|
517
|
+
|
|
485
518
|
if (!changed) return {updated: false, reason: 'already up to date'};
|
|
486
519
|
|
|
487
520
|
menu.meta = {...(menu.meta || {}), updatedAt: new Date().toISOString()};
|