Release: merge development into beta - #22
Conversation
Replace the unassociated standalone <label> in CreateGroupDashboardModal and TileEditor with CnIconBrowser's :label prop, and drop the now-dead .tile-editor__label rule. Note: in inline mode the library still renders the label's for= against the popup-only trigger id, so full programmatic association needs a follow-up fix in @conduction/nextcloud-vue.
- ICON_CATALOGUE: assert frozen array and { key, label, value, search,
path } entry shape
- TileEditor: cover onIcon iconType derivation (svg vs url) and the
isUrlIcon computed
- OrgNavigationItem: cover the CnDashboardIcon SVG-path branch and the
legacy-name -> path resolution, alongside the existing URL-icon test
…owser into development Reviewed-on: https://codeberg.org/Conduction/launchpad/pulls/123 Reviewed-by: WilcoLouwerse <wilcolouwerse@noreply.codeberg.org>
The Conduction and Sendent default tiles hardcoded
/apps/launchpad/img/<logo>.png. That URL only resolves when the app is
mounted under the default apps directory; on instances serving launchpad
from a secondary apps path (e.g. custom_apps) the logos 404 and render
broken.
Inject IURLGenerator and resolve the logo paths via imagePath('launchpad',
...) so they carry the app's real web prefix regardless of install
location. Falls back to the app-relative path when no generator is wired
(unit-test construction).
Standardizes the strict gate onto the canonical php:8.3-cli + node20 version (fixes the 404 ci-php image where present); validated on the pilot apps.
Fix 8 phpcs errors surfaced by the newly-enforced strict gate: - phpcbf autofix (blank line after control structure, long-condition closing comment) in DashboardService - named-parameter calls to appImagePath() (CustomSniffs NamedParameters) - replace disallowed inline-if ternaries with if/else in DashboardApiController::getActive() and WidgetPlacement::jsonSerialize() - capitalise inline comment in WidgetPlacement
launchpad was the last v1-shaped manifest in the fleet (2026-07-06 manifest audit, item 3): unpkg @latest v1 $schema, v1 top-level widgets[], '@runtime' string sentinels where v2 wants arrays, null register/schema on an index page, and a _note-less custom page. Migrated by hand (the manifest-migrate codemod cannot express these shapes): - $schema -> pinned Codeberg v2 URL; version 0.1.0 -> 0.2.0 - dashboard-detail: empty page-level widgets[] + _note documenting the ADR-036 Decision-8 runtime-manifest stub role (the real per-user pages come from GET /apps/launchpad/api/manifest) - admin-templates-index: type index (null register/schema) -> type custom with component TemplatesPage + _note (no OR register backs this data, so the declarative index contract cannot apply) - admin-settings: _note added - v1 top-level widgets[] block removed; the spend-analytics widget is registered in the JS registry, and its data contract lives in openspec/specs/launchpad-spend-analytics-widget - observability block (ADR-040) unchanged Validates against both the hydra-vendored canonical schema (gate-22 PASS) and current nextcloud-vue (manifest-migrate --validate-only: Valid (v2 schema)).
…2 (gate-22 green)' (#127) from feat/manifest-v2 into development
Fleet audit item 21: stale nc-vue pin. Bumps ^1.0.0-beta.143 -> ^1.0.0-beta.155, which bundles manifest schema 2.13.0 (top-level runtime key) plus the sideEffects/precompiled-validator perf fixes. Verified: installed schema 2.13.0, npm run build green, check_manifest.js gate exit 0. First half of the fix for #129: the bundled schema now accepts the top-level runtime key; the remaining blocker is the widget-entry shape (widgetId -> widgetKey), tracked in #129.
…ta.155 (audit item 21)' (#130) from chore/nc-vue-pin-155 into development
- website/bugs/repository/documentation github -> codeberg - drop github-only <discussion> (no codeberg equivalent) - point <screenshot> at real in-repo screenshots Part of fleet-wide App Store audit 2026-07-07.
Replace SPDX-License-Identifier AGPL-3.0-or-later with EUPL-1.2 across all LaunchPad-authored source (lib/ PHP, src/ Vue/JS, appinfo/info.xml docblock), and normalise SPDX-FileCopyrightText from "LaunchPad Contributors" to "2024 Conduction B.V. <info@conduction.nl>" to match REUSE.toml, composer.json, publiccode.yml and the PHPDoc @copyright/@license. Leaves the info.xml <licence>agpl</licence> app-store token unchanged (documented fleet convention). Fix README licence badge AGPL-3.0 -> EUPL-1.2 to match README §License prose. Add scripts/check-license-headers.sh regression guard (composer lint:licenses, wired into check:strict) that fails the build if an AGPL-3.0 SPDX identifier returns, naming the offending file. Archives openspec change align-source-license-headers-to-eupl.
… (apply fix-group-dashboard-admin-auth-attribute)
…n-activity-debounce-cache-reliability)
…idget-unbounded-user-scan)
…x-l10n-domain-mismatch-mydash-calls)
…ard-accessible-widget-repositioning)
…ots' (#131) from fix/appstore-metadata into development Reviewed-on: https://codeberg.org/Conduction/launchpad/pulls/131
…dd-dashboard-sharing-e2e-coverage)
…ompulsory widgets Adds an acknowledgement read-gate on compulsory dashboard widgets with per-user read receipts and an admin read-receipt report. Local-first (ADR-049 widgets-as-config), no OpenRegister install dependency. Includes Acknowledgement entity/mapper/migration, AcknowledgementService + Controller, AcknowledgementPrompt + report modal, activity integration, PHPUnit + vitest + e2e specs, EN/NL i18n.
…ad rename
The "LaunchPad" menu tile opened OpenBuild: the nav <route> was
mydash.page.index, which never resolved (NC registers the app under its
folder name "launchpad") and fell through to OpenBuild's dashboard
catch-all route. The frontend also called /apps/mydash/api/manifest (404).
- appinfo/info.xml: nav route mydash.page.index → launchpad.page.index;
<id> mydash → launchpad
- backend: route names (launchpad.kiosk.render, launchpad.publicShare.show),
log contexts, and the two straggler occ commands (launchpad:storage:*)
- frontend: i18n domain t('launchpad'), loadState, and /apps/launchpad URLs
across 36 files; rebrand two user-visible "MyDash" strings to "LaunchPad"
- add src/publicPath.js (generateFilePath) imported first in main.js/admin.js
so dynamically-imported chunks load from the served js dir — fixes
"Refused to execute script (MIME text/html)" on launchpad-cn-manifest-validator.js
- add PublicShareContext::isBearer() getter (test expected it)
- reconcile kiosk/demo-showcase unit test assertions to the launchpad app id
DB tables (oc_mydash_*), migrations, and cache prefixes are intentionally
left as mydash_ — they are the physical schema created by already-run
migrations.
…ed js dir
Dynamically-imported chunks (e.g. launchpad-cn-manifest-validator.js) were
requested from /apps/launchpad/js/ — a path Nextcloud answers with the
app-shell HTML — because webpack's default 'auto' publicPath does not match
where NC serves the app's JS (e.g. /custom_apps/launchpad/js/ in a dev
checkout). Result: "Refused to execute script (MIME type text/html)" and the
chunk never loads.
Add src/publicPath.js which sets __webpack_public_path__ via
generateFilePath('launchpad', 'js', ''), resolved against NC's per-app web
root (OC.appswebroots) so it is correct for both apps/ and custom_apps/
layouts. Imported first in main.js and admin.js so it runs before any lazy
import(). Verified live: validator chunk → 200 text/javascript, 0 console
errors.
# Conflicts: # appinfo/info.xml # docs/migration/widget-library-to-ncvue.md # lib/Service/DashboardService.php # lib/Service/PublicShareContext.php # src/components/Dashboard/__tests__/IconPicker.spec.js # src/components/Widgets/Renderers/CalendarWidget.vue # src/components/Widgets/Renderers/FilesWidget.vue # src/components/Widgets/Renderers/LinkButtonWidget.vue # src/components/Widgets/Renderers/NewsWidget.vue # src/components/Widgets/Renderers/PeopleWidget.vue # src/components/Widgets/Renderers/__tests__/FilesWidget.spec.js # src/components/Widgets/VisibilityRulesModal.vue # src/components/Widgets/WidgetContextMenu.vue # src/components/admin/AdminDemoData.vue # src/components/admin/AdminSettings.vue # src/components/admin/RoleLayoutDefaultsSection.vue # src/components/admin/tabs/TemplatesPage.vue # src/dialogs/PublicSharePasswordDialog.vue # src/stores/__tests__/kioskPlaylists.spec.js # src/stores/kioskPlaylists.js # src/stores/publicShares.js # src/views/DashboardPublicShareView.vue # src/views/Views.vue
…RLGenerator' (#124) from fix/launchpad-default-tile-logo-path into development
…ses (#104) FeedRefreshServiceTest::testRefreshFeed500RecordsFailurePreservesItems stubs IResponse::getStatusCode() to 503 and asserts the recorded failure reason starts with "503". The name and the docblock both said 500 — a status nothing in the test produces or checks. The test itself is sound and load-bearing; only the label was wrong. REQ-FRJ-006 is written about per-feed failure tolerance generally and does not single out a status, so 503 is a faithful representative and no coverage changes hands. Renamed, docblock corrected, and the reason for the old label recorded so it is not "fixed" back. Behaviour unchanged; this is a rename plus comments. Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Quality Report — ConductionNL/launchpad @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| composer | ✅ | ✅ 102/102 | |||
| npm | ✅ | ✅ 548/548 | |||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-12 08:32 UTC
Download the full PDF report from the workflow artifacts.
Quality Report — ConductionNL/launchpad @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| composer | ✅ | ✅ 102/102 | |||
| npm | ✅ | ✅ 548/548 | |||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-12 18:28 UTC
Download the full PDF report from the workflow artifacts.
* chore: adopt nextcloud/coding-standard, .editorconfig and NC 34 Configuration only. The reformat is the next commit on purpose, so .git-blame-ignore-revs can name a revision containing nothing but whitespace. - .php-cs-fixer.dist.php + conduction/coding-standard, which extends nextcloud/coding-standard and can only ADD to it — enforced by that package's invariant test, not by review. - cs:check / cs:fix now run php-cs-fixer. They were aliases for phpcs/phpcbf, so the documented Nextcloud command reformatted code AWAY from Nextcloud's standard. - nextcloud/coding-standard dropped as a direct dependency. It arrives transitively at a version conduction/coding-standard has tested against; declared directly it was a dead dependency with no config and no invocation. - phpcs.xml is now a stub over the shared semantics-only ruleset, and the local phpcs-custom-sniffs/ copy is gone. The fleet was carrying six divergent versions of NamedParametersSniff.php — a custom RULE, not a setting. - .editorconfig, verbatim from nextcloud/server. No fleet app had one, so an editor configured by someone's previous Nextcloud work defaulted to tabs, which the old ruleset then rejected. - nextcloud/ocp -> ^34.0 and PHPUnit -> stable34. This app declared support for NC 34 while being analysed against 31, so a symbol REMOVED in 32/33/34 was invisible to the type checker. That is why the NC 34 removal of \OC::$server needed a hand-written PHPCS sniff. - the stylelint glob is quoted, so stylelint expands it rather than the shell. Unquoted, src/**/ matches exactly one directory level and nested components are silently unlinted. gate-65 (coding-standard-adoption) enforces all of the above from ConductionNL/.github@main. This app failed it; with this commit it passes. * style: reformat with nextcloud/coding-standard — whitespace only Applied by php-cs-fixer with conduction/coding-standard. Tabs, same-line braces, (int)$x, single-space concatenation, ordered imports — Nextcloud's dialect, which this app now passes unchanged. 476 file(s), no behaviour change. Isolated from the configuration change so .git-blame-ignore-revs can name a revision that touches nothing but formatting. Reviewing it line by line is not a useful activity; the previous commit is the review. * chore: ignore the reformat commit in git blame 46e028e touches 476 files and changes no behaviour. Without this, every line it reflowed attributes to it and the real author is one --skip away. GitHub honours the file automatically; locally it needs `git config blame.ignoreRevsFile .git-blame-ignore-revs` once. * fix: regenerate composer.lock for the new constraints The previous commit changed composer.json without touching the lock, so `composer install` refused with exit 4 and EVERY PHP job failed: Required (in require-dev) package "conduction/coding-standard" is not present in the lock file. Required (in require-dev) package "conduction/hydra-gates" is not present in the lock file. Required (in require-dev) package "nextcloud/ocp" is in the lock file as "v31.0.9" but that does not satisfy your constraint "^34.0". Nothing was wrong with the reformat or the ruleset — the jobs never got as far as running a tool. Measured on larpingapp#313 before this fix: phpcs, psalm, phpstan and both PHPUnit legs red, all of them at `composer install`. Hydra Gates passed in the same run, because it does not install composer dependencies. Now locked at conduction/coding-standard v1.0.0, conduction/hydra-gates v1.7.0, nextcloud/ocp v34.0.2 — the last of which is the point of the exercise: this app declares support for NC 34 and is now analysed against it. * fix(appinfo): order info.xml elements per the App Store xs:sequence The App Store's info.xsd declares <info> and its children as xs:sequence, so element ORDER is significant. This file was rejected by `xmllint --noout --schema info.xsd appinfo/info.xml`. Nextcloud's lint-info-xml workflow validates against exactly that schema, and ConductionNL/.github#383 adds the same check to the shared pipeline. Elements were moved into the schema's order. <version> and the <nextcloud> min/max-version declaration are unchanged. <commands> now precedes <settings>, and <navigations> follows <activity>; inside <repair-steps>, <post-migration> precedes <install> (the schema's order is pre-migration, post-migration, live-migration, install, uninstall - it does not reflect execution order, which Nextcloud selects by event). Two content fixes were unavoidable, as neither is an ordering problem. <types><search/></types> is not a valid app type at any position: the schema allows only prelogin, filesystem, authentication, extended_authentication, logging, dav, prevent_group_restriction and session, and Nextcloud does nothing with an unrecognised one. Unified search is already wired properly - Application.php calls registerSearchProvider(LaunchPadSearchProvider) - so the element was decorative. Replaced by a comment pointing at that registration. <activity><provider> had to be wrapped in <providers>. The direct child is what the schema rejects, and Nextcloud reads the provider list from $info['activity']['providers']['provider'], so the Activity provider (REQ-ACT-001) was in fact not being registered at all. The wrapping is therefore a behaviour change: OCA\LaunchPad\Activity\Extension now actually registers, which is what the requirement asked for. Verified: `xmllint --noout --schema info.xsd appinfo/info.xml` reports "validates" (libxml2 2.12.10). The pre-change file failed the same command. * fix(deps): pin nextcloud/ocp to ^34.0 instead of dev-master dev-master has advanced to the Nextcloud 35 development stubs, where ISchemaWrapper::createTable()/getTable() return the new OCP\DB\Schema\ITable (@SInCE 35.0.0) rather than being documented as returning \Doctrine\DBAL\Schema\Table. That made PHPStan report 17 genuine parameter-type mismatches in the Migration table builders, which type-hint Doctrine\DBAL\Schema\Table. The app declares <nextcloud min-version="32" max-version="34"/>, so analysing against NC 35 development stubs was wrong regardless. Pinning to ^34.0 matches the constraint used by every other app in this migration (softwarecatalog, hermiq, pipelinq) and by the merged reference larpingapp#313. PHPStan is now clean; no application code changes. * ci: re-trigger Code Quality The previous run produced zero jobs and concluded failure: it started inside the window where ConductionNL/.github@main carried the broken quality.yml splice from b745bf2f, repaired at 4118bca8. Nothing in this PR touches the workflow. * fix(tests): make the ICache test doubles match the real interface OCP\ICache is untyped on every Nextcloud version this app supports — 'get($key)', 'set($key, $value, $ttl = 0)', 'hasKey($key)', 'remove($key)', 'clear($prefix = "")' — identical in server stable32 and stable34. The three in-test fakes narrowed every parameter to string/int, which PHP rejects as an incompatible declaration: PHP Fatal error: Declaration of Unit\Activity\FakeDebounceCache::get( string $key) must be compatible with OCP\ICache::get($key) They only ever loaded because the app resolved nextcloud/ocp at dev-master, which has advanced to the NC 35 development stubs where ICache::get() IS typed. Pinning ocp to ^34.0 lines the stub up with the servers this app actually declares support for, and the fakes then have to line up too. Return types are left in place — widening a parent's absent return type is covariant and legal. Parameter types only; no test behaviour changes. The three affected files run green: OK (39 tests, 80 assertions). * fix(ci): test the whole declared Nextcloud range, not only the ceiling appinfo/info.xml declares <nextcloud min-version="32" max-version="34"/>, but nextcloud-test-refs was '["stable34"]' — so the declared floor and the middle major were advertised to the App Store with no job touching either. This is the coding-standard migration's own defect: its rollout REPLACED the ref list instead of extending it. The programme opened by reporting that nothing was tested on NC 34 and, in fixing that, made 32 and 33 the untested end. Same drift, other direction. stable34 stays first because newman, playwright and journeydoc-capture all read fromJSON(inputs.nextcloud-test-refs)[0] as their single server. Verified green on all three refs against nextcloud/ocp ^34 on portaliq (run 31599055849, six PHPUnit legs: 32/33/34 x PHP 8.3/8.4).
Quality Report — ConductionNL/launchpad @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| composer | ✅ | ✅ 104/104 | |||
| npm | ✅ | ✅ 548/548 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-12 18:57 UTC
Download the full PDF report from the workflow artifacts.
phpmd.xml becomes a stub referencing vendor/conduction/hydra-gates/quality-config/phpmd.xml, and the local phpmd-unusedparams.xml is deleted in favour of the central copy. ExcessiveClassLength 1050 is preserved via <exclude> plus a re-declaration. DevelopmentCodeFragment with ignore-namespaces=false is NOT carried over: with that setting PDepend namespace-qualifies every unqualified call, so the rule matched nothing in this fully namespaced codebase. The central true takes over and the rule becomes live at no cost - phpmd output is byte-identical. The second leg also gains an explicit --baseline-file, because PHPMD auto-discovers phpmd.baseline.xml next to the FIRST ruleset argument and the ruleset has moved into vendor/. Co-authored-by: Ruben van der Linde <release-bot@conduction.nl>
phpstan.neon now includes the shared base shipped in conduction/hydra-gates (quality-config/phpstan-base.neon) and keeps only what is genuinely local to this app. Requires hydra-gates v1.7.1 — v1.7.0's base declared bare relative paths, which PHPStan resolves against the file that declares them, so the run aborted before analysing anything. composer.lock is updated accordingly; no other package moved. Verified with phpstan dump-parameters before and after: level, paths, excludePaths, bootstrapFiles and scanDirectories resolve byte-identically, the same number of files is analysed on both sides, and the finding count is unchanged.
Quality Report — ConductionNL/launchpad @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| composer | ✅ | ✅ 104/104 | |||
| npm | ✅ | ✅ 548/548 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ❌ | ||||
| Newman | ❌ | ||||
| Playwright | ❌ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-12 22:08 UTC
Download the full PDF report from the workflow artifacts.
Moves the pin from 2.2.0-vue3.9 to the current vue3 dist-tag. The lockfile was regenerated with npm 10.8.2 to match the npm version CI runs (engines: npm ^10.0.0); npm ci was verified from a clean node_modules. Verified locally: npm ci, build, 58 vitest files / 641 tests, lint (eslint plus the manifest, initial-state and translation-domain checks), stylelint — all pass. Co-authored-by: Ruben van der Linde <juan.claude@conduction.nl>
Quality Report — ConductionNL/launchpad @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| composer | ✅ | ✅ 104/104 | |||
| npm | ✅ | ✅ 548/548 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ❌ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-12 22:33 UTC
Download the full PDF report from the workflow artifacts.
Quality Report — ConductionNL/launchpad @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| composer | ✅ | ✅ 104/104 | |||
| npm | ✅ | ✅ 548/548 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-12 23:01 UTC
Download the full PDF report from the workflow artifacts.
…110) Lock-only. composer.json is untouched: the ^1.0 constraint is correct and stays floating. v1.7.3 removes two conditional paths from the shared phpstan-base.neon (%cwd%/vendor-bin and %cwd%/lib/Resources/template). A conditional path in a shared base has no spelling that is safe on both PHPStan majors: plain is validated and ABORTS on PHPStan 2.x, the '(?)' marker is parsed as a NEON entity after a %...% expansion and crashes 2.x, and quoting it stops 1.x from stripping the marker so the exclusion silently matches nothing. This app is on PHPStan 1.12.x, so it is not broken today, but it carries the landmine until it moves to PHPStan 2. It has neither vendor-bin nor lib/Resources/template, so no phpstan.neon change is needed.
…eck covers (#113) `stylelint` was quoted; `stylelint:fix` was not. Unquoted, the SHELL expands the glob, and without globstar `src/**/` matches exactly one directory level. Measured in this repo: the unquoted form reaches 32 files, the quoted form 83. So `npm run stylelint:fix` reported done while 51 files were never touched — exactly the files `npm run stylelint` then flags. Found by gate-65's stylelint-glob-unquoted rule, which now inspects BOTH scripts (.github#406). It previously read only the check script and so read this app as clean.
Quality Report — ConductionNL/launchpad @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| composer | ✅ | ✅ 104/104 | |||
| npm | ✅ | ✅ 548/548 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ❌ | ||||
| Newman | ❌ | ||||
| Playwright | ❌ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-12 23:41 UTC
Download the full PDF report from the workflow artifacts.
Quality Report — ConductionNL/launchpad @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| composer | ✅ | ✅ 104/104 | |||
| npm | ✅ | ✅ 548/548 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-13 00:13 UTC
Download the full PDF report from the workflow artifacts.
Adopts @nextcloud/prettier-config (useTabs: true, tabWidth: 4), the tool Nextcloud itself uses, which unlike stylelint covers CSS/SCSS. eslint-config-prettier is spread LAST in eslint.config.js so the two formatters cannot demand opposite things. Measured first: this app's styles were already 84 tab-lines / 0 space-lines, so there was no drift to correct — the value here is the JS/Vue side plus a standing guarantee for the styles. l10n/ is in .prettierignore: 37 generated l10n/*.js translation bundles. Co-authored-by: Ruben van der Linde <juan.claude@conduction.nl>
Quality Report — ConductionNL/launchpad @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| composer | ✅ | ✅ 104/104 | |||
| npm | ✅ | ✅ 548/548 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-13 09:48 UTC
Download the full PDF report from the workflow artifacts.
This repo carries `@nextcloud/prettier-config` and a `format` script, but nothing ever ran that script in CI. The shared `quality.yml` has NO prettier job of its own — it mentions prettier ZERO times (eslint 9, stylelint 10) — and `frontend-checks` is the only opt-in that can invoke a repo's own npm scripts. So prettier was active in developers' editors and inert everywhere else: exactly the state the fleet's old `.prettierrc` was deleted for. Appending "format" to the existing `frontend-checks` array adds one `Frontend Check (format)` job. Every pre-existing entry and its order are unchanged. Measured on this tree before enabling, with the same prettier version and the same resolved config CI uses; the per-app scope and result are recorded in the comment above the input. Centralising the config never stopped drift; the gate does.
Quality Report — ConductionNL/launchpad @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| format | ✅ | ||||
| composer | ✅ | ✅ 104/104 | |||
| npm | ✅ | ✅ 548/548 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-13 11:22 UTC
Download the full PDF report from the workflow artifacts.
The glob was src/**/*.{vue,scss,css}, so css/header-override.css and
css/launchpad.css had never been linted. Both globs (check and fix) widened
together — a stylelint:fix narrower than its check reports done while leaving
violations the check flags, which was a real finding on this app earlier.
Coverage 83 -> 85 files, zero new findings: prettier had already normalised
those stylesheets fleet-wide.
Quality Report — ConductionNL/launchpad @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| format | ✅ | ||||
| composer | ✅ | ✅ 104/104 | |||
| npm | ✅ | ✅ 548/548 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-14 07:21 UTC
Download the full PDF report from the workflow artifacts.
Same migration as the pilot (ConductionNL/larpingapp#325) and the template (ConductionNL/nextcloud-app-template#146). eslint.config.mjs is the canonical copy; only the app-specific blocks at the end differ. Requires Node 22 — @nextcloud/eslint-config@9 declares engines.node ^22.14 || ^24 || >=26 and imports findPackageJSON from node:module, first available in 22.14. The shared workflows already default to 22 (ConductionNL/.github#450). Stale eslint-8-era direct deps and overrides are removed, and the two peers the config needs are declared at the right major (vue-eslint-parser ^10.3.0, @typescript-eslint/parser ^8.67.0). An overrides entry resolves nc-vue's OPTIONAL eslint peer against eslint 10 — optional means npm will not install it, not that a mismatched version is accepted. Coverage: all 82 .vue files parse, 0 fatal errors. 209 PRE-EXISTING VIOLATIONS ARE RECORDED, NOT FIXED ------------------------------------------------------ v9 enables rules this app has never run. --fix and prettier resolved the mechanical ones; 209 findings across 62 files remain and are recorded in eslint-suppressions.json using eslint's own bulk suppressions (--suppress-all), NOT by loosening any rule. Every rule keeps the severity @nextcloud/eslint-config gives it, the debt is counted per file, and --prune-suppressions shrinks it as it is paid down. A NEW violation still fails the run — verified on openconnector by appending a console.log after suppressing. 127 no-console 31 @typescript-eslint/no-unused-vars 24 vue/custom-event-name-casing 9 no-unused-vars 6 n/no-unpublished-import 5 eqeqeq 2 jsdoc/check-tag-names 1 no-useless-assignment 1 @nextcloud/no-deprecated-library-props 1 jsdoc/require-param-type 1 no-undef 1 vue/multi-word-component-names TWO AUTOFIXES ARE DELIBERATELY WITHHELD (recorded as debt instead) ----------------------------------------------------------------- - @nextcloud/l10n-enforce-ellipsis rewrites '...' to the typographic '…' INSIDE translatable strings. That changes the translation KEY and orphans every l10n/*.json entry for it; on openconnector it turned the l10n parity check red while it was green on development. The migration must not silently drop translations, so the source strings are left alone. - vue/prefer-define-options rewrites 'export default {…}' in a plain <script> into 'defineOptions({…})' inside <script setup>, carrying props/data/computed across the block boundary. @vue/compiler-sfc then rejects the result outright (defineOptions() cannot declare props), which broke the build in softwarecatalog and docudesk. It is a semantic refactor, not a lint fix. TEST GLOBALS ARE DECLARED, NOT SUPPRESSED ----------------------------------------- Spec files that live under src/ have no framework globals, so no-undef reported every describe/it/expect as undefined — 1203 findings in openregister from just 7 identifiers. Declaring the environment removed ~1900 phantom findings fleet-wide. Suppressing them instead would have buried any REAL no-undef, which is the rule that catches a typo'd identifier. VERIFIED -------- npm run lint PASS npm run stylelint PASS npm run format PASS npm run build PASS
`@nextcloud/no-deprecated-library-props` autofixed NcButton's deprecated
`type="primary"` to `variant="primary"`. The rule is right — @nextcloud/vue v9
did repurpose `type` as the native button type and moved the visual style to
`variant` — but the rename changes the RENDERED DOM, and tests assert on it:
openbuild 10 tests failed on `button[data-nc-button-type="primary"]`
returning undefined; 1375/1375 pass on `development`.
So this is a runtime change, not a formatting one, and it belongs in its own
PR together with the test updates it requires. It joins the two autofixes
already withheld for the same reason:
@nextcloud/l10n-enforce-ellipsis edits the CONTENT of translatable strings,
changing the translation key
vue/prefer-define-options moves options across SFC block boundaries
and breaks the build
All three keep their @nextcloud/eslint-config severity and are recorded in
eslint-suppressions.json, so the debt is counted and any NEW occurrence still
fails the run.
Verified after the change: openbuild is back to 1375/1375, and lint / format /
stylelint / build pass on every app touched here.
`@nextcloud/l10n-non-breaking-space` replaced the ordinary space before a
typographic ellipsis with U+00A0 INSIDE a translatable string:
- t("hermiq", "name: my-skill, description: …, version: 0.1.0")
+ t("hermiq", "name: my-skill, description: …, version: 0.1.0")
The rule is NC house style and correct in itself, but the string IS the
translation key, so the edit orphans every l10n entry for it. It turned
`test:l10n` red on hermiq, shillinq, decidesk and docudesk while all four are
green on `development`.
🔑 The two branches reported IDENTICAL scan totals — same file count, same
number of distinct keys, same en.json size — and still disagreed. The only
difference was two bytes inside one key, found by comparing the line as hex.
A count that matches is not the same as content that matches.
This is the fourth autofix withheld for the same underlying reason: it edits
meaning rather than layout. The others are l10n-enforce-ellipsis (same key
problem), vue/prefer-define-options (moves options across SFC blocks and
breaks the build) and @nextcloud/no-deprecated-library-props (renames a
rendered prop and breaks DOM assertions).
All four keep their configured severity and are recorded in
eslint-suppressions.json, so the debt is counted and any NEW occurrence still
fails the run.
Verified: test:l10n passes again on all four apps; docudesk unit tests
45/45.
build(lint): migrate to eslint 10 + @nextcloud/eslint-config 9
Quality Report — ConductionNL/launchpad @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| format | ✅ | ||||
| composer | ✅ | ✅ 104/104 | |||
| npm | ✅ | ✅ 536/536 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-14 14:57 UTC
Download the full PDF report from the workflow artifacts.
launchpad's last two unthrottled #[PublicPage] endpoints. It now reports ZERO. These were MISSED by the fleet sweep, and the reason is worth recording: an early check reported launchpad as having no git repository, so it was written off as a deployed copy and excluded from every later measurement. It is a normal checkout on development. The app that was already the fleet's BEST at brute-force protection -- PublicShareService is the only service-level IThrottler implementation in the fleet, and the whole sweep copied its shape -- was the one left with unthrottled endpoints. No brute-force counter on either. The share TOKEN is checked by PublicShareController, which already registers failed attempts through PublicShareService; publicShare() is only the shell that hosts it. 120/60 on both, deliberately generous -- a recipient reloading a shared dashboard must not be what trips it. NOT verified locally: launchpad has no vendor/bin/phpunit in this environment, so there is no suite to run. Lint-clean only; CI is the first real run.
Quality Report — ConductionNL/launchpad @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| format | ✅ | ||||
| composer | ✅ | ✅ 104/104 | |||
| npm | ✅ | ✅ 536/536 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-14 15:50 UTC
Download the full PDF report from the workflow artifacts.
* ci: fast structural checks on every branch * ci: close the branch-trigger gap
Quality Report — ConductionNL/launchpad @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| format | ✅ | ||||
| composer | ✅ | ✅ 104/104 | |||
| npm | ✅ | ✅ 536/536 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ✅ | ||||
| Hydra gates | ❌ |
Quality workflow — 2026-08-14 18:39 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.