feat: activate 3 dashboard widgets + apply ADR-004 build pattern#742
feat: activate 3 dashboard widgets + apply ADR-004 build pattern#742rubenvdlinde wants to merge 2 commits into
Conversation
The widget classes (JobQueueWidget, RecentCallsWidget, SourceSyncWidget)
plus matching src/*Widget.js entries plus Vue components (~113-125
lines each) all existed in the tree but were never wired up:
- AppInfo/Application.php had no registerDashboardWidget() calls,
so IManager::getWidgets() never included them
- webpack.config.js had no entries for them, so 'npm run build'
never produced openconnector-*Widget.js
- The PHP load() methods called Util::addScript on file names that
did not exist on disk (would 404 if anyone wired this up partially)
This activates them properly and brings openconnector inline with the
org-wide ADR-004 'Build / bundling' pattern that pipelinq/procest/
docudesk/zaakafhandelapp/opencatalogi already follow:
- 3 webpack entries added (jobQueueWidget, recentCallsWidget,
sourceSyncWidget)
- 3 $context->registerDashboardWidget() calls added in Application.php
- Each widget's PHP load() now Util::addScript()s the runtime + 2
shared chunks before the per-widget bundle (runtime → vendor →
nc-vue → widget)
- .babelrc gains @babel/preset-typescript so .ts files (74 of them
in this app) go through the same babel-loader as the .js files
- webpack.config.js filters out the base config's ts-loader rule and
pushes a babel-loader rule for .ts (one consistent module-ID space)
- optimization.runtimeChunk: { name: 'runtime' } consolidates the
runtime so cross-chunk module resolution survives splitChunks on
apps with broader graphs (TS + many entries — same pattern needed
for zaakafhandelapp)
- optimization.splitChunks extracts Vue + @nextcloud/vue + pinia +
icons + @conduction/nextcloud-vue into stable-filename shared chunks
After 'npm run build':
openconnector-runtime.js (new) 0.003 MB
openconnector-shared-vendor.js (new) 0.34 MB
openconnector-shared-nc-vue.js (new) 1.64 MB
openconnector-jobQueueWidget.js (new) 1.74 MB
openconnector-recentCallsWidget.js (new) 1.74 MB
openconnector-sourceSyncWidget.js (new) 1.74 MB
Type-checking moves to 'npx tsc --noEmit' (separate command, opt-in).
NOTE: this PR could not be browser-validated against this dev install
because the local docker volume has a nested mount layout
('custom_apps/openconnector/openconnector/' instead of
'custom_apps/openconnector/'); Nextcloud refuses to load the app there
('appinfo file cannot be read'). That's a pre-existing docker-dev env
quirk, not caused by this PR. CI build + a clean install will surface
the correct behaviour.
Quality Report — ConductionNL/openconnector @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ❌ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ❌ | ||||
| eslint | ❌ | ||||
| stylelint | ❌ | ||||
| composer | ✅ | ✅ 148/148 | |||
| npm | ❌ | ❌ 1/573 denied | |||
| PHPUnit | ⏭️ | ||||
| Newman | ⏭️ | ||||
| Playwright | ⏭️ |
❌ Denied npm licenses
| Package | Version | License |
|---|---|---|
| @fortawesome/free-solid-svg-icons | 6.7.2 | (CC-BY-4.0 AND MIT) |
Quality workflow — 2026-05-05 09:13 UTC
Download the full PDF report from the workflow artifacts.
There was a problem hiding this comment.
[BLOCKER] Widget titles are Dutch strings missing from translation files — broken on non-Dutch installs
All three PHP widget getTitle() methods return Dutch strings via $this->l10n->t(): 'Taken wachtrij' (JobQueueWidget), 'Recente calls' (RecentCallsWidget), 'Bron synchronisatie status' (SourceSyncWidget). None of these strings appear in l10n/en.json or l10n/nl.json. On a non-Dutch Nextcloud installation getTitle() will return the raw Dutch key. Add the strings to both l10n/en.json (with English translations) and l10n/nl.json (with Dutch translations) and regenerate the .js l10n files.
WilcoLouwerse
left a comment
There was a problem hiding this comment.
Review
🔴 Blockers (2)
- splitChunks extracts shared bundles never loaded by index.php — runtime errors (
templates/index.php:6)
The webpack.config.js diff addssplitChunks: { chunks: 'all', ... }withenforce: truecacheGroups forshared-vendor(Vue, pinia, etc.) andshared-nc-vue. Withchunks: 'all'andenforce: true, webpack WILL extract Vue and pinia out ofopenconnector-main.jsintoopenconnector-shared-vendor.js. The templatetemplates/index.phponly callsUtil::addScript($appId, $appId . '-main')— the shared chunks are never loaded, so the main app page will throw webpack runtime errors about missing modules.
templates/index.php and templates/settings/admin.php must be updated to load openconnector-runtime, openconnector-shared-vendor, and openconnector-shared-nc-vue before the main/settings scripts, exactly as the widget load() methods now do. Alternatively, restrict splitChunks.chunks to 'async' so synchronous entry bundles are not affected.
- Widget titles are Dutch strings missing from translation files — broken on non-Dutch installs —
lib/Dashboard/JobQueueWidget.php:41
🟡 Concerns (4)
- Dutch strings used as-is in English translation file — English users see Dutch text (
l10n/en.json:1)
Widget UI strings appear inl10n/en.jsonwith the Dutch string as both key AND value, e.g."Bekijk bron": "Bekijk bron","Actief": "Actief". English users will see Dutch text. Either change thet()call keys to English and provide Dutch translations innl.json, or keep Dutch keys but provide proper English translations inen.json(e.g."Bekijk bron": "View source"). - Hardcoded /index.php path in onShow() — breaks pretty-URL Nextcloud configurations (
src/views/widgets/JobQueueWidget.vue:77)
All three widgets usewindow.location.href = '/index.php/apps/openconnector/...'for navigation instead ofgenerateUrl()from@nextcloud/router(which is already imported). Nextcloud supports pretty URLs (mod_rewrite) where/index.php/is stripped. The hardcoded path breaks any Nextcloud installation withoutindex.phpin the URL. Fix:window.location.href = generateUrl('/apps/openconnector/jobs')(and similarly for the other two widgets). - API error silently shows empty-content state — user cannot distinguish no-data from error (
src/views/widgets/JobQueueWidget.vue:104)
In all three widgetfetchData()methods, a caught exception sets the data array to[]. The widget then renders the empty-content slot (e.g.'Geen taken gevonden'), which is indistinguishable from the legitimate no-data case. A failed API call (network error, 403, 500) should display a distinct error message. Add anerrordata property, set it in the catch block, and render an error variant ofNcEmptyContentwith a retry button. - onShow() ignores the item argument — all item clicks navigate to the same list page (
src/views/widgets/JobQueueWidget.vue:76)
TheNcDashboardWidget@showevent passes the clicked item as argument, but all threeonShow(item)implementations ignoreitemand navigate to a generic list URL. Consider usinggenerateUrl('/apps/openconnector/jobs/' + item.id)(or similar) so clicking a specific item navigates to its detail page rather than the full list.
🟢 Minor (2)
- IURLGenerator injected but never used — dead constructor dependency (
lib/Dashboard/JobQueueWidget.php:20)
All three PHP widget classes injectIURLGenerator $urlin the constructor butgetUrl()returnsnullunconditionally and$this->urlis never referenced. Remove theIURLGeneratorconstructor parameter and the correspondinguse OCP\IURLGenerator;import. - PHP widget files missing SPDX license header and declare(strict_types=1) (
lib/Dashboard/JobQueueWidget.php:1)
All three dashboard widget PHP files (JobQueueWidget.php,RecentCallsWidget.php,SourceSyncWidget.php) lack the SPDX copyright/license header block required by the project and are missingdeclare(strict_types=1);. Add the standard header and strict-types declaration to each file to satisfy the SPDX hydra gate.
Reviewed by WilcoLouwerse via automated batch review.
Quality Report — ConductionNL/openconnector @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| composer | ✅ | ✅ 148/148 | |||
| npm | ✅ | ✅ 685/685 | |||
| PHPUnit | ⏭️ | ||||
| Newman | ⏭️ | ||||
| Playwright | ⏭️ |
Quality workflow — 2026-05-19 04:09 UTC
Download the full PDF report from the workflow artifacts.
|
Closing — the legacy State on
The ADR-004 build-pattern strand ( Action: the deletion of the legacy Credit @rubenvdlinde for the ADR-004 build pattern itself — that scaffolding lives elsewhere in the fleet for apps still on |
Three widget classes (
JobQueueWidget,RecentCallsWidget,SourceSyncWidget) plus matchingsrc/*Widget.jsentries plus Vue components (~113-125 lines each) all existed in the tree but were never wired up:AppInfo/Application.phphad noregisterDashboardWidget()callswebpack.config.jshad no entries for themload()methods calledUtil::addScripton filenames that did not exist on disk (would 404 if anyone wired this up partially)This PR activates them and brings openconnector inline with the org-wide ADR-004 "Build / bundling" pattern.
What changed
jobQueueWidget,recentCallsWidget,sourceSyncWidget$context->registerDashboardWidget()calls inApplication.phpload()methods updated to attach runtime + 2 shared chunks before the per-widget bundle.babelrc: add@babel/preset-typescript.tsfiles insrc/go through the samebabel-loaderas.jsfileswebpack.config.js: filter out base'sts-loaderrule, pushbabel-loaderrule for.ts$webpack.config.js:optimization.runtimeChunk: { name: 'runtime' }webpack.config.js:optimization.splitChunkswith stable-filename shared chunksNew chunks after
npm run buildopenconnector-runtime.jsopenconnector-shared-vendor.jsopenconnector-shared-nc-vue.jsopenconnector-jobQueueWidget.jsopenconnector-recentCallsWidget.jsopenconnector-sourceSyncWidget.jsNote on local browser validation
This PR could not be browser-validated against the dev install because the local docker volume has a nested mount layout (
custom_apps/openconnector/openconnector/instead ofcustom_apps/openconnector/); Nextcloud refuses to load the app there with "appinfo file cannot be read". That's a pre-existing docker-dev env quirk, not caused by this PR. CI build + a clean install will surface the correct behaviour.Test plan
/apps/dashboard/(or mydash), confirm 3 new widgets in the picker (Job Queue, Recent Calls, Source Sync)npx tsc --noEmit(separate command) for type-check; not gated by webpack