feat(dashboard): 6 daily/hourly charts + date-range header (full legacy parity)#838
Closed
rubenvdlinde wants to merge 11 commits into
Closed
feat(dashboard): 6 daily/hourly charts + date-range header (full legacy parity)#838rubenvdlinde wants to merge 11 commits into
rubenvdlinde wants to merge 11 commits into
Conversation
Drops three webpack entries (jobQueueWidget/recentCallsWidget/sourceSyncWidget), their src/*.js bootstraps, src/views/widgets/*.vue components, and the matching PHP IWidget classes under lib/Dashboard/. Why these are dead at runtime: appinfo/info.xml has NO <dashboard> declaration block, and lib/AppInfo/Application.php's register() never calls registerWidget() or new IconAddon(), so NC never instantiates the IWidget classes and the webpack-built chunks never get loaded by the NC dashboard. The user-facing dashboard already comes from the manifest-driven CnDashboardPage (manifest.json Dashboard page, type=dashboard). Time-series widgets for that page are blocked on the OR GraphQL groupBy primitive (opsx-driven follow-up) and will wire via the manifest, not this widget chain. Net cleanup: 9 files removed, 3 webpack entries dropped.
…vigation)
The chain-C src/ audit identified `src/modals/Modals.vue` as a barrel-import
that webpack built into the bundle but no live entry point ever loaded — it
kept 47 modal files, the entire `src/entities/` tree, all of `src/sidebars/`,
both `src/navigation/` shells, `src/vue/`, `src/dialogs/`, four 0-byte
placeholder components, and several services alive at build time while
being completely unreachable at runtime.
Cascading deletes (everything below was orphan-rooted at Modals.vue):
src/entities/ (64 files, ~2,000 LoC)
— Duplicates OR schemas. useObjectStore + OR's
/api/objects/openconnector/{schema}/* is the canonical path now.
src/sidebars/ (7 files, ~3,050 LoC)
— Replaced by CnLogsPage's built-in filters + CnIndexPage facet
sidebar (enabled by manifest in #826).
src/navigation/MainMenu.vue + Configuration.vue
— Replaced by CnAppRoot + AppSettings manifest page (type: settings).
src/vue/components/JobLogIndex.vue
— Replaced by the JobLogs manifest page (type: logs).
src/dialogs/Dialogs.vue
— Orphan placeholder.
src/components/{Create,Edit}{Endpoint,Webhook}Dialog.vue
— Four 0-byte placeholder files (likely failed scaffolds).
src/components/{DateRangeCalendar,DateRangeInput,PaginationComponent}.vue
— Replaced by CnLogsPage's date filter + CnDataTable's pagination.
src/services/{getTheme,getValidISOstring,isValidJson,openLink}.js +
src/services/errors/{MissingParameterError,ValidationError,index}.js
— Only consumed by orphan modals.
`src/modals/Modals.vue` itself deleted (the root of the cascade).
30+ modal files under `src/modals/` deleted alongside it — every modal whose
UX is fully covered by an nc-vue primitive (CnFormDialog / CnDeleteDialog /
CnDetailPage / CnMassDeleteDialog).
Preserved as extraction reference (intentionally broken imports, eslint-
ignored, see src/modals/README.md):
modals/Mapping/EditMapping.vue (1537 LoC) — bespoke create/edit
modals/Synchronization/EditSynchronization.vue (1076 LoC) — bespoke create/edit
modals/Rule/EditRule.vue (1888 LoC) — visual rule-builder
modals/Endpoint/{AddEndpointRule,EditEndpoint}.vue
modals/Job/{RunJob,TestJob}.vue — action surfaces
modals/Synchronization/{RunSynchronization,TestSynchronization}.vue
modals/MappingTest/ (4 files) — test-mapping action + sub-widgets
modals/Mapping/mappingItem/ (2 files) — sub-record edit/delete
modals/TestSource/TestSource.vue — action surface
Net: 126 files deleted, 1 file (eslint.config.js) edited to ignore the
preserved modals dir, 1 file (src/modals/README.md) added documenting the
extraction plan. ~14,000 LoC removed.
Wire-up untouched — main.js / App.vue / registry.js / manifest.json /
store/store.js still resolve cleanly because none of these deleted trees
were imported by anything in the live entry tree.
After the orphan-tree sweep, the only consumers of the per-app pinia stores
are App.vue (useSettingsStore) and views/Import/ImportIndex.vue
(importExportStore.importFiles). Trim the registry to match.
src/store/modules/{navigation,search}.{js,ts} + their *.spec.{js,ts}
— deleted. The dispatch-modal-by-name state machine
(navigationStore.modal === 'editX') was a v1 pattern fully replaced
by CnIndexPage's #form-dialog / #delete-dialog slots. The search
store hit `/api/search` from a sidebar that no longer exists.
src/store/store.js
— drop useNavigationStore / useSearchStore imports + the
navigationStore / searchStore exports. Updated the header comment
to record the chain-E sweep.
src/store/modules/importExport.js
— drop the dead `importFile` (singular) action and its broken
`import { sourceStore, endpointStore, jobStore, mappingStore,
synchronizationStore, ruleStore } from store.js` — those per-schema
stores were deleted in chain-C. The live `importFiles` (plural,
called by ImportIndex.vue) + `exportFile` are kept untouched.
Net: 4 files deleted, 2 files trimmed, ~420 LoC removed.
… Import
The custom `/import` page lived as a multi-file YAML/JSON drag-and-drop
shell that POSTed to `/index.php/apps/openconnector/api/import` — but
**that backend endpoint was already deleted in the chain-C OR-cutover**
(see appinfo/routes.php comment "Import/Export routes deleted in chain-C
OR-cutover. OR provides POST /api/registers/{id}/import and POST
/api/configurations/{id}/import"). The Vue page was making a request to
a non-existent route on every Import click — broken at runtime.
Replacement path: every CnIndexPage in the manifest already exposes a
Mass Import action in its Actions menu (`showMassImport: true` by
default), wiring CnMassImportDialog against OR's per-schema endpoints.
That covers the use case for the 10 first-class concepts (Sources,
Endpoints, Consumers, Webhooks, Jobs, Mappings, Rules, Synchronizations,
SynchronizationContracts, CloudEvents) without an openconnector-specific
multi-file dispatcher.
Drops:
src/manifest.json
— Import menu item (settings section, order 10)
— Import page entry (custom, /import, ImportIndex)
src/views/Import/ImportIndex.vue (254 LoC)
— The custom upload UI.
src/composables/UseFileSelection.js (98 LoC)
— Drag-drop file-picker helper; ImportIndex was its only consumer.
src/store/modules/importExport.js (76 LoC) + store.js export
— Wrapped the dead /api/import POST; ImportIndex was its only consumer.
src/registry.js
— `ImportIndex` registration; the registry is now empty (next entries
will be v2 widget slots, not custom pages — see updated comment).
lib/Controller/UiController.php::import()
appinfo/routes.php `ui#import` route
— The PHP SPA shell action for /import; serves nothing meaningful now.
Net: 3 source files deleted (~430 LoC), 5 files trimmed, 1 PHP route +
1 PHP controller action removed. Build still green (6.48 MiB main bundle,
slightly smaller).
If a future workflow needs the multi-file batched-import dispatcher, the
right home is a fleet-wide `CnBatchImportWizard` in @conduction/nextcloud-vue
that targets the same OR per-schema endpoints — not an openconnector-
specific resurrection.
…ns' into chore/cleanup-sweep
…drop-custom-import
…legacy parity) Completes the dashboard rebuild started in #831. The user-shared screenshot of the legacy dashboard had a date-range picker + 3 sections of chart pairs (Calls daily/hourly, Jobs daily/hourly, Sync daily/hourly). All six charts now ship as `type: 'chart'` widgets using nc-vue's new `dataSource.bucket` shorthand (ConductionNL/nextcloud-vue#323), which emits OR's `groupBy: { field, interval, from, to }` GraphQL arg from ConductionNL/openregister#1611. Dashboard config gains: dateRange: { enabled: true, persistKey: "openconnector-dashboard" } — Renders CnDateRangePicker above the grid. Defaults to last-7 (UTC midnight boundaries). Persists user pick to localStorage under "openconnector-dashboard". Provides `cnDashboardDateRange` reactive ref to all child chart widgets. 6 chart widgets — area chart for daily series, bar chart for hourly: calls-daily → call_log, interval: day calls-hourly → call_log, interval: hour jobs-daily → job_log, interval: day jobs-hourly → job_log, interval: hour sync-daily → synchronization_log, interval: day sync-hourly → synchronization_log, interval: hour Each chart's dataSource.bucket = { field: "created", interval, fromVar: "from", toVar: "to" }. CnChartWidget injects `cnDashboardDateRange` and substitutes `$from` / `$to` GraphQL variables, so changing the date range refreshes every chart on the page. Layout (12-col grid): Row 0 : 6 KPI tiles (from #831), each 2 cols × 2 cells Row 2-5: calls-daily | calls-hourly (6 + 6 cols × 4 cells) Row 6-9: jobs-daily | jobs-hourly (6 + 6 cols × 4 cells) Row 10+: sync-daily | sync-hourly (6 + 6 cols × 4 cells) Until nc-vue#323 ships a new @conduction/nextcloud-vue beta release, the chart widgets that need the `bucket` shorthand will fall back to the "unavailable" empty state (per the nc-vue PR design — no partial queries fired against null ranges). KPI tiles render normally.
…eat/dashboard-charts # Conflicts: # src/manifest.json # src/registry.js
This was referenced May 21, 2026
Two-line edit to bring feature/i18n-complete-translations to manifest v2: - $schema URL: app-manifest.schema.json → app-manifest-v2.schema.json - version: 1.0.0 → 2.0.0 Pre-flip Ajv check confirmed the manifest already validates against v2 schema 2.7.0 with zero errors — the page-level shapes were already v2-compatible, just the schema header was lagging. No page content changes needed; downstream PRs (#823 issue-814 bootstrap, #826 polish, #827 cleanup, #828 menu-trim, #829 drop-import, #830 action-rows, #831 KPI tiles, #838 charts) continue to apply on top of this v2 base. State on this branch is now Tier 4: - schema URL ✓ v2 - version ✓ 2.0.0 - nc-vue pin ✓ ^1.0.0-beta.67 - customs: 1 (Import, justified by _note — "Multi-step file-upload + dry-run preview UX exceeds nc-vue v2 form/wizard capability; revisit after CnWizardPage ships"). Tier 4 permits justified customs. - The 3 src/views/widgets/*.vue files are NC Dashboard widget entry points (separate webpack chunks, registered via OCA.Dashboard.register), NOT manifest wrappers — stay.
This was referenced May 21, 2026
Merged
…eta.68 Picks up the dashboard date-range header + CnChartWidget.dataSource.bucket shorthand from ConductionNL/nextcloud-vue#326 (auto-published by semantic-release on merge into beta). With this bump, the 6 chart widgets in src/manifest.json's Dashboard page configuration (see #838) leave the "unavailable" fallback state and actually fire OR groupBy queries: GraphQL query($from: String!, $to: String!) { call_log(groupBy: { field: \"created\", interval: DAY, from: \$from, to: \$to }) { groups { key value } } } Variables resolve from the CnDashboardPage's `dateRange` inject, which the manifest enables via `dateRange: { enabled: true, persistKey: \"openconnector-dashboard\" }`. End-to-end pipeline unblocked: openregister#1611 (groupBy primitive, opsx-shipped) → nextcloud-vue#326 (consumer-side bucket + date-range, merged into beta) → this dependency bump → #838's chart widgets render. devDependencies in package.json got alphabetically reordered by npm during the install — content-equal to before the bump, just re-sorted to match npm's preferred ordering.
…ns' into feat/dashboard-charts
rubenvdlinde
added a commit
that referenced
this pull request
May 22, 2026
… Import (#829) * chore(import): drop broken custom Import flow; rely on per-index Mass Import The custom `/import` page lived as a multi-file YAML/JSON drag-and-drop shell that POSTed to `/index.php/apps/openconnector/api/import` — but **that backend endpoint was already deleted in the chain-C OR-cutover** (see appinfo/routes.php comment "Import/Export routes deleted in chain-C OR-cutover. OR provides POST /api/registers/{id}/import and POST /api/configurations/{id}/import"). The Vue page was making a request to a non-existent route on every Import click — broken at runtime. Replacement path: every CnIndexPage in the manifest already exposes a Mass Import action in its Actions menu (`showMassImport: true` by default), wiring CnMassImportDialog against OR's per-schema endpoints. That covers the use case for the 10 first-class concepts (Sources, Endpoints, Consumers, Webhooks, Jobs, Mappings, Rules, Synchronizations, SynchronizationContracts, CloudEvents) without an openconnector-specific multi-file dispatcher. Drops: src/manifest.json — Import menu item (settings section, order 10) — Import page entry (custom, /import, ImportIndex) src/views/Import/ImportIndex.vue (254 LoC) — The custom upload UI. src/composables/UseFileSelection.js (98 LoC) — Drag-drop file-picker helper; ImportIndex was its only consumer. src/store/modules/importExport.js (76 LoC) + store.js export — Wrapped the dead /api/import POST; ImportIndex was its only consumer. src/registry.js — `ImportIndex` registration; the registry is now empty (next entries will be v2 widget slots, not custom pages — see updated comment). lib/Controller/UiController.php::import() appinfo/routes.php `ui#import` route — The PHP SPA shell action for /import; serves nothing meaningful now. Net: 3 source files deleted (~430 LoC), 5 files trimmed, 1 PHP route + 1 PHP controller action removed. Build still green (6.48 MiB main bundle, slightly smaller). If a future workflow needs the multi-file batched-import dispatcher, the right home is a fleet-wide `CnBatchImportWizard` in @conduction/nextcloud-vue that targets the same OR per-schema endpoints — not an openconnector- specific resurrection. * feat(manifest): flip to v2 schema URL — Tier 4 on i18n branch Two-line edit to bring feature/i18n-complete-translations to manifest v2: - $schema URL: app-manifest.schema.json → app-manifest-v2.schema.json - version: 1.0.0 → 2.0.0 Pre-flip Ajv check confirmed the manifest already validates against v2 schema 2.7.0 with zero errors — the page-level shapes were already v2-compatible, just the schema header was lagging. No page content changes needed; downstream PRs (#823 issue-814 bootstrap, #826 polish, #827 cleanup, #828 menu-trim, #829 drop-import, #830 action-rows, #831 KPI tiles, #838 charts) continue to apply on top of this v2 base. State on this branch is now Tier 4: - schema URL ✓ v2 - version ✓ 2.0.0 - nc-vue pin ✓ ^1.0.0-beta.67 - customs: 1 (Import, justified by _note — "Multi-step file-upload + dry-run preview UX exceeds nc-vue v2 form/wizard capability; revisit after CnWizardPage ships"). Tier 4 permits justified customs. - The 3 src/views/widgets/*.vue files are NC Dashboard widget entry points (separate webpack chunks, registered via OCA.Dashboard.register), NOT manifest wrappers — stay.
rubenvdlinde
added a commit
that referenced
this pull request
May 22, 2026
…fields (#828) * chore(manifest): trim log items from menu + add row-level View-logs action The 3 `*Logs` entries (Source logs / Endpoint logs / Job logs) dominated the main nav and competed with the 9 first-class concepts (Sources / Endpoints / Consumers / Webhooks / Jobs / Mappings / Rules / Synchronizations / Cloud events). Removing them from the menu reclaims that vertical space; access to the log pages now lives on the parent index pages' row actions instead: | Index page | Row action `View logs` → | |---|---| | Sources | SourceLogs (`/sources/logs`) | | Endpoints | EndpointLogs (`/endpoints/logs`) | | Jobs | JobLogs (`/jobs/logs`) | | Synchronizations | SynchronizationLogs (`/synchronizations/logs`) | | CloudEvents | CloudEventLogs (`/cloud-events/logs`) | Synchronizations also gains a `View contracts` row action (→ SynchronizationContracts) since the contracts page was already pageless-in-menu after chain-E and is the natural sibling concept to logs. Log pages remain reachable via direct URL; CnLogsPage's `type: logs` is inherently read-only (no Add/Edit/Delete prop surface), so the "log pages must be immutable" todo is already satisfied — no further wiring needed. Manifest schema used: each page's `config.actions[]` array, same shape as decidesk's row actions: `{ id, label, icon, handler: "navigate", route }`. Handler `navigate` passes the row id to the target route — useful once the log pages accept a `?<parent>=<id>` filter param (follow-up). * chore(manifest): curate column set per index page The pre-refactor SourcesIndex.vue (deleted in aacd152) showed a hand-curated set of fields per source — name, status, type, lastCall, lastSync, dateModified, etc. — not the full schema. After the OR cutover, nc-vue's CnIndexPage falls back to schema-driven column generation when the manifest doesn't declare a `columns` array, which surfaced every property on the schema (accept / apikey / auth / authorizationHeader / authorizationPassthroughMethod / configurations / dateCreated / …) and forced the user to horizontal-scroll the table to see anything useful. Pin a curated column set per index, picked from the OR schema in lib/Settings/openconnector_register.json and informed by what the pre-refactor views showed: Sources name, type, status, isEnabled, lastSync, dateModified Endpoints name, method, endpoint, targetType, updated Consumers name, authorizationType, domains, updated Webhooks name, authorizationType, domains, updated Jobs name, jobClass, interval, isEnabled, lastRun, status Mappings name, description, passThrough, dateModified Rules name, action, timing, type, order Synchronizations name, sourceType, targetType, status, sourceLastSynced SynchronizationContracts synchronization, originId, targetId, sourceLastSynced, updated CloudEvents source, type, subject, status, time Users can still toggle to other columns via the sidebar's columns panel (enabled in #826) — these are just the defaults. * chore(manifest): curate create/edit form fields per index page The user reported that the auto-generated Create Mapping modal exposed every property on the schema — `configurations`, `dateCreated`, `dateModified`, `passThrough`, `slug`, `reference`, `unset` — most of which are system fields or advanced settings that don't belong in a "name your new thing" dialog. `CnIndexPage` forwards a `config.includeFields[]` whitelist to `CnFormDialog`. Pin per-index curated field lists so the create/edit dialog only exposes the user-facing fields: Sources name, description, type, isEnabled Endpoints name, description, endpoint, method, targetType Consumers name, description, authorizationType Webhooks name, description, authorizationType Jobs name, description, jobClass, interval, isEnabled Mappings name, description Rules name, description, action, timing, type Synchronizations name, description, sourceType, targetType CloudEvents source, type, subject, data All other fields remain editable on the Detail page (CnDetailPage's property grid). System fields (`dateCreated`, `dateModified`, `slug`, `reference`, `uuid`) stay out of every user-facing form. This is much smaller than the originally-scoped "extract bespoke modal" work (which would have rewritten 1537 LoC `EditMapping.vue` + 1076 LoC `EditSynchronization.vue` + 1888 LoC `EditRule.vue`). `includeFields` solves the user-flagged "form has too many fields" issue with a JSON config change; the larger bespoke-modal effort can land later as separate per-schema PRs IF the curated form is still deemed insufficient (Mapping rules / cast / unset editor, sync source / target config editor, rule condition builder). SynchronizationContracts intentionally has no `includeFields` — contracts are auto-generated by the sync engine; no user-facing create form. * feat(manifest): flip to v2 schema URL — Tier 4 on i18n branch Two-line edit to bring feature/i18n-complete-translations to manifest v2: - $schema URL: app-manifest.schema.json → app-manifest-v2.schema.json - version: 1.0.0 → 2.0.0 Pre-flip Ajv check confirmed the manifest already validates against v2 schema 2.7.0 with zero errors — the page-level shapes were already v2-compatible, just the schema header was lagging. No page content changes needed; downstream PRs (#823 issue-814 bootstrap, #826 polish, #827 cleanup, #828 menu-trim, #829 drop-import, #830 action-rows, #831 KPI tiles, #838 charts) continue to apply on top of this v2 base. State on this branch is now Tier 4: - schema URL ✓ v2 - version ✓ 2.0.0 - nc-vue pin ✓ ^1.0.0-beta.67 - customs: 1 (Import, justified by _note — "Multi-step file-upload + dry-run preview UX exceeds nc-vue v2 form/wizard capability; revisit after CnWizardPage ships"). Tier 4 permits justified customs. - The 3 src/views/widgets/*.vue files are NC Dashboard widget entry points (separate webpack chunks, registered via OCA.Dashboard.register), NOT manifest wrappers — stay.
rubenvdlinde
added a commit
that referenced
this pull request
May 22, 2026
* feat(dashboard): wire 6 KPI tiles via manifest stats-block widgets
Restores the top row of the legacy openconnector dashboard (per the user-
shared screenshot): six clickable count tiles for Sources, Mappings,
Synchronizations, Contracts, Jobs and Endpoints. Each tile resolves its
count via OR's `aggregate: 'count'` shorthand and links to the matching
index page on click.
Uses nc-vue's `type: 'stats-block'` widget (mounts CnStatsBlockWidget,
declared in CnDashboardPage docstring lines 263-266). No code added —
manifest-only:
src/manifest.json — Dashboard page config gains:
- 6 `stats-block` widget defs, each pointing at a schema slug via
`dataSource: { register, schema, aggregate: 'count' }`
- 12-column layout placing the 6 tiles in a single row, each 2 cols
wide and 2 cells tall
The 6 daily/hourly charts (Outgoing Calls / Job Executions / Sync
Executions, each as a daily and hourly chart) stay deferred to a
follow-up PR — they need:
1. `@conduction/nextcloud-vue` `CnChartWidget.dataSource.bucket`
shorthand wired to OR's `groupBy` arg
2. `CnDashboardPage.dateRange` header providing the `from`/`to` inject
both of which are in flight on `ConductionNL/nextcloud-vue`
`feat/dashboard-date-range`, unblocked by
`ConductionNL/openregister#1611`.
Inline `_note` on the manifest documents the deferred-charts state.
* fix(dashboard): use supported stats-block props (route under props, drop iconClass)
The previous commit used `linkRoute` (string) at the widget def top
level + `iconClass` (string) — neither is forwarded by CnDashboardPage's
`getStatsBlockProps` (nc-vue/src/components/CnDashboardPage/CnDashboardPage.vue
line 732-734). The dispatcher only forwards `props.countLabel`,
`props.variant`, `props.showZeroCount`, `props.horizontal`, AND
`props.route` (Vue-router location object).
Move `route` under `props` as `{ name: 'Sources' }` etc. — that's the
shape CnStatsBlockWidget's `route` prop expects (Object, default null;
nc-vue/src/components/CnStatsBlockWidget/CnStatsBlockWidget.vue line
113-116). Drop `iconClass` since neither the widget def envelope nor
the dispatcher route it anywhere; CnStatsBlock supports icons via a
`<component>` import (e.g. MDI Vue), but that can't ride through a
JSON manifest. KPI tiles ship icon-less for now; layering icons via
the manifest is a follow-up nc-vue feature request.
* feat(manifest): flip to v2 schema URL — Tier 4 on i18n branch
Two-line edit to bring feature/i18n-complete-translations to manifest
v2:
- $schema URL: app-manifest.schema.json → app-manifest-v2.schema.json
- version: 1.0.0 → 2.0.0
Pre-flip Ajv check confirmed the manifest already validates against
v2 schema 2.7.0 with zero errors — the page-level shapes were
already v2-compatible, just the schema header was lagging. No page
content changes needed; downstream PRs (#823 issue-814 bootstrap,
#826 polish, #827 cleanup, #828 menu-trim, #829 drop-import, #830
action-rows, #831 KPI tiles, #838 charts) continue to apply on top
of this v2 base.
State on this branch is now Tier 4:
- schema URL ✓ v2
- version ✓ 2.0.0
- nc-vue pin ✓ ^1.0.0-beta.67
- customs: 1 (Import, justified by _note — "Multi-step file-upload
+ dry-run preview UX exceeds nc-vue v2 form/wizard capability;
revisit after CnWizardPage ships"). Tier 4 permits justified
customs.
- The 3 src/views/widgets/*.vue files are NC Dashboard widget
entry points (separate webpack chunks, registered via
OCA.Dashboard.register), NOT manifest wrappers — stay.
rubenvdlinde
added a commit
that referenced
this pull request
May 22, 2026
* fix(controllers): accept string UUIDs on /sources/test, /jobs/run|test, /synchronizations/{id}/run|test
The chain-B/C OR cutover replaced auto-increment integer ids with UUIDs,
but five action-controller methods kept `int $id` parameters:
SourcesController::test lib/Controller/SourcesController.php:225
JobsController::run lib/Controller/JobsController.php:181
JobsController::test lib/Controller/JobsController.php:225
SynchronizationsController::test lib/Controller/SynchronizationsController.php:228
SynchronizationsController::run lib/Controller/SynchronizationsController.php:277
PHP coerces the inbound UUID string ("77637bae-01ec-4909-9f47-f2236fe7c3b1")
to int by taking the leading digits → 77. ObjectService::find(id: "77",
schema: '<schema>') then raises DoesNotExistException → the catch returns
404 Not Found. Every action-button click in the UI + every Newman
fixture POST to /sources/test/{uuid} silently 404s with no log written.
This is the root cause of the empty openconnector dashboard reported in
#838 — the journey tests "pass" because they
only assert response status, not semantic success, but the underlying
CallService / JobService / SynchronizationService never actually runs.
Switch `int $id` → `string $id` on all 5 methods. Drop the now-redundant
`(string) $id` cast at the `find()` call site (the param is already
a string). Update docblocks (`@param int $id` → `@param string $id ...UUID...`).
Discovered while investigating an empty openconnector dashboard.
Companion bugs filed at OR side:
- ConductionNL/openregister#1614 — honor x-openregister-archival annotation
- ConductionNL/openregister#1615 — eager magic-table creation on schema import
Closes #839.
* fix(CallService): write to modern `source` UUID FK instead of legacy `sourceId` integer
The openconnector_register.json descriptor declares `call_log.sourceId`
as a legacy integer FK kept "during transition per chain-A REQ-A-008
(cleanup tracked at #821)", and a parallel `source` property typed
`string format=uuid` ($ref to source schema) as the post-chain-B
canonical reference.
`CallService::call()` (and its 3 short-circuit paths for disabled
source / missing location / rate-limited) write `'sourceId' =>
$source->getUuid()` — a UUID string being shoved into the legacy
integer column. Postgres rejects:
SQLSTATE[22P02]: Invalid text representation: 7
ERROR: invalid input syntax for type integer:
"77637bae-01ec-4909-9f47-f2236fe7c3b1"
Switch all four `'sourceId'` keys to `'source'` so the UUID lands in
the correct column. The legacy integer column stays empty (NULL) —
#821 tracks its removal once nothing reads
it anymore.
## Verified end-to-end on the local container
(After ConductionNL/openregister PR #1616 lands the eager magic-table
creation that materialises `oc_openregister_table_65_223`:)
TRUNCATE oc_openregister_table_65_223;
// PHP CLI: CallService->call(source: $src, endpoint: '/get');
→ row inserted with `source = '77637bae-...'`, status_code = 200
GET /api/objects/openregister/api/objects/openconnector/call_log
→ returns the row (after a manual UPDATE _owner='admin' workaround
pending ConductionNL/openregister#1617 — system-context attribution)
Same fix needed for the JobService / SynchronizationService write paths
(jobId / synchronizationId → job / synchronization) — filed separately
as #841 since those services have additional
complexity (event_message also has the integer-FK problem on
eventId / consumerId / subscriptionId).
Companion changes shipping together in this PR:
- 5 action-controllers `int $id` → `string $id` (the original commit)
- This CallService field-name fix
Both are "chain-B/C cutover type drift" bugs.
rubenvdlinde
added a commit
that referenced
this pull request
May 22, 2026
* chore(cleanup): retire half-removed NC-core dashboard widget chain
Drops three webpack entries (jobQueueWidget/recentCallsWidget/sourceSyncWidget),
their src/*.js bootstraps, src/views/widgets/*.vue components, and the
matching PHP IWidget classes under lib/Dashboard/.
Why these are dead at runtime:
appinfo/info.xml has NO <dashboard> declaration block, and
lib/AppInfo/Application.php's register() never calls registerWidget()
or new IconAddon(), so NC never instantiates the IWidget classes
and the webpack-built chunks never get loaded by the NC dashboard.
The user-facing dashboard already comes from the manifest-driven
CnDashboardPage (manifest.json Dashboard page, type=dashboard).
Time-series widgets for that page are blocked on the OR GraphQL
groupBy primitive (opsx-driven follow-up) and will wire via the
manifest, not this widget chain.
Net cleanup: 9 files removed, 3 webpack entries dropped.
* chore(cleanup): delete cascading orphan trees (entities, sidebars, navigation)
The chain-C src/ audit identified `src/modals/Modals.vue` as a barrel-import
that webpack built into the bundle but no live entry point ever loaded — it
kept 47 modal files, the entire `src/entities/` tree, all of `src/sidebars/`,
both `src/navigation/` shells, `src/vue/`, `src/dialogs/`, four 0-byte
placeholder components, and several services alive at build time while
being completely unreachable at runtime.
Cascading deletes (everything below was orphan-rooted at Modals.vue):
src/entities/ (64 files, ~2,000 LoC)
— Duplicates OR schemas. useObjectStore + OR's
/api/objects/openconnector/{schema}/* is the canonical path now.
src/sidebars/ (7 files, ~3,050 LoC)
— Replaced by CnLogsPage's built-in filters + CnIndexPage facet
sidebar (enabled by manifest in #826).
src/navigation/MainMenu.vue + Configuration.vue
— Replaced by CnAppRoot + AppSettings manifest page (type: settings).
src/vue/components/JobLogIndex.vue
— Replaced by the JobLogs manifest page (type: logs).
src/dialogs/Dialogs.vue
— Orphan placeholder.
src/components/{Create,Edit}{Endpoint,Webhook}Dialog.vue
— Four 0-byte placeholder files (likely failed scaffolds).
src/components/{DateRangeCalendar,DateRangeInput,PaginationComponent}.vue
— Replaced by CnLogsPage's date filter + CnDataTable's pagination.
src/services/{getTheme,getValidISOstring,isValidJson,openLink}.js +
src/services/errors/{MissingParameterError,ValidationError,index}.js
— Only consumed by orphan modals.
`src/modals/Modals.vue` itself deleted (the root of the cascade).
30+ modal files under `src/modals/` deleted alongside it — every modal whose
UX is fully covered by an nc-vue primitive (CnFormDialog / CnDeleteDialog /
CnDetailPage / CnMassDeleteDialog).
Preserved as extraction reference (intentionally broken imports, eslint-
ignored, see src/modals/README.md):
modals/Mapping/EditMapping.vue (1537 LoC) — bespoke create/edit
modals/Synchronization/EditSynchronization.vue (1076 LoC) — bespoke create/edit
modals/Rule/EditRule.vue (1888 LoC) — visual rule-builder
modals/Endpoint/{AddEndpointRule,EditEndpoint}.vue
modals/Job/{RunJob,TestJob}.vue — action surfaces
modals/Synchronization/{RunSynchronization,TestSynchronization}.vue
modals/MappingTest/ (4 files) — test-mapping action + sub-widgets
modals/Mapping/mappingItem/ (2 files) — sub-record edit/delete
modals/TestSource/TestSource.vue — action surface
Net: 126 files deleted, 1 file (eslint.config.js) edited to ignore the
preserved modals dir, 1 file (src/modals/README.md) added documenting the
extraction plan. ~14,000 LoC removed.
Wire-up untouched — main.js / App.vue / registry.js / manifest.json /
store/store.js still resolve cleanly because none of these deleted trees
were imported by anything in the live entry tree.
* chore(cleanup): trim store registry + drop dead importFile
After the orphan-tree sweep, the only consumers of the per-app pinia stores
are App.vue (useSettingsStore) and views/Import/ImportIndex.vue
(importExportStore.importFiles). Trim the registry to match.
src/store/modules/{navigation,search}.{js,ts} + their *.spec.{js,ts}
— deleted. The dispatch-modal-by-name state machine
(navigationStore.modal === 'editX') was a v1 pattern fully replaced
by CnIndexPage's #form-dialog / #delete-dialog slots. The search
store hit `/api/search` from a sidebar that no longer exists.
src/store/store.js
— drop useNavigationStore / useSearchStore imports + the
navigationStore / searchStore exports. Updated the header comment
to record the chain-E sweep.
src/store/modules/importExport.js
— drop the dead `importFile` (singular) action and its broken
`import { sourceStore, endpointStore, jobStore, mappingStore,
synchronizationStore, ruleStore } from store.js` — those per-schema
stores were deleted in chain-C. The live `importFiles` (plural,
called by ImportIndex.vue) + `exportFile` are kept untouched.
Net: 4 files deleted, 2 files trimmed, ~420 LoC removed.
* chore(import): drop broken custom Import flow; rely on per-index Mass Import (#829)
* chore(import): drop broken custom Import flow; rely on per-index Mass Import
The custom `/import` page lived as a multi-file YAML/JSON drag-and-drop
shell that POSTed to `/index.php/apps/openconnector/api/import` — but
**that backend endpoint was already deleted in the chain-C OR-cutover**
(see appinfo/routes.php comment "Import/Export routes deleted in chain-C
OR-cutover. OR provides POST /api/registers/{id}/import and POST
/api/configurations/{id}/import"). The Vue page was making a request to
a non-existent route on every Import click — broken at runtime.
Replacement path: every CnIndexPage in the manifest already exposes a
Mass Import action in its Actions menu (`showMassImport: true` by
default), wiring CnMassImportDialog against OR's per-schema endpoints.
That covers the use case for the 10 first-class concepts (Sources,
Endpoints, Consumers, Webhooks, Jobs, Mappings, Rules, Synchronizations,
SynchronizationContracts, CloudEvents) without an openconnector-specific
multi-file dispatcher.
Drops:
src/manifest.json
— Import menu item (settings section, order 10)
— Import page entry (custom, /import, ImportIndex)
src/views/Import/ImportIndex.vue (254 LoC)
— The custom upload UI.
src/composables/UseFileSelection.js (98 LoC)
— Drag-drop file-picker helper; ImportIndex was its only consumer.
src/store/modules/importExport.js (76 LoC) + store.js export
— Wrapped the dead /api/import POST; ImportIndex was its only consumer.
src/registry.js
— `ImportIndex` registration; the registry is now empty (next entries
will be v2 widget slots, not custom pages — see updated comment).
lib/Controller/UiController.php::import()
appinfo/routes.php `ui#import` route
— The PHP SPA shell action for /import; serves nothing meaningful now.
Net: 3 source files deleted (~430 LoC), 5 files trimmed, 1 PHP route +
1 PHP controller action removed. Build still green (6.48 MiB main bundle,
slightly smaller).
If a future workflow needs the multi-file batched-import dispatcher, the
right home is a fleet-wide `CnBatchImportWizard` in @conduction/nextcloud-vue
that targets the same OR per-schema endpoints — not an openconnector-
specific resurrection.
* feat(manifest): flip to v2 schema URL — Tier 4 on i18n branch
Two-line edit to bring feature/i18n-complete-translations to manifest
v2:
- $schema URL: app-manifest.schema.json → app-manifest-v2.schema.json
- version: 1.0.0 → 2.0.0
Pre-flip Ajv check confirmed the manifest already validates against
v2 schema 2.7.0 with zero errors — the page-level shapes were
already v2-compatible, just the schema header was lagging. No page
content changes needed; downstream PRs (#823 issue-814 bootstrap,
#826 polish, #827 cleanup, #828 menu-trim, #829 drop-import, #830
action-rows, #831 KPI tiles, #838 charts) continue to apply on top
of this v2 base.
State on this branch is now Tier 4:
- schema URL ✓ v2
- version ✓ 2.0.0
- nc-vue pin ✓ ^1.0.0-beta.67
- customs: 1 (Import, justified by _note — "Multi-step file-upload
+ dry-run preview UX exceeds nc-vue v2 form/wizard capability;
revisit after CnWizardPage ships"). Tier 4 permits justified
customs.
- The 3 src/views/widgets/*.vue files are NC Dashboard widget
entry points (separate webpack chunks, registered via
OCA.Dashboard.register), NOT manifest wrappers — stay.
rubenvdlinde
added a commit
that referenced
this pull request
May 22, 2026
…sh (#854) * chore(manifest): polish menu icons + enable index sidebar + docs link Three small UX-polish changes against the manifest-v2 SPA shell: 1. Replace 3 broken/misleading menu icons: - Sources: icon-server → icon-link (icon-server is not defined in NC core CSS, so the entry rendered without any icon at all) - Webhooks: icon-category-social → icon-mail (social rendered as 3 people; mail communicates outbound notification semantics) - Synchronizations: icon-shared → icon-history (shared rendered as account-plus; history renders as the rotate/sync arrows glyph and matches the legacy MDI 'Update' icon the old MainMenu used) 2. Add a Documentation footer link in the settings section, matching the decidesk fleet pattern. Points at https://openconnector.conduction.nl. 3. Enable the sidebar (search + facet filters) on all 10 index pages: Sources, Endpoints, Consumers, Webhooks, Jobs, Mappings, Rules, Synchronizations, SynchronizationContracts, CloudEvents. Uses CnIndexPage's manifest-driven `sidebar: { enabled: true, showMetadata: true }` config — same shape used by decidesk. No code changes; manifest-only. * chore(cleanup): retire half-removed NC-core dashboard widget chain Drops three webpack entries (jobQueueWidget/recentCallsWidget/sourceSyncWidget), their src/*.js bootstraps, src/views/widgets/*.vue components, and the matching PHP IWidget classes under lib/Dashboard/. Why these are dead at runtime: appinfo/info.xml has NO <dashboard> declaration block, and lib/AppInfo/Application.php's register() never calls registerWidget() or new IconAddon(), so NC never instantiates the IWidget classes and the webpack-built chunks never get loaded by the NC dashboard. The user-facing dashboard already comes from the manifest-driven CnDashboardPage (manifest.json Dashboard page, type=dashboard). Time-series widgets for that page are blocked on the OR GraphQL groupBy primitive (opsx-driven follow-up) and will wire via the manifest, not this widget chain. Net cleanup: 9 files removed, 3 webpack entries dropped. * chore(cleanup): delete cascading orphan trees (entities, sidebars, navigation) The chain-C src/ audit identified `src/modals/Modals.vue` as a barrel-import that webpack built into the bundle but no live entry point ever loaded — it kept 47 modal files, the entire `src/entities/` tree, all of `src/sidebars/`, both `src/navigation/` shells, `src/vue/`, `src/dialogs/`, four 0-byte placeholder components, and several services alive at build time while being completely unreachable at runtime. Cascading deletes (everything below was orphan-rooted at Modals.vue): src/entities/ (64 files, ~2,000 LoC) — Duplicates OR schemas. useObjectStore + OR's /api/objects/openconnector/{schema}/* is the canonical path now. src/sidebars/ (7 files, ~3,050 LoC) — Replaced by CnLogsPage's built-in filters + CnIndexPage facet sidebar (enabled by manifest in #826). src/navigation/MainMenu.vue + Configuration.vue — Replaced by CnAppRoot + AppSettings manifest page (type: settings). src/vue/components/JobLogIndex.vue — Replaced by the JobLogs manifest page (type: logs). src/dialogs/Dialogs.vue — Orphan placeholder. src/components/{Create,Edit}{Endpoint,Webhook}Dialog.vue — Four 0-byte placeholder files (likely failed scaffolds). src/components/{DateRangeCalendar,DateRangeInput,PaginationComponent}.vue — Replaced by CnLogsPage's date filter + CnDataTable's pagination. src/services/{getTheme,getValidISOstring,isValidJson,openLink}.js + src/services/errors/{MissingParameterError,ValidationError,index}.js — Only consumed by orphan modals. `src/modals/Modals.vue` itself deleted (the root of the cascade). 30+ modal files under `src/modals/` deleted alongside it — every modal whose UX is fully covered by an nc-vue primitive (CnFormDialog / CnDeleteDialog / CnDetailPage / CnMassDeleteDialog). Preserved as extraction reference (intentionally broken imports, eslint- ignored, see src/modals/README.md): modals/Mapping/EditMapping.vue (1537 LoC) — bespoke create/edit modals/Synchronization/EditSynchronization.vue (1076 LoC) — bespoke create/edit modals/Rule/EditRule.vue (1888 LoC) — visual rule-builder modals/Endpoint/{AddEndpointRule,EditEndpoint}.vue modals/Job/{RunJob,TestJob}.vue — action surfaces modals/Synchronization/{RunSynchronization,TestSynchronization}.vue modals/MappingTest/ (4 files) — test-mapping action + sub-widgets modals/Mapping/mappingItem/ (2 files) — sub-record edit/delete modals/TestSource/TestSource.vue — action surface Net: 126 files deleted, 1 file (eslint.config.js) edited to ignore the preserved modals dir, 1 file (src/modals/README.md) added documenting the extraction plan. ~14,000 LoC removed. Wire-up untouched — main.js / App.vue / registry.js / manifest.json / store/store.js still resolve cleanly because none of these deleted trees were imported by anything in the live entry tree. * chore(cleanup): trim store registry + drop dead importFile After the orphan-tree sweep, the only consumers of the per-app pinia stores are App.vue (useSettingsStore) and views/Import/ImportIndex.vue (importExportStore.importFiles). Trim the registry to match. src/store/modules/{navigation,search}.{js,ts} + their *.spec.{js,ts} — deleted. The dispatch-modal-by-name state machine (navigationStore.modal === 'editX') was a v1 pattern fully replaced by CnIndexPage's #form-dialog / #delete-dialog slots. The search store hit `/api/search` from a sidebar that no longer exists. src/store/store.js — drop useNavigationStore / useSearchStore imports + the navigationStore / searchStore exports. Updated the header comment to record the chain-E sweep. src/store/modules/importExport.js — drop the dead `importFile` (singular) action and its broken `import { sourceStore, endpointStore, jobStore, mappingStore, synchronizationStore, ruleStore } from store.js` — those per-schema stores were deleted in chain-C. The live `importFiles` (plural, called by ImportIndex.vue) + `exportFile` are kept untouched. Net: 4 files deleted, 2 files trimmed, ~420 LoC removed. * chore(manifest): trim log items from menu + add row-level View-logs action The 3 `*Logs` entries (Source logs / Endpoint logs / Job logs) dominated the main nav and competed with the 9 first-class concepts (Sources / Endpoints / Consumers / Webhooks / Jobs / Mappings / Rules / Synchronizations / Cloud events). Removing them from the menu reclaims that vertical space; access to the log pages now lives on the parent index pages' row actions instead: | Index page | Row action `View logs` → | |---|---| | Sources | SourceLogs (`/sources/logs`) | | Endpoints | EndpointLogs (`/endpoints/logs`) | | Jobs | JobLogs (`/jobs/logs`) | | Synchronizations | SynchronizationLogs (`/synchronizations/logs`) | | CloudEvents | CloudEventLogs (`/cloud-events/logs`) | Synchronizations also gains a `View contracts` row action (→ SynchronizationContracts) since the contracts page was already pageless-in-menu after chain-E and is the natural sibling concept to logs. Log pages remain reachable via direct URL; CnLogsPage's `type: logs` is inherently read-only (no Add/Edit/Delete prop surface), so the "log pages must be immutable" todo is already satisfied — no further wiring needed. Manifest schema used: each page's `config.actions[]` array, same shape as decidesk's row actions: `{ id, label, icon, handler: "navigate", route }`. Handler `navigate` passes the row id to the target route — useful once the log pages accept a `?<parent>=<id>` filter param (follow-up). * chore(manifest): curate column set per index page The pre-refactor SourcesIndex.vue (deleted in aacd152) showed a hand-curated set of fields per source — name, status, type, lastCall, lastSync, dateModified, etc. — not the full schema. After the OR cutover, nc-vue's CnIndexPage falls back to schema-driven column generation when the manifest doesn't declare a `columns` array, which surfaced every property on the schema (accept / apikey / auth / authorizationHeader / authorizationPassthroughMethod / configurations / dateCreated / …) and forced the user to horizontal-scroll the table to see anything useful. Pin a curated column set per index, picked from the OR schema in lib/Settings/openconnector_register.json and informed by what the pre-refactor views showed: Sources name, type, status, isEnabled, lastSync, dateModified Endpoints name, method, endpoint, targetType, updated Consumers name, authorizationType, domains, updated Webhooks name, authorizationType, domains, updated Jobs name, jobClass, interval, isEnabled, lastRun, status Mappings name, description, passThrough, dateModified Rules name, action, timing, type, order Synchronizations name, sourceType, targetType, status, sourceLastSynced SynchronizationContracts synchronization, originId, targetId, sourceLastSynced, updated CloudEvents source, type, subject, status, time Users can still toggle to other columns via the sidebar's columns panel (enabled in #826) — these are just the defaults. * chore(import): drop broken custom Import flow; rely on per-index Mass Import The custom `/import` page lived as a multi-file YAML/JSON drag-and-drop shell that POSTed to `/index.php/apps/openconnector/api/import` — but **that backend endpoint was already deleted in the chain-C OR-cutover** (see appinfo/routes.php comment "Import/Export routes deleted in chain-C OR-cutover. OR provides POST /api/registers/{id}/import and POST /api/configurations/{id}/import"). The Vue page was making a request to a non-existent route on every Import click — broken at runtime. Replacement path: every CnIndexPage in the manifest already exposes a Mass Import action in its Actions menu (`showMassImport: true` by default), wiring CnMassImportDialog against OR's per-schema endpoints. That covers the use case for the 10 first-class concepts (Sources, Endpoints, Consumers, Webhooks, Jobs, Mappings, Rules, Synchronizations, SynchronizationContracts, CloudEvents) without an openconnector-specific multi-file dispatcher. Drops: src/manifest.json — Import menu item (settings section, order 10) — Import page entry (custom, /import, ImportIndex) src/views/Import/ImportIndex.vue (254 LoC) — The custom upload UI. src/composables/UseFileSelection.js (98 LoC) — Drag-drop file-picker helper; ImportIndex was its only consumer. src/store/modules/importExport.js (76 LoC) + store.js export — Wrapped the dead /api/import POST; ImportIndex was its only consumer. src/registry.js — `ImportIndex` registration; the registry is now empty (next entries will be v2 widget slots, not custom pages — see updated comment). lib/Controller/UiController.php::import() appinfo/routes.php `ui#import` route — The PHP SPA shell action for /import; serves nothing meaningful now. Net: 3 source files deleted (~430 LoC), 5 files trimmed, 1 PHP route + 1 PHP controller action removed. Build still green (6.48 MiB main bundle, slightly smaller). If a future workflow needs the multi-file batched-import dispatcher, the right home is a fleet-wide `CnBatchImportWizard` in @conduction/nextcloud-vue that targets the same OR per-schema endpoints — not an openconnector- specific resurrection. * chore(manifest): curate create/edit form fields per index page The user reported that the auto-generated Create Mapping modal exposed every property on the schema — `configurations`, `dateCreated`, `dateModified`, `passThrough`, `slug`, `reference`, `unset` — most of which are system fields or advanced settings that don't belong in a "name your new thing" dialog. `CnIndexPage` forwards a `config.includeFields[]` whitelist to `CnFormDialog`. Pin per-index curated field lists so the create/edit dialog only exposes the user-facing fields: Sources name, description, type, isEnabled Endpoints name, description, endpoint, method, targetType Consumers name, description, authorizationType Webhooks name, description, authorizationType Jobs name, description, jobClass, interval, isEnabled Mappings name, description Rules name, description, action, timing, type Synchronizations name, description, sourceType, targetType CloudEvents source, type, subject, data All other fields remain editable on the Detail page (CnDetailPage's property grid). System fields (`dateCreated`, `dateModified`, `slug`, `reference`, `uuid`) stay out of every user-facing form. This is much smaller than the originally-scoped "extract bespoke modal" work (which would have rewritten 1537 LoC `EditMapping.vue` + 1076 LoC `EditSynchronization.vue` + 1888 LoC `EditRule.vue`). `includeFields` solves the user-flagged "form has too many fields" issue with a JSON config change; the larger bespoke-modal effort can land later as separate per-schema PRs IF the curated form is still deemed insufficient (Mapping rules / cast / unset editor, sync source / target config editor, rule condition builder). SynchronizationContracts intentionally has no `includeFields` — contracts are auto-generated by the sync engine; no user-facing create form. * feat(actions): add row-level Run/Test handlers for Sources, Jobs, Synchronizations Restores the ability to trigger backend run/test actions from the UI — post chain-C the per-schema modals (RunJob.vue, TestJob.vue, TestSource.vue, RunSynchronization.vue, TestSynchronization.vue) were orphaned and unreachable, leaving NO way to trigger these workflows from the index pages. The legacy modals are 175-345 LoC each with rich in-modal progress/result panels. Recreating those bespoke modals is preserved as a follow-up (src/modals/README.md). This change ships the **lean version**: manifest-declared row actions whose `handler:` resolves to a small JS function that POSTs to the (still-live) backend endpoint and shows a toast on success/error. The user then checks the corresponding `*Logs` page (now one Actions-menu click away after #828) for run details. src/handlers/actionHandlers.js (NEW) — 5 handler functions, each ~10 LoC: testSourceHandler runJobHandler testJobHandler runSynchronizationHandler testSynchronizationHandler — Built via `makePostHandler` factory; each calls `axios.post(generateUrl(backendPath))` + showSuccess/showError toast. src/registry.js — Export the handlers alongside the existing ImportIndex component. CnIndexPage's `resolveHandler` looks up function entries in this registry by name (line 1513 of nc-vue's CnIndexPage.vue). src/manifest.json — Three index pages gain new row actions before their existing `View logs` entry: Sources +Test connection (testSourceHandler) Jobs +Run now (runJobHandler), +Test (testJobHandler) Synchronizations +Run now (runSynchronizationHandler), +Test (testSynchronizationHandler) Backend endpoints used (all from appinfo/routes.php, untouched): POST /api/sources/test/{id} POST /api/jobs/run/{id} POST /api/jobs/test/{id} POST /api/synchronizations/{id}/run POST /api/synchronizations/{id}/test Mapping `Test mapping` and Endpoint `Add rule` are not included — those need richer in-dialog UX (input picker for mappings; rule selector for endpoints) and stay scoped for the bespoke-modal extraction follow-up. * refactor(handlers): inline t() literals so translation extractor picks them up The original makePostHandler factory passed `successMessage` / `errorMessage` as variables to `t('openconnector', message)` — the extraction tool that generates the .pot file only walks literal-string call-sites and would have missed those strings, leaving them un-translatable. Replace the factory with five small handlers (~5 lines each) where the `t()` call argument is a literal string. Extracted at the cost of ~30 LoC total — acceptable trade for translatable copy. Also factored two helpers (rowId / errorDetail) to keep each handler under 10 lines. Behaviour is unchanged; same five exports remain in the same shape. * feat(dashboard): wire 6 KPI tiles via manifest stats-block widgets Restores the top row of the legacy openconnector dashboard (per the user- shared screenshot): six clickable count tiles for Sources, Mappings, Synchronizations, Contracts, Jobs and Endpoints. Each tile resolves its count via OR's `aggregate: 'count'` shorthand and links to the matching index page on click. Uses nc-vue's `type: 'stats-block'` widget (mounts CnStatsBlockWidget, declared in CnDashboardPage docstring lines 263-266). No code added — manifest-only: src/manifest.json — Dashboard page config gains: - 6 `stats-block` widget defs, each pointing at a schema slug via `dataSource: { register, schema, aggregate: 'count' }` - 12-column layout placing the 6 tiles in a single row, each 2 cols wide and 2 cells tall The 6 daily/hourly charts (Outgoing Calls / Job Executions / Sync Executions, each as a daily and hourly chart) stay deferred to a follow-up PR — they need: 1. `@conduction/nextcloud-vue` `CnChartWidget.dataSource.bucket` shorthand wired to OR's `groupBy` arg 2. `CnDashboardPage.dateRange` header providing the `from`/`to` inject both of which are in flight on `ConductionNL/nextcloud-vue` `feat/dashboard-date-range`, unblocked by `ConductionNL/openregister#1611`. Inline `_note` on the manifest documents the deferred-charts state. * fix(dashboard): use supported stats-block props (route under props, drop iconClass) The previous commit used `linkRoute` (string) at the widget def top level + `iconClass` (string) — neither is forwarded by CnDashboardPage's `getStatsBlockProps` (nc-vue/src/components/CnDashboardPage/CnDashboardPage.vue line 732-734). The dispatcher only forwards `props.countLabel`, `props.variant`, `props.showZeroCount`, `props.horizontal`, AND `props.route` (Vue-router location object). Move `route` under `props` as `{ name: 'Sources' }` etc. — that's the shape CnStatsBlockWidget's `route` prop expects (Object, default null; nc-vue/src/components/CnStatsBlockWidget/CnStatsBlockWidget.vue line 113-116). Drop `iconClass` since neither the widget def envelope nor the dispatcher route it anywhere; CnStatsBlock supports icons via a `<component>` import (e.g. MDI Vue), but that can't ride through a JSON manifest. KPI tiles ship icon-less for now; layering icons via the manifest is a follow-up nc-vue feature request. * feat(dashboard): add 6 daily/hourly charts + date-range header (full legacy parity) Completes the dashboard rebuild started in #831. The user-shared screenshot of the legacy dashboard had a date-range picker + 3 sections of chart pairs (Calls daily/hourly, Jobs daily/hourly, Sync daily/hourly). All six charts now ship as `type: 'chart'` widgets using nc-vue's new `dataSource.bucket` shorthand (ConductionNL/nextcloud-vue#323), which emits OR's `groupBy: { field, interval, from, to }` GraphQL arg from ConductionNL/openregister#1611. Dashboard config gains: dateRange: { enabled: true, persistKey: "openconnector-dashboard" } — Renders CnDateRangePicker above the grid. Defaults to last-7 (UTC midnight boundaries). Persists user pick to localStorage under "openconnector-dashboard". Provides `cnDashboardDateRange` reactive ref to all child chart widgets. 6 chart widgets — area chart for daily series, bar chart for hourly: calls-daily → call_log, interval: day calls-hourly → call_log, interval: hour jobs-daily → job_log, interval: day jobs-hourly → job_log, interval: hour sync-daily → synchronization_log, interval: day sync-hourly → synchronization_log, interval: hour Each chart's dataSource.bucket = { field: "created", interval, fromVar: "from", toVar: "to" }. CnChartWidget injects `cnDashboardDateRange` and substitutes `$from` / `$to` GraphQL variables, so changing the date range refreshes every chart on the page. Layout (12-col grid): Row 0 : 6 KPI tiles (from #831), each 2 cols × 2 cells Row 2-5: calls-daily | calls-hourly (6 + 6 cols × 4 cells) Row 6-9: jobs-daily | jobs-hourly (6 + 6 cols × 4 cells) Row 10+: sync-daily | sync-hourly (6 + 6 cols × 4 cells) Until nc-vue#323 ships a new @conduction/nextcloud-vue beta release, the chart widgets that need the `bucket` shorthand will fall back to the "unavailable" empty state (per the nc-vue PR design — no partial queries fired against null ranges). KPI tiles render normally. * chore(deps): bump @conduction/nextcloud-vue ^1.0.0-beta.67 → ^1.0.0-beta.68 Picks up the dashboard date-range header + CnChartWidget.dataSource.bucket shorthand from ConductionNL/nextcloud-vue#326 (auto-published by semantic-release on merge into beta). With this bump, the 6 chart widgets in src/manifest.json's Dashboard page configuration (see #838) leave the "unavailable" fallback state and actually fire OR groupBy queries: GraphQL query($from: String!, $to: String!) { call_log(groupBy: { field: \"created\", interval: DAY, from: \$from, to: \$to }) { groups { key value } } } Variables resolve from the CnDashboardPage's `dateRange` inject, which the manifest enables via `dateRange: { enabled: true, persistKey: \"openconnector-dashboard\" }`. End-to-end pipeline unblocked: openregister#1611 (groupBy primitive, opsx-shipped) → nextcloud-vue#326 (consumer-side bucket + date-range, merged into beta) → this dependency bump → #838's chart widgets render. devDependencies in package.json got alphabetically reordered by npm during the install — content-equal to before the bump, just re-sorted to match npm's preferred ordering.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Stacked on #831 (which adds the 6 KPI tiles). Completes the dashboard rebuild matching the user-shared legacy screenshot: date-range picker header + 6 charts in 3 sections (Calls / Jobs / Sync — each as a daily area chart + hourly bar chart).
Driven entirely by nc-vue's new
CnDashboardPage.dateRangeprop andCnChartWidget.dataSource.bucketshorthand (ConductionNL/nextcloud-vue#323), which emits OR's GraphQLgroupBy: { field, interval, from, to }arg (ConductionNL/openregister#1611). The two upstream PRs handle all the wire-up; this PR is manifest-only (~32 line addition).Wiring
Dashboard page config gains:
Renders
CnDateRangePickerabove the grid. Defaults tolast-7(UTC midnight boundaries). Persists the user's choice tolocalStorage. Provides a reactivecnDashboardDateRangeref consumed by every chart on the page.Six new chart widgets, each
type: 'chart'withdataSource.bucket = { field: "created", interval, fromVar: "from", toVar: "to" }:calls-dailycall_logcalls-hourlycall_logjobs-dailyjob_logjobs-hourlyjob_logsync-dailysynchronization_logsync-hourlysynchronization_logLayout (12-col grid):
Dependencies
ConductionNL/openregister#1611(groupBy GraphQL arg)ConductionNL/nextcloud-vue#323(dateRange + bucket shorthand)@conduction/nextcloud-vue@^1.0.0-beta.Xrelease with the aboveUntil the new beta ships: chart widgets fall back to the
unavailableempty state (per nc-vue#323's design — no partial queries fired against null ranges). KPI tiles render normally either way.Test plan
@conduction/nextcloud-vueinpackage.jsonand rebuild/apps/openconnector/→ confirm KPI tiles + date-range header + 6 charts renderlocalStorage