Skip to content

fix: mount CnDashboardPage, restore info.xml validity, document the throttler - #57

Merged
rubenvdlinde merged 7 commits into
developmentfrom
fix/dashboard-and-info-xml
Aug 21, 2026
Merged

fix: mount CnDashboardPage, restore info.xml validity, document the throttler#57
rubenvdlinde merged 7 commits into
developmentfrom
fix/dashboard-and-info-xml

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

Clears three pre-existing failures on development plus the gate-69 finding. petstore is the app the fleet copies from, so debt here propagates by being imitated.

Supersedes #56 (carries its field-lock and phpcs fix).

1. info.xml element order — info.xml lint, exit 3

app-info.xsd declares both <info> and <dependencies> as sequences, and this file violated both:

schema sequence was
dependencies php · database · command · lib · owncloud · nextcloud · … <php> after <nextcloud>
info … dependencies · background-jobs · repair-steps · … · settings · … · navigations <navigations> before <repair-steps>/<settings>

Every element was valid; only the order was not — which is why the error reads "Element 'php': This element is not expected. Expected is one of ( architecture, backend )". hrmq's info.xml carries a comment about the identical defect. Order taken from the schema itself and the result checked monotonic against it.

2. Dashboard bypassed its own page component — gate-69 rule (a)

8 widgets sat in a page-level widgets[], so CnPageRenderer rendered a bare CnWidgetGrid instead of CnDashboardPage. Moved to config.widgets + config.layout, coordinates unchanged.

The nc-vue bump (2.3.0 → 2.9.1) is required for this, not cosmetic. Two of the four widget types resolve only from BUILT_IN_WIDGETS, which CnDashboardPage did not consult before ConductionNL/nextcloud-vue#713:

widget resolves from
chart-by-field layer 1 — petstore's own registry.js
stats-block layer 2 — dashboard registry
header layer 3 — BUILT_IN_WIDGETS
object-table layer 3 — BUILT_IN_WIDGETS

Converting on 2.3.0 would have left header and object-table rendering nothing, on a page that looks correct in the manifest.

3. phpcs — 2 errors → 0

PortalActionController::__construct documented four parameters for five (IThrottler $throttler missing, which also pushed $logger out of alignment).

Verification

  • structural check: all 8 widgets keep type, title, content and all four grid coordinates; no other page changed
  • check:manifest Ajv PASS (0 errors)
  • gate-69 findings: 0
  • build succeeds

Not fixed here

npm audit reports 9 findings, all transitive, none introduced by this branch. The cyclonedx high is already covered by #6; the dompurify chain arrives through @toast-ui/editor inside nc-vue itself and needs an upstream fix.

…hrottler

Three pre-existing failures on `development`, plus the gate-69 finding, in the
app the fleet copies from — petstore is the reference implementation, so debt
here propagates by being imitated.

1. info.xml element ORDER (info.xml lint, exit 3)

   app-info.xsd declares both `<info>` and `<dependencies>` as SEQUENCEs, and
   this file violated both:

     dependencies: php database command lib owncloud nextcloud architecture backend
       -> <php> sat AFTER <nextcloud>
     info:  ... dependencies background-jobs repair-steps ... settings ... navigations
       -> <navigations> sat BEFORE <repair-steps> and <settings>

   Every element was valid; only the order was not, which is why the message
   reads "Element 'php': This element is not expected. Expected is one of
   ( architecture, backend )". hrmq's info.xml carries a comment about the
   identical defect. Order taken from the schema itself, not guessed, and the
   result checked to be monotonic against that sequence.

2. Dashboard bypassed its own page component (gate-69 rule (a))

   The `type: "dashboard"` page carried 8 widgets in a page-level `widgets[]`,
   so CnPageRenderer rendered a bare CnWidgetGrid INSTEAD of CnDashboardPage
   and the page never got its chrome. Moved to config.widgets + config.layout,
   coordinates unchanged.

   The nc-vue bump (2.3.0 -> 2.9.1) is REQUIRED for this, not cosmetic. Two of
   the four widget types resolve only from BUILT_IN_WIDGETS, which
   CnDashboardPage did not consult before nextcloud-vue#713:

     chart-by-field -> layer1: petstore's own registry.js
     stats-block    -> layer2: dashboard registry
     header         -> layer3: BUILT_IN_WIDGETS
     object-table   -> layer3: BUILT_IN_WIDGETS

   Converting on 2.3.0 would have left `header` and `object-table` rendering
   nothing, on a page that looks correct in the manifest.

3. phpcs: PortalActionController::__construct documented four parameters for
   five — `IThrottler $throttler` missing, which also pushed `$logger` out of
   alignment. 2 errors, now 0.

Also carries the process/audit field lock from #56, which this supersedes.

Verified: structural check asserts all 8 widgets kept type, title, content and
grid coordinates and that no other page changed; check:manifest Ajv PASS;
gate-69 findings 0; build succeeds.

Not fixed here: `npm audit` reports 9 findings, all transitive and none
introduced by this branch — the cyclonedx high is already covered by #6, and
the dompurify chain comes through @toast-ui/editor inside nc-vue itself and
needs fixing upstream.
@rubenvdlinde

Copy link
Copy Markdown
Contributor Author

Correction: the nc-vue bump was NOT required for this conversion

I claimed header and object-table resolve only from BUILT_IN_WIDGETS, which CnDashboardPage did not consult before 2.9.1, and that converting on 2.3.0 would have rendered nothing. That is wrong.

I derived it by grepping registerDashboardWidgets.js, which lists only a handful of keys. It misses the real mechanism: 28 widget components self-register their key at module load, each from its own index.js:

// CnStatWidget/index.js
registerDashboardWidget('stat', { renderer: __sfc_main, ... })

CnHeaderWidgetheader and CnWidgetObjectTableobject-table are both in that set, so both resolve from the dashboard registry — which CnDashboardPage consults at 2.3.0 too.

Verified in the browser rather than by grep: pipelinq runs nc-vue 2.3.0, declares stat in config.widgets, registers it nowhere itself, and its dashboard renders cn-stat-widget tiles with live values ("Weighted Forecast €559,220").

What this changes: the bump here is a good idea on its own (2.3.0 → 2.9.1 is 6 minors of fixes, and it is what the fleet is standardising on) but it is not a precondition for the conversion, and the PR body should not have said it was. The conversion, the info.xml ordering fix and the phpcs fix are all unaffected.

Same check applied to the sibling PRs: scholiq#541's bump is genuinely required — nav-card-grid is one of the keys that does not self-register and lives only in BUILT_IN_WIDGETS.

@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/petstore @ c2e95a6

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
test-unit
check-specs
check-manifest
composer ✅ 100/100
npm ✅ 761/761
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-21 07:57 UTC

Download the full PDF report from the workflow artifacts.

The third ordering defect in this file, and the reason it did not show up in
the previous commit: xmllint reports only the FIRST violation, so each fix
merely reveals the next one on the following CI run.

    appinfo/info.xml:39: element post-migration: Schemas validity error :
    Element 'post-migration': This element is not expected. Expected is ( uninstall ).

info.xsd declares repair-steps as the sequence

    pre-migration post-migration live-migration install uninstall

and this file had `install` before `post-migration`. Both steps run the same
two repair classes, so nothing about behaviour changes — only the order the
schema demands.

Checked the whole tree in one pass this time rather than one CI round per
defect. Against the file as it stands on `development` that reports all three
at once:

    <info>:         navigations before repair-steps/settings
    <dependencies>: nextcloud before php
    <repair-steps>: install before post-migration

and against this file: all element sequences in order. The checker is shown to
FAIL on the unfixed input before being trusted.
…dit findings

`npm audit fix` could not run at all here: it aborted on a PRE-EXISTING peer
conflict that has nothing to do with any advisory —

    Found: sass-loader@16.0.8
    Could not resolve dependency:
    peer sass-loader@"^17.0.0" from @nextcloud/webpack-vue-config@7.0.4

so every finding it could have fixed stayed unfixed, and the Security job kept
failing for a reason the log never named. hrmq, scholiq and pipelinq are all on
^17.0.0 already; petstore and decidesk were the stragglers.

With the peer conflict resolved, audit fix runs and the count drops 21 -> 17.

What remains needs BREAKING major bumps of dev tooling and is deliberately not
in this PR — @nextcloud/eslint-config@9, vitest@4, @cyclonedx/cyclonedx-npm@6.
Those are fleet-wide toolchain decisions, and #6 is already moving cyclonedx
independently. Two further notes for whoever picks that up:

  - npm offers "@nextcloud/webpack-vue-config@4.0.0" as the fix for the
    crypto-browserify chain, which is a DOWNGRADE from the 7.0.4 in use.
    `fixAvailable` is not always a fix.
  - the dompurify chain arrives through @toast-ui/editor inside
    @conduction/nextcloud-vue itself, so it cannot be fixed from this repo.

Build verified after the sass-loader major: webpack compiles, check:manifest
Ajv PASS.
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/petstore @ 0686376

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
test-unit
check-specs
check-manifest
composer ✅ 100/100
npm ✅ 761/761
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-21 08:07 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/petstore @ 93edfe6

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
test-unit
check-specs
check-manifest
composer ✅ 100/100
npm ✅ 761/761
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-21 08:21 UTC

Download the full PDF report from the workflow artifacts.

petstore and hrmq were the last two apps on eslint 8; everything else moved to
eslint 10 + @nextcloud/eslint-config 9 some time ago. This is not a version
bump — v9 requires eslint >= 10, and eslint 10 is incompatible with the whole
eslint-8-era plugin set this app carried.

Removed, because leaving them is worse than not upgrading at all:
  @eslint/eslintrc, @eslint/js, @eslint/config-helpers,
  @typescript-eslint/eslint-plugin@7, @vue/eslint-config-typescript@13,
  eslint-plugin-vue@9, eslint-plugin-import, eslint-import-resolver-*

A stale eslint-plugin-vue@9 / vue-eslint-parser@9 hoists over the copies v9
bundles; `vue/base/setup-for-vue` then supplies NO parser, `typescript-eslint`
claims **/*.vue instead, and every SFC fails with "Parsing error: Expression
expected". eslint counts a parse failure as ONE finding and lints nothing else
in the file, so the entire Vue layer goes unchecked while the problem count
looks small. Verified this did NOT happen: the run reports real Vue rule
findings (vue/attribute-hyphenation, vue/new-line-between-multi-line-property),
which only a working parser can produce.

eslint.config.js -> eslint.config.mjs, copied from the fleet's canonical shape
(scholiq) with only the app-specific tail changed. It must be `.mjs` rather
than `"type": "module"`: v9 is ESM, but webpack.config.js, vitest.config.js and
the tests/** CLI checkers are CommonJS and would stop parsing.

engines: ^20 -> ^22.14 || ^24 || >=26, plus .nvmrc. v9 imports findPackageJSON
from node:module, which first exists in 22.14; on Node 20 eslint dies before
linting a single file and npm reports the mismatch only as an EBADENGINE
warning it continues past.

Also aligned, each one forced by the next:
  vitest 1 -> 3            (@vitejs/plugin-vue@5 pins vite to ^5||^6, but
  @vitejs/plugin-vue 5 -> 6 @nextcloud/vue's vue-router wants ^7||^8, so the
                            plugin had to move for the tree to resolve)
  stylelint 15 -> 17, @nextcloud/stylelint-config 2 -> 3
  sass-loader 16 -> 17     (`npm audit fix` could not run at all until this
                            peer conflict was resolved)

Lint findings fixed rather than suppressed: 82 -> 0 errors. 71 were mechanical
(--fix), plus an unused catch binding (`catch (e)` -> `catch`) and `no-console`
set off to match scholiq/procest/pipelinq/decidesk/shillinq, whose remaining
uses here are console.warn on a failed fetch.

npm audit: 21 findings (1 critical, 3 high) -> 10 (0 critical, 1 high).

NOT done: @cyclonedx/cyclonedx-npm stays at ^4.2.1. v6 treats a non-clean
`npm ls` as fatal, and this tree cannot be made clean from here —
stylelint-config-recommended-vue@1.6.1 peers postcss-html@^1 while its own
stylelint-config-html@2 requires ^2, an upstream contradiction the whole fleet
carries. Bumping cyclonedx would trade a passing SBOM job for a failing one.

Verified: lint 0 errors, vitest 15/15, check:manifest Ajv PASS, webpack builds.
@rubenvdlinde
rubenvdlinde requested a review from Rem-Dam as a code owner August 21, 2026 09:21
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/petstore @ 7164387

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
test-unit
check-specs
check-manifest
composer ✅ 100/100
npm ✅ 747/747
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-21 09:30 UTC

Download the full PDF report from the workflow artifacts.

gate-16 (spec-coverage) flagged one changed method with no @SPEC — true about
the diff, false about the change. `UserDisplay.resolve()` appears only because
eslint 10 flagged its unused catch binding (`catch (e)` -> `catch`).

Used `@spec exclude` with the reason rather than pointing at a requirement.
Resolving a UID to a display name is presentation detail with no petstore
requirement behind it; naming an anchor would assert a traceability that does
not exist and would then pass silently forever.

For the record, this branch is net BETTER than development on gates:
  development: gate-4, 5, 14, 19, 25, 26 FAIL (6)
  this branch: gate-4, 5, 14 FAIL (3, all pre-existing)
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/petstore @ 8852427

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
test-unit
check-specs
check-manifest
composer ✅ 100/100
npm ✅ 747/747
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-21 09:57 UTC

Download the full PDF report from the workflow artifacts.

Two halves of the same defect (the openconnector#1173 rule: an app's floor must
be >= the maximum floor of every <app> it depends on).

petstore hard-depends on openregister — src/manifest.json declares
"dependencies": ["openregister"] — and openregister declares
<nextcloud min-version="32"/>. petstore declared 28.

  appinfo/info.xml   min-version 28 -> 32

  Below 32 the dependency refuses to install and every pet, category and order
  — all OpenRegister objects — is unreachable. Declaring 28 advertised an App
  Store range this app cannot deliver.

  code-quality.yml   nextcloud-test-refs stable31 -> stable34

  The stable31 cells could never enable openregister and failed at "Install
  Nextcloud" with the workflow's own words: "This is an ENVIRONMENT failure,
  not an application failure — the run cannot measure this repository without
  it." They were burning two matrix legs to tell us that, on every run, before
  a line of this repo's code executed.

  stable31 is REMOVED, not dropped for coverage: an untested range is an
  advertised claim we cannot support, and the app no longer claims it. The
  matrix now matches the fleet (procest, pipelinq, scholiq all run 34/32/33).

info.xml element order re-checked against app-info.xsd after the edit: all
sequences in order.
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/petstore @ d217226

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
test-unit
check-specs
check-manifest
composer ✅ 100/100
npm ✅ 747/747
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-21 10:10 UTC

Download the full PDF report from the workflow artifacts.

… app

The dashboard rendered NOTHING — an empty page under the Nextcloud chrome —
and every CI check stayed green, because the failure is a runtime abort:

    Error: Two different versions of Dexie loaded in the same app: 4.4.5 and 4.4.4

Dexie refuses to initialise twice and throws during boot, so no Vue component
ever mounts. Found by opening the page, not by any check.

Cause, in two layers:

  1. @conduction/nextcloud-vue VENDORS dexie inside its published dist, at
     dist/esm/node_modules/dexie/dist/dexie.js. It is not a resolvable
     node_modules entry, so `npm ls dexie` reports exactly ONE copy and the
     duplication is invisible from the dependency tree.

  2. petstore also declared `dexie: ^4.0.8` directly — and never imports it
     anywhere in src/. The bump to nc-vue 2.9.x moved the app's own copy to
     4.4.5 while the vendored one stayed 4.4.4, and the two instances collided.

Removing the unused direct dependency leaves nc-vue's vendored copy as the only
one. Verified in a browser: the dashboard now renders `cn-dashboard-page` with
its header, 42 widget wrappers, 28 KPI cards and 3 tables.

Also kept: `dexie` added to the shared-vendor splitChunks group. It did not fix
this on its own — splitChunks cannot dedupe a copy that is already inlined in a
dependency's dist — but it is correct regardless, because with `default: false`
and `defaultVendors: false` nothing else can share a singleton library, and the
group is already attached before the others so no new <script> tag is needed.

The vendoring is an upstream packaging problem: a stateful singleton that
aborts on double-load should be a peer dependency, not inlined. Reporting to
ConductionNL/nextcloud-vue separately.
@rubenvdlinde

rubenvdlinde commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

Final state — two failures remain, both externally owned

PHPUnit (NC stable34) → step Guard coverage baseline. scripts/coverage-guard.php here predates --against and cannot do a merge-base comparison. #51 fixes exactly this file, which is why I backed my duplicate copy out of this branch. It does not fail on development only because a no-diff run has nothing to compare. #51 is itself red on five of its own jobs, so it cannot clear the way yet.

Security (composer)npm audit, 10 findings. Down from 21 (critical eliminated, highs 3 → 1). What remains needs breaking majors of dev tooling or upstream fixes: the dompurify chain arrives through @toast-ui/editor inside nc-vue itself, and cyclonedx cannot go to 6 because v6 treats a non-clean npm ls as fatal.

What this branch fixes

area fix
blank dashboard the page rendered nothing — two dexie copies at different versions abort Dexie during boot, so no component mounts. Found by opening it; no static check sees a runtime abort. Fixed by dropping the unused direct dependency (upstream: ConductionNL/nextcloud-vue#719)
info.xml lint three element-ordering defects, each masking the next
PHPUnit stable31 ×2 removed a matrix leg that could never install openregister (min-version 32), and raised petstore's own floor 28 → 32 to match
PHP Quality (phpcs) 2 errors → 0
gate-69 the dashboard now mounts CnDashboardPage
Hydra Gates development fails 6 gates; this branch fails 0
toolchain eslint 8 → 10 + config 9, vitest 1 → 3, stylelint 15 → 17; lint 82 errors → 0

Verified in a browser, not only in CI

cn-dashboard-page renders with its header, 42 widget wrappers, 28 KPI cards and 3 tables — against a completely empty page before.

(An earlier revision of this comment lost its table cells to shell backtick expansion; this is the intended text.)

@rubenvdlinde
rubenvdlinde merged commit 61f3108 into development Aug 21, 2026
35 of 37 checks passed
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/petstore @ 65fabea

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
test-unit
check-specs
check-manifest
composer ✅ 100/100
npm ✅ 746/746
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-21 10:20 UTC

Download the full PDF report from the workflow artifacts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant