Release: merge development into beta - #512
Conversation
Co-authored-by: Ruben van der Linde <rubenvdlinde@gmail.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
The 0.2.17 release bumped the version on main. Without this, development stays behind main and the next development -> main promotion conflicts on the version file. Version files resolve to development's side, which is the higher line, so this never moves a version backwards.
…260831154331 chore(sync): carry beta back into development
Quality Report — ConductionNL/planninq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-l10n-js | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| composer | ✅ | ✅ 104/104 | |||
| npm | ✅ | ✅ 558/558 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-31 15:56 UTC
Download the full PDF report from the workflow artifacts.
Dependabot cannot update these packages. Its npm updater fails with: npm error code EOVERRIDE npm error Override for <pkg> conflicts with direct dependency The package is listed BOTH as a direct dependency and as a literal overrides entry pinned to the same range. Dependabot bumps the direct dependency and does not move the override, npm rejects the mismatched pair, and the update is abandoned -- so these packages can never be updated, security advisories included. npm's self-reference is the idiom for exactly this: $<name> tells the override to follow whatever the direct dependency resolves to, instead of a range that has to be kept in lockstep by hand. This repo already uses it (see the vue entry under @vue/test-utils). Transitive consumers still get pinned to one version -- the direct dependency's -- which is what the override was there to do. What changes is that the pin tracks the dependency instead of duplicating it. Verified in a clean container: bumping the direct dependency with the literal override reproduces the EOVERRIDE above; with the self-reference the same bump resolves. Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Quality Report — ConductionNL/planninq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-l10n-js | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| composer | ✅ | ✅ 104/104 | |||
| npm | ✅ | ✅ 558/558 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-31 16:29 UTC
Download the full PDF report from the workflow artifacts.
Bumps [@eslint/config-helpers](https://github.com/eslint/rewrite/tree/HEAD/packages/config-helpers) from 0.4.2 to 0.7.0. - [Release notes](https://github.com/eslint/rewrite/releases) - [Changelog](https://github.com/eslint/rewrite/blob/main/packages/config-helpers/CHANGELOG.md) - [Commits](https://github.com/eslint/rewrite/commits/core-v0.7.0/packages/config-helpers) --- updated-dependencies: - dependency-name: "@eslint/config-helpers" dependency-version: 0.7.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Quality Report — ConductionNL/planninq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-l10n-js | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| composer | ✅ | ✅ 104/104 | |||
| npm | ✅ | ✅ 558/558 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-31 17:06 UTC
Download the full PDF report from the workflow artifacts.
…2.17 chore(release): sync main back into development
Quality Report — ConductionNL/planninq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-l10n-js | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| composer | ✅ | ✅ 104/104 | |||
| npm | ✅ | ✅ 558/558 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-31 17:13 UTC
Download the full PDF report from the workflow artifacts.
…527) planninq was the last app in the fleet on eslint 8. Dependabot's @nextcloud/eslint-config 8.4.2 -> 9.0.1 bump could not install at all: that release declares `peer eslint: ">=10"`, so twelve checks went red at npm ci, before a single file was linted. Bumping the config alone was never going to work. eslint 8 was held in three more places at once: @typescript-eslint/parser@7 peers eslint ^8.56.0 eslint-plugin-import@2.32.0 peers eslint up to ^9 @eslint/eslintrc exists only to bridge the eslintrc era So the stack moves together, to the versions hermiq, versioniq and keepiq already run green: eslint ^10.9.1, @nextcloud/eslint-config ^9.0.1, @typescript-eslint/parser ^8.68.0. eslint-plugin-vue is dropped because v9 bundles its own v10, and a stale ^9 hoists over it and makes every SFC parse as TypeScript. conductionVue3Fixes is dropped too: it patched a Vue-2 ruleset, and against v9's recommended all 21 vue/no-deprecated-* rules are already on while the two it existed to disable are not enabled at all. Spreading it does not merely duplicate work, it BREAKS the run, naming vue/* rules while registering no plugin. THE CHECK THAT MATTERS HERE IS THE FILE COUNT, NOT THE ERROR COUNT. An eslint 10 install pointed at a config it cannot read lints NOTHING and exits 2 in a way that reads as a lint failure. That is how versioniq's whole Vue and TypeScript layer went unchecked with 266 real problems behind it. This migration hit exactly that on the first attempt, exit 2 and zero files, and it was caught because the file count was the check. eslint 8 linted 46 files; this lints 47. Those 47 files carried 284 errors nobody could see. --fix cleared 222. The remaining 62 are fixed here rather than deferred: 21 no-console all console.error/warn, i.e. real diagnostics, so the rule now allows those two by name instead of being switched off. A stray console.log is still an error, which is what the rule is for. 18 max-statements single-line `if (c) { stmt }` expanded. 14 unused catch every one of the 8 blocks handles the failure and simply does not read the binding, so they become optional catch binding. None was an empty swallow. 5 multi-word-names route views only. They are mounted by path and never written as a tag, so they cannot collide with an HTML element, which is the rule's purpose. Scoped off for views/, kept everywhere else. 2 deprecated props can-close -> no-close, which is its INVERSE, so `:canClose="!loading"` becomes `:noClose="loading"`. And Vue Router 4 removed `exact`. 2 jsdoc tags {@see X} is not a valid inline tag, {@link X} is. 1 event casing MainMenu emitted 'open-settings' while App.vue listens with @OpenSettings. That matched only through Vue 3's camelize fallback in emit(); the emit is now camelCase and the two agree directly. 1 dead assignment every branch assigns or returns, so the null initializer was never read. Verified: eslint 47 files 0/0, build exits 0, stylelint exits 0, and the unit suite is 98/98 both before and after, run on the same checkout. Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Quality Report — ConductionNL/planninq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-l10n-js | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| composer | ✅ | ✅ 104/104 | |||
| npm | ✅ | ✅ 536/536 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-31 17:47 UTC
Download the full PDF report from the workflow artifacts.
planninq was the last fleet app whose shell was hand-written: a router
with 11 routes in src/router/index.js, a MainMenu.vue listing the same
five destinations again, an own-rolled "OpenRegister is required" gate,
and a Dashboard.vue that computed its three KPI counts by filtering an
already-fetched project list in the browser. The manifest carried only
observability keys and said so: "planninq renders no manifest-driven UI".
It does now. The manifest owns the routes, the navigation, the dependency
gate and the dashboard:
dependencies -> CnAppRoot's dependency phase, keeping planninq's own
empty state through the #dependency-missing slot
menu -> CnAppNav (5 destinations + a Documentation footer link)
pages -> 9 pages; main.js builds the vue-router config from
them, one route per page with name === page.id
Dashboard -> type:"dashboard" with three declarative "stat" widgets
counted BY OPENREGISTER instead of in the browser
MainMenu.vue, router/index.js and views/Dashboard.vue are deleted. The
dashboard's two non-KPI panels move to components/DashboardPanels.vue
unchanged; UserSettings.vue loses its own dialog wrapper and becomes a
bare NcAppSettingsSection in CnAppRoot's #user-settings slot. The sidebar
outlet and its provide()d setSidebar/closeSidebar stay in App.vue — that
is app behaviour the shell does not own.
Two things worth knowing for the next app that does this:
1. A dashboard widget TYPE resolves against the LIBRARY's widget catalog
(registerDashboardWidget / getWidgetTypeEntry), not the app's
"registry" prop and not the page's "slots" map. Both of those are for
PAGE components and slot overrides. A type with no catalog entry
renders "Widget not available" with nothing logged, so the panels
widget is registered in main.js, not in registry.js.
2. CnStatWidget resolves its "icon" through the library's own widget-icon
catalog too, which is ~57 names and does not include every MDI icon —
AccountGroupOutline and ArchiveOutline silently became the default
grid glyph. The registered names are AccountGroup and History.
Also fixes a pre-existing display bug the move surfaced: the project list
printed project.icon raw, so a stored icon NAME rendered as text
("AccountMultiplePlusOnboarding Automation"). A name now goes through
CnIcon; an emoji still renders as text.
Verified in the browser against the published @conduction/nextcloud-vue
(USE_LOCAL_LIB=false, not the sibling checkout): all 9 routes resolve to
the right page id with real content and no JS errors, including the
parameterised project board / backlog / timeline; the three KPI tiles
read 3 / 3 / 0 from OpenRegister in the canonical horizontal card; both
panels render and navigate. 98 unit tests pass, eslint is clean.
Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Quality Report — ConductionNL/planninq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ❌ | ||||
| check-l10n-js | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| composer | ✅ | ✅ 104/104 | |||
| npm | ✅ | ✅ 536/536 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ❌ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-31 19:39 UTC
Download the full PDF report from the workflow artifacts.
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
check:manifest failed on development after #530, and took Hydra Gates, E2E and Quality Report down with it: /pages/1..8 must have required property '_note' The schema requires a custom page to say why decomposition into a standard page type was not feasible. It relaxes that only when the component matches the library's ^Cn[A-Z]\w+$ pattern, because then the component name documents the choice itself. All eight pages use host-app SFCs, so none qualified. Each note is derived from what the component actually does, read from its template, not from the page id: ProjectBoard column-per-status board with drag-to-transition ProjectTimeline task bars plus dependency edges, fed by /api/timeline Timesheet entries grouped per day, inline edit TaskDetail detail plus an embedded time-entry log Portfolio per-assignee aggregate with no single backing record Projects card list with a client-side status chip filter ProjectBacklog parent-scoped list under a breadcrumb Boards board picker: entry points rather than records⚠️ Three of these are worth a second look rather than treating this as settled. Projects, ProjectBacklog and Boards are thin list surfaces (113 to 424 lines) that may well fit CnIndexPage once the chip filter and the parent breadcrumb have primitives. The notes record what each is and what the primitive lacks, so converting them later is a smaller decision than rediscovering why they were custom. Verified: check:manifest, lint and build all exit 0, and the diff is exactly eight changed lines. An earlier attempt round-tripped the JSON and reformatted 218 lines while still passing the gate. Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Quality Report — ConductionNL/planninq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ❌ | ||||
| check-l10n-js | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| composer | ✅ | ✅ 104/104 | |||
| npm | ✅ | ✅ 536/536 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ❌ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-31 20:47 UTC
Download the full PDF report from the workflow artifacts.
Quality Report — ConductionNL/planninq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-l10n-js | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| composer | ✅ | ✅ 104/104 | |||
| npm | ✅ | ✅ 536/536 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ❌ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-31 20:57 UTC
Download the full PDF report from the workflow artifacts.
Both were failing on development before the manifest work, and both are
user-visible rather than bookkeeping.
gate-102 manifest-l10n-coverage: 9 manifest strings had no translation, so a
Dutch user saw English navigation. The parity checker requires the official
language of every European country, so the strings are added across all 36
required locales, not only nl. Dutch follows this app's own catalogue, where
board is already 'bord' (Kanban-bord, Bordweergave) and Archived is
'Gearchiveerd'.
gate-60 icon-vocabulary, two findings:
- src/icons.js did not register AccountGroup or History while the manifests
name them. An unregistered name renders NO icon, not a fallback, so those
entries were shipping a blank.
- the Dashboard entry used 'Home' where ADR-077 Tier A requires
ViewDashboardOutline for the dashboard concept. Tier A is a MUST.
The remaining Tier B warning (Portfolio on ChartBar rather than
BriefcaseOutline) is a SHOULD and is left alone.
⚠️ Twice while doing this a scripted edit passed the gate and produced a wrong
diff. Round-tripping the manifest through json.dumps reformatted 218 lines, and
sorting the locale dicts rewrote every existing key in all 37 files: 13,635
added lines for 333 real ones. Both were reverted and redone as order-preserving
edits. The diff is now 745 added over 76 files, which is the 9 keys per locale
plus the generated .js.
Verified: check:l10n, check:l10n-js, check:manifest, lint and build all exit 0,
and icon-vocabulary reports 0 failures.
Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
… swallowing clicks (#536) due-date-reminder-settings.spec.ts failed with a 60s click timeout on the Planninq settings button. The button was never the problem. The call log reads: - locator resolved to <button ... aria-controls="nc-vue-7"> - element is visible, enabled and stable - <div role="dialog" ... data-testid-modal="cn-support-dialog"> subtree intercepts pointer events nc-vue opens the support dialog on first visit and records that the user has seen it in a per-user preference. Playwright starts from a fresh browser profile every run, but that preference lives on the SERVER, so it is never there and the dialog mounts as a full modal mask over the app in every spec. The seed now writes it once for the admin the suite runs as, which is what buildiq's seed already does for the same reason. Verified against the dev instance rather than assumed: deleting the preference and replaying the exact call the seed makes returns HTTP 200 and the preference reads back as present. bash -n passes. This addresses the E2E job only. The app itself was never broken here: the settings dialog works, it was covered. Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Quality Report — ConductionNL/planninq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ⏭️ | ||||
| phpcs | ⏭️ | ||||
| phpmd | ⏭️ | ||||
| psalm | ⏭️ | ||||
| phpstan | ⏭️ | ||||
| phpmetrics | ⏭️ | ||||
| eslint | ⏭️ | ||||
| stylelint | ⏭️ | ||||
| build | ⏭️ | ||||
| composer | ⏭️ | ⏭️ | |||
| npm | ⏭️ | ⏭️ | |||
| app:check-code | ⏭️ | ||||
| info.xml | ⏭️ | ||||
| REUSE | ⏭️ | ||||
| PHPUnit | ❌ | ||||
| Newman | ❌ | ||||
| Playwright | ❌ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-31 21:50 UTC
Download the full PDF report from the workflow artifacts.
Quality Report — ConductionNL/planninq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-l10n-js | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| composer | ✅ | ✅ 104/104 | |||
| npm | ✅ | ✅ 536/536 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ❌ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-08-31 22:08 UTC
Download the full PDF report from the workflow artifacts.
… label (#540) With the support-dialog fix in, due-date-reminder-settings.spec.ts stopped failing on an intercepted click and started failing on a locator that resolves to nothing: waiting for locator('#app-navigation-vue').locator('a[title="Settings"]') There is no such element. CnAppNav auto-prepends the entry that opens the app's NcAppSettingsDialog and names it "Personal settings", and that name is translated, so a title selector is a language assertion this suite has no business making. It is the same defect class as the vault unlock button, which matched /^(Unlock|Set up vault)$/ and found nothing on a Dutch instance. The library carries stable ids for exactly this: data-testid="cn-nav-settings" on the foldout and data-testid="cn-nav-personal-settings" on the entry. Both are present in the installed bundle (2.27.2), verified rather than assumed. 🔴 The click targets the <a> INSIDE the entry, not the test id itself. data-testid lands on NcAppNavigationItem's ROOT, which is an <li>; clicking that is a silent no-op and the failure then surfaces several lines later on whatever the dialog was supposed to show. planninq declares no section:"settings" menu entries, so the foldout exists solely because includePersonalSettings defaults true. That is why the entry is the auto-prepended one rather than an app-declared item. Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
gate-60 reported 1 Tier B warning. Adopted. 1 -> 0. Portfolio ChartBar -> BriefcaseOutline A portfolio of projects is not a bar chart. ChartBar described one VIEW of a portfolio rather than the thing itself.⚠️ BriefcaseOutline had to be REGISTERED in src/icons.js in the same commit. It was not there, and an icon a manifest names but the registry does not hold renders as NOTHING, not a fallback. Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Quality Report — ConductionNL/planninq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-l10n-js | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| composer | ✅ | ✅ 104/104 | |||
| npm | ✅ | ✅ 536/536 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-09-01 05:19 UTC
Download the full PDF report from the workflow artifacts.
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Quality Report — ConductionNL/planninq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-l10n-js | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| composer | ✅ | ✅ 104/104 | |||
| npm | ✅ | ✅ 536/536 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-09-01 05:34 UTC
Download the full PDF report from the workflow artifacts.
Quality Report — ConductionNL/planninq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-l10n-js | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| composer | ✅ | ✅ 104/104 | |||
| npm | ✅ | ✅ 536/536 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-09-01 05:59 UTC
Download the full PDF report from the workflow artifacts.
`npm run lint` was `eslint src`, so two whole trees were never linted. Across
the fleet that hid roughly 3,900 errors, none of which any CI leg had shown.
Most of it was the config, not the code, and the same two defects were in
every app.
**scripts/ had no config block at all.** These are CommonJS Node CLI checkers,
and flat config defaults every `.js` to ESM with browser-ish globals, so eslint
read the CommonJS wrapper itself as undefined identifiers: `require`,
`process`, `__dirname`, `__filename`, `module`. A `scripts/**` block now
declares the environment. Declaring beats suppressing here: `no-undef` is the
rule that catches a genuinely misspelled identifier, and dozens of fake
findings would bury a real one. A second block covers `scripts/**/*.mjs`, which
is ESM and needs Node's globals without the CommonJS wrapper.
**The tests block applied a non-TypeScript-aware rule to TypeScript.** It named
`tests/**/*.ts` while setting the CORE `no-unused-vars`, which v9 deliberately
turns off for `.ts` in favour of the `@typescript-eslint` version. The core
rule reads the parameter names inside a function TYPE as bindings, so
t?: (app: string, key: string) => string
reports `app` and `key` as unused variables, and every unused `catch (e)` in a
`.ts` spec reports twice. The block is split now: `.js`/`.mjs` on the core
rule, `.ts`/`.tsx` on the TypeScript one, same patterns on both.
Also: stale `eslint-disable` comments naming plugins eslint 10 no longer
registers, which are themselves errors ("Definition for rule ... was not
found"), and a rule that must not parse shell scripts.
The genuinely real findings were the useful part: dead locals, unused imports,
dead helper functions, unused `catch` bindings, extensionless relative imports,
and a handful of `== null` comparisons spelled out so they still match null AND
undefined.
Verified per app: `npm run lint` 0 errors over src + tests + scripts,
`prettier --check` clean, and the unit suite still green.
Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Quality Report — ConductionNL/planninq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-l10n-js | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| composer | ✅ | ✅ 104/104 | |||
| npm | ✅ | ✅ 536/536 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-09-01 10:40 UTC
Download the full PDF report from the workflow artifacts.
Nextcloud serves an app under both /apps/planninq/... and /index.php/apps/planninq/..., but generateUrl() returns only the form the instance is configured for. Used as the vue-router base, that means a visitor arriving on the other form has a pathname the router cannot strip its base from. No route matches, the catch-all takes over, and they land on the dashboard with no error at all. Measured live on learniq, which had the identical base, across all 282 of its routes: /apps/learniq/courses resolved to Courses, and /index.php/apps/learniq/courses resolved to the dashboard. Not one broken page, every deep link in that URL form. routerBase() derives the base from the pathname, so it always matches the URL the visitor actually arrived on. openregister, opencatalogi, stackiq, larpinq, zaakafhandelapp, pipelinq and keepiq already do exactly this. Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Quality Report — ConductionNL/planninq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-l10n-js | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| composer | ✅ | ✅ 104/104 | |||
| npm | ✅ | ✅ 536/536 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-09-01 19:14 UTC
Download the full PDF report from the workflow artifacts.
… inside (#548) its own card.⚠️ THE CAUSE IS AN INSET, NOT A COMPONENT. A card widget renders `flush` and then has its padding put BACK by the card-fit rule (`padding: 8px 14px`), so the KPI sits inside the wrapper while the WRAPPER draws the border, radius and background the user reads as "the card". The library's `--clickable:hover` rule then drew a 2px border and a drop shadow on the KPI itself, 8-14px in from the edge being hovered. Measured live on dossiq, while genuinely hovered: the tile carried a 2px rgb(0,103,158) border and its own shadow, inset 9px from the wrapper's top and 15px from its left. A non-card-fit tile sits at 1px, so its border lands on the wrapper's own edge and reads as one card. That inset is the whole difference, which is why it looked app-specific and was not. nextcloud-vue#932 moves the affordance to the wrapper. No layout change: nothing moves, one card outlines. Verified in the browser with a real pointer hover: before inner 2px rgb(0,103,158) + shadow wrapper grey, no shadow after inner transparent, no shadow wrapper rgb(0,103,158) + shadow Every app with clickable stat, gauge or delta tiles had this. This bump is one of the fleet sweep that clears it. Dependency change only: package.json and the nextcloud-vue entry in package-lock.json. Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Quality Report — ConductionNL/planninq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-l10n-js | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| composer | ✅ | ✅ 104/104 | |||
| npm | ✅ | ✅ 536/536 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-09-02 19:11 UTC
Download the full PDF report from the workflow artifacts.
Automated PR to sync development changes to beta for beta release.
Merging this PR will trigger the beta release workflow.