Files
wekan/models/lib/problemsOverview.js
T
Lauri Ojansivu 5a1c9a61e9 Admin Panel / Problems "Status" overview + snap run wekan.problems: show migrations/repairs in progress and login-page "Must be logged in" causes; run repairs server-side.
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 !
2026-07-22 16:22:39 +03:00

60 lines
1.9 KiB
JavaScript

'use strict';
// Pure builder for the Admin Panel / Problems "Status" overview and the
// `snap run wekan.problems` overview: given a snapshot of what is in progress and
// what problems were detected, it returns a single normalized overview object.
// Pure + unit-testable; the server (server/lib/systemStatus.js) and the snap
// command both gather the snapshot and render this same shape.
//
// input = {
// inProgress: [{ kind, active, message }], // migrations / repairs running
// brokenCards: <number>, // broken/orphaned cards count
// loginProblems: [{ id, title, detail, severity, ok }],
// extraProblems: [{ id, severity, title, detail, count? }], // optional
// }
function buildProblemsOverview(input) {
const i = input || {};
const inProgress = (Array.isArray(i.inProgress) ? i.inProgress : [])
.filter(x => x && x.active);
const problems = [];
const brokenCards = Number.isFinite(i.brokenCards) ? i.brokenCards : 0;
if (brokenCards > 0) {
problems.push({
id: 'broken-cards',
severity: 'warning',
count: brokenCards,
title: 'Broken cards',
detail: `${brokenCards} card(s) with a missing board/list/swimlane or an invalid type. Open the board to auto-repair, or run the repair migration.`,
});
}
// Login-page causes that currently look wrong (ok === false).
for (const c of Array.isArray(i.loginProblems) ? i.loginProblems : []) {
if (c && c.ok === false) {
problems.push({
id: c.id,
severity: c.severity || 'warning',
title: c.title,
detail: c.detail,
});
}
}
for (const p of Array.isArray(i.extraProblems) ? i.extraProblems : []) {
if (p) problems.push(p);
}
return {
anyInProgress: inProgress.length > 0,
inProgress,
anyProblems: problems.length > 0,
problems,
};
}
module.exports = { buildProblemsOverview };