Skip to content

Commit 4ab3161

Browse files
committed
Add permanent delete to Admin Panel Problems.
The Delete pane sits above Notifications and exposes the existing, default-off enablePermanentDelete gate for Global Admins. It has its own URL, documentation, and regression coverage for menu order, rendering and the setting handler. Thanks to xet7 !
1 parent a9a6e62 commit 4ab3161

7 files changed

Lines changed: 50 additions & 14 deletions

File tree

client/components/settings/adminProblems.jade

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ template(name="adminProblems")
1818
+featuresPerformance
1919
else if isPane 'features-security'
2020
+featuresSecurity
21+
else if isPane 'features-delete'
22+
+featuresDelete
2123
else if isPane 'features-notifications'
2224
+featuresNotifications
2325
else if isPane 'report-security'
@@ -115,6 +117,15 @@ template(name="featuresSecurity")
115117
span {{_ 'anonymize-export-users'}}
116118
p.description {{_ 'anonymize-export-users-description'}}
117119

120+
//- Admin Panel / Problems / Delete.
121+
template(name="featuresDelete")
122+
ul.setting-detail
123+
li
124+
a.flex.js-toggle-enable-permanent-delete
125+
.materialCheckBox(class="{{#if enablePermanentDelete}}is-checked{{/if}}")
126+
span {{_ 'enable-permanent-delete'}}
127+
p.description {{_ 'enable-permanent-delete-description'}}
128+
118129
//- Admin Panel / Problems / Notifications.
119130
template(name="featuresNotifications")
120131
ul.setting-detail

client/components/settings/adminProblems.js

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ const PROBLEMS_MENU = [
286286
// sits with the reports below, beside the Speed / Tests / CPU usage streams it is
287287
// about.
288288
{ id: 'features-security', icon: 'fa-shield', labelKey: 'features-security', emoji: true },
289+
{ id: 'features-delete', icon: 'fa-trash', labelKey: 'delete' },
289290
{ id: 'features-notifications', icon: 'fa-bell', labelKey: 'features-notifications', emoji: true },
290291
{ separator: true },
291292
{ heading: true, labelKey: 'reports' },
@@ -473,7 +474,7 @@ function switchMenu(event, tmpl) {
473474
// nothing to fetch. Everything else falls through to loadReport().
474475
const SELF_LOADING_PANES = [
475476
'report-summary',
476-
'features-performance', 'features-security', 'features-notifications',
477+
'features-performance', 'features-security', 'features-delete', 'features-notifications',
477478
'report-security', 'report-speed', 'report-tests', 'report-cpu',
478479
'report-database', 'report-integrity', 'report-office', 'report-api',
479480
];
@@ -950,8 +951,9 @@ function toggleSettingField(field) {
950951
}
951952
}
952953

953-
// Performance, Security and Notifications - the three panes that were Admin Panel /
954-
// Features before it was removed. Blaze resolves a helper, and delivers an event,
954+
// Performance, Security and Notifications were Admin Panel / Features panes before
955+
// it was removed; Delete exposes the later soft-delete gate beside them. Blaze
956+
// resolves a helper, and delivers an event,
955957
// against the template the element is IN - never an enclosing one - so each pane needs
956958
// these ON it. One shared pair registered on all three: a handler whose element is not
957959
// in a given pane simply never fires there, so splitting them per pane would buy
@@ -990,6 +992,9 @@ const featurePaneHelpers = {
990992
disableWatch() {
991993
return (ReactiveCache.getCurrentSetting() || {}).disableWatch;
992994
},
995+
enablePermanentDelete() {
996+
return (ReactiveCache.getCurrentSetting() || {}).enablePermanentDelete;
997+
},
993998
};
994999
const featurePaneEvents = {
9951000
'click .js-toggle-render-links-as-plain-text'() {
@@ -1025,9 +1030,12 @@ const featurePaneEvents = {
10251030
'click .js-toggle-disable-watch'() {
10261031
toggleSettingField('disableWatch');
10271032
},
1033+
'click .js-toggle-enable-permanent-delete'() {
1034+
toggleSettingField('enablePermanentDelete');
1035+
},
10281036
};
10291037
for (const tpl of [Template.featuresPerformance, Template.featuresSecurity,
1030-
Template.featuresNotifications]) {
1038+
Template.featuresDelete, Template.featuresNotifications]) {
10311039
tpl.helpers(featurePaneHelpers);
10321040
tpl.events(featurePaneEvents);
10331041
}

docs/Features/Admin-Panel/Problems/README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,15 @@ Below that is the acknowledge list of the Security / Speed / Tests problem strea
2929

3030
## The menu, in two named groups
3131

32-
**Settings** — the two panes that came from the removed Features tab, which are
32+
**Settings** — the panes that hold server-wide feature switches, which are
3333
settings rather than reports but are what an admin reaches for when something is
3434
unsafe or noisy:
3535

3636
- **Security** — how rich text is rendered (links as plain text, all code as plain
3737
text) and the import / export privacy switches (disable all import / export,
3838
avatars, anonymize users). All enforced server-side.
39+
- **Delete** — allow Global Admins to permanently purge soft-deleted content.
40+
The switch is off by default and enabling it deletes nothing by itself.
3941
- **Notifications** — disable all activities, all notifications, or watching, for
4042
deployments that must limit activity tracking
4143
([#5820](https://github.com/wekan/wekan/issues/5820)).
@@ -93,6 +95,7 @@ the address uses: `/admin/problems/<slug>`.
9395
| --- | --- | --- |
9496
| Problems / Summary | `summary` ||
9597
| Problems / Security | `security` ||
98+
| Problems / Delete | `delete` ||
9699
| Problems / Notifications | `notifications` ||
97100
| Problems / Security Report | `security-report` ||
98101
| Problems / Impersonation Report | `impersonation` ||
@@ -111,6 +114,6 @@ the address uses: `/admin/problems/<slug>`.
111114
| Problems / Database problems | `database` ||
112115
| Problems / Filesystem integrity | `integrity` ||
113116

114-
16 of these 19 panes has no page of its own yet. A dash is a
117+
17 of these 20 panes has no page of its own yet. A dash is a
115118
gap to fill, not a pane that does nothing - what the pane shows is described in
116119
this README until somebody writes it up.

docs/Features/Page/Admin-Panel-URLs.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ The bare `/admin/settings` still resolves; it *redirects* to
6363
| --- | --- | --- |
6464
| `/admin/problems/summary` | Summary | `report-summary` |
6565
| `/admin/problems/security` | Security | `features-security` |
66+
| `/admin/problems/delete` | Delete | `features-delete` |
6667
| `/admin/problems/notifications` | Notifications | `features-notifications` |
6768
| `/admin/problems/security-report` | Security Report | `report-security` |
6869
| `/admin/problems/impersonation` | Impersonation Report | `report-impersonation` |

imports/i18n/data/en.i18n.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,8 @@
523523
"decline": "Decline",
524524
"default-avatar": "Default avatar",
525525
"delete": "Delete",
526+
"enable-permanent-delete": "Enable permanent delete for Global Admin",
527+
"enable-permanent-delete-description": "Allow Global Admins to permanently delete soft-deleted content. Enabling this setting does not delete anything by itself.",
526528
"deleteCustomFieldPopup-title": "Delete Custom Field?",
527529
"deleteLabelPopup-title": "Delete Label?",
528530
"description": "Description",

models/lib/adminUrls.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ const ADMIN_PAGES = {
9595
panes: {
9696
summary: 'report-summary',
9797
security: 'features-security',
98+
delete: 'features-delete',
9899
notifications: 'features-notifications',
99100
'security-report': 'report-security',
100101
impersonation: 'report-impersonation',
@@ -173,6 +174,7 @@ const ADMIN_PANE_TITLES = {
173174
problems: {
174175
summary: { titleKey: 'summary' },
175176
security: { titleKey: 'features-security' },
177+
delete: { titleKey: 'delete' },
176178
notifications: { titleKey: 'features-notifications' },
177179
'security-report': { titleKey: 'securityReportTitle' },
178180
impersonation: { titleKey: 'impersonationReportTitle' },

tests/problemsMenuOrder.test.cjs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
'use strict';
22

3-
// Admin Panel / Problems: the menu order, the Security Report rename, and the three
4-
// panes that moved here from Admin Panel / Features.
3+
// Admin Panel / Problems: the menu order, the Security Report rename, the three
4+
// panes that moved here from Admin Panel / Features, and the Delete setting added
5+
// after that page was removed.
56
//
67
// Requested:
78
// * "Security" renamed to "Security Report" and moved ABOVE "Broken Cards"
@@ -71,9 +72,9 @@ test('the report is called Security Report, in the source string', () => {
7172
});
7273

7374
test('the menu is two named groups: Settings, then Reports', () => {
74-
// Summary, then a rule and a "Settings" title over the two panes that came from
75-
// Admin Panel / Features, then a rule and a "Reports" title over everything else.
76-
for (const id of ['features-security', 'features-notifications']) {
75+
// Summary, then a rule and a "Settings" title over the server-wide switches,
76+
// then a rule and a "Reports" title over everything else.
77+
for (const id of ['features-security', 'features-delete', 'features-notifications']) {
7778
assert.ok(at(id) > -1, `${id} must be a Problems entry`);
7879
assert.ok(at(id) > at('report-summary'), `${id} must be below Summary`);
7980
}
@@ -83,6 +84,10 @@ test('the menu is two named groups: Settings, then Reports', () => {
8384
'the Settings title comes after Summary');
8485
assert.ok(headingAt('settings') < at('features-security'),
8586
'and above the settings panes it names');
87+
assert.ok(at('features-security') < at('features-delete'),
88+
'Delete is below Security');
89+
assert.ok(at('features-delete') < at('features-notifications'),
90+
'Delete is immediately above Notifications');
8691
assert.ok(at('features-notifications') < headingAt('reports'),
8792
'the Reports title comes after them');
8893
assert.ok(headingAt('reports') < at('report-security'),
@@ -146,13 +151,17 @@ test('no pane keeps its own ReactiveVar any more (negative)', () => {
146151
});
147152

148153

149-
test('each pane took its helpers and handlers with it', () => {
154+
test('each settings pane has its helpers and handlers', () => {
150155
// The half that fails silently: the pane renders, every checkbox reads as unchecked
151156
// and no click does anything.
152157
assert.ok(/const featurePaneHelpers = \{/.test(featuresJs), 'the pane helpers are their own object');
153158
assert.ok(/const featurePaneEvents = \{/.test(featuresJs), 'and so are the handlers');
154-
assert.ok(/for \(const tpl of \[Template\.featuresPerformance, Template\.featuresSecurity,[\s\S]{0,80}tpl\.helpers\(featurePaneHelpers\);[\s\S]{0,40}tpl\.events\(featurePaneEvents\);/
155-
.test(featuresJs), 'registered on all three pane templates');
159+
assert.ok(/for \(const tpl of \[Template\.featuresPerformance, Template\.featuresSecurity,[\s\S]{0,140}tpl\.helpers\(featurePaneHelpers\);[\s\S]{0,40}tpl\.events\(featurePaneEvents\);/
160+
.test(featuresJs), 'registered on every settings pane template');
161+
assert.ok(featuresJs.includes("toggleSettingField('enablePermanentDelete')"),
162+
'the Delete checkbox writes the permanent-delete setting');
163+
assert.ok(/Template\.featuresDelete/.test(featuresJs),
164+
'the Delete pane receives the shared helpers and handlers');
156165
// They must NOT be left on the page template.
157166
// There is no page template left to leave them on: the pane templates are the only
158167
// place they can be.

0 commit comments

Comments
 (0)