mirror of
https://github.com/wekan/wekan.git
synced 2026-11-08 03:22:32 -05:00
Motivated by the 10.16-10.21 reports where, after an upgrade, the login page showed "Must be logged in" or sat on the logo + "Loading, please wait." spinner, pages took 5+ minutes, All Boards counts stayed 0 and i18n showed raw keys — the FerretDB v1 (SQLite) process pegged ~2 cores for a long time under WeKan's poll load, i.e. a migration/repair or a saturated backend, with no way to see it without the Admin Panel. Server-side, independent of any client / progress page: - server/startup/repairBoardsOnStartup.js runs the shared board data-repairs once (version-gated, background, 30s after boot) so corrupted data is fixed even if no user opens a board and nobody watches a progress page. - The MongoDB <-> SQLite text migration and the startup repair now PERSIST their progress to the text_migration_status collection (models/textMigrationStatus.js), so a separate process can see "a migration/repair is in progress" (an in-memory object could not). Status overview (server/lib/systemStatus.js), shown in Admin Panel / Problems -> Summary and via the method systemStatusReport (admin-gated, server/methods/ systemStatus.js): - everything in progress (text migration, board repair, recovery, cron migration, attachment migration) aggregated from the persisted status collections; - detected problems (broken cards; failing login-page checks); - login-page "Must be logged in" / "Loading, please wait" cause checklist (migration in progress, ROOT_URL, LDAP, Sandstorm) — models/lib/loginProblems.js; - a CPU detail area that calls out a pegged ferretdb process and the mitigation. Snap: `snap run wekan.problems` (snap-src/bin/wekan-problems[.mjs], snapcraft app `problems`) prints the same overview as text — problems, migrations/repairs in progress, login checks — so an admin with only server access can see it WITHOUT Admin Panel access. Sub-commands: migrations | login | broken-cards | cpu | help. Pure helpers models/lib/loginProblems.js and models/lib/problemsOverview.js are unit-tested; tests/problemsStatus.test.cjs (14 checks) also source-guards the server hub, method, startup pass, migration persistence and snap command. Thanks to xet7 !
72 lines
2.4 KiB
JavaScript
72 lines
2.4 KiB
JavaScript
import { TAPi18n } from '/imports/i18n';
|
|
|
|
// Admin Panel → Problems → Summary page: a checkbox list of problem areas
|
|
// (Security / Speed / Tests) with each area's menu path and its count of NEW
|
|
// (unacknowledged) problems, plus ONE Acknowledge button that acknowledges every
|
|
// checked area. This is the ONLY place problems are acknowledged — the Security /
|
|
// Speed / Tests detail pages are read-only.
|
|
// Design: docs/Security/Remediation/WeKan.md. Data: the admin-only
|
|
// eventLogProblemAreas / acknowledgeEventLog methods (models/eventLog.js).
|
|
|
|
const STREAM_LABEL_KEY = {
|
|
security: 'securityReportTitle',
|
|
speed: 'speedReportTitle',
|
|
tests: 'testsReportTitle',
|
|
};
|
|
|
|
Template.problemsSummary.onCreated(function () {
|
|
this.areas = new ReactiveVar([]);
|
|
// Status overview: everything in progress (migrations / repairs) + detected
|
|
// problems (broken cards, login-page "Must be logged in" causes). Same data as
|
|
// `snap run wekan.problems`.
|
|
this.status = new ReactiveVar(null);
|
|
this.reload = () => {
|
|
Meteor.call('eventLogProblemAreas', (err, res) => {
|
|
if (!err) this.areas.set(Array.isArray(res) ? res : []);
|
|
});
|
|
Meteor.call('systemStatusReport', (err, res) => {
|
|
if (!err) this.status.set(res || null);
|
|
});
|
|
};
|
|
this.reload();
|
|
this.timer = Meteor.setInterval(this.reload, 30000);
|
|
});
|
|
|
|
Template.problemsSummary.onDestroyed(function () {
|
|
if (this.timer) Meteor.clearInterval(this.timer);
|
|
});
|
|
|
|
Template.problemsSummary.helpers({
|
|
areas() {
|
|
return Template.instance().areas.get();
|
|
},
|
|
hasProblems() {
|
|
return (Template.instance().areas.get() || []).length > 0;
|
|
},
|
|
areaLabel(stream) {
|
|
return TAPi18n.__(STREAM_LABEL_KEY[stream] || stream);
|
|
},
|
|
statusOverview() {
|
|
const s = Template.instance().status.get();
|
|
return s && s.overview ? s.overview : null;
|
|
},
|
|
inProgress() {
|
|
const s = Template.instance().status.get();
|
|
return s && s.overview ? s.overview.inProgress : [];
|
|
},
|
|
statusProblems() {
|
|
const s = Template.instance().status.get();
|
|
return s && s.overview ? s.overview.problems : [];
|
|
},
|
|
});
|
|
|
|
Template.problemsSummary.events({
|
|
'click .js-ack-checked'(event, templateInstance) {
|
|
const streams = Array.from(templateInstance.findAll('.js-problem-check:checked'))
|
|
.map(el => el.getAttribute('data-stream'))
|
|
.filter(Boolean);
|
|
if (!streams.length) return;
|
|
Meteor.call('acknowledgeEventLog', streams, () => templateInstance.reload());
|
|
},
|
|
});
|