feat(dashboard): seed default widget bundle on new dashboards + loading shim#129
Merged
rubenvdlinde merged 3 commits intodevelopmentfrom May 5, 2026
Merged
Conversation
…s + loading shim
Three preconfigured tile widgets (Conduction, Sendent, Nextcloud) plus a
Files widget are now inserted on every dashboard created via the sidebar
"+" affordance. The bootstrap path keeps its own role-default-driven seed
so admin templates and template-applied dashboards are unaffected.
The empty-state CTA ("No dashboard yet" / Create dashboard) used to flash
during the initial fetch because `activeDashboard` is null until
`loadDashboards()` resolves. A loading shim now renders while the store's
`loading` flag is set.
- DashboardService::createDashboard gains a `seedDefaults` flag and a
private seedDefaultWidgets() helper that persists the bundle via the
existing tile* columns on WidgetPlacement.
- DashboardApiController::create opts in and returns the placements in
the same envelope shape as getActive() so the store populates
widgetPlacements without an extra round-trip.
- Frontend dashboard store reads placements from the create response.
- Views.vue gains a `v-else-if="loading"` branch with NcLoadingIcon.
…Newman Without `tileType`, `WidgetPlacement::jsonSerialize()` skips emitting the flat tile* fields, so the seeded Conduction/Sendent/Nextcloud tiles shipped to the frontend without a title, icon, or link. Setting `tileType='preset'` makes the renderer's flat-column path work; the sentinel intentionally differs from the legacy `'custom'` value so the placements stay on the registry-backed render path in DashboardGrid.vue rather than the pre-registry tile branch. Newman now pins the contract: - POST /api/dashboard returns exactly 4 placements - positions 0..2 are tiles with the expected tileType, tileTitle, tileLinkValue, and grid coords - position 3 is `files` spanning the second row - the empty-body create path asserts the same widgetId order when 2xx
Contributor
Quality Report — ConductionNL/mydash @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| composer | ✅ | ✅ 100/100 | |||
| npm | ✅ | ✅ 501/501 | |||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ⏭️ |
Coverage: 90.7% (127/140 statements)
Quality workflow — 2026-05-05 21:05 UTC
Download the full PDF report from the workflow artifacts.
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
tilewidgets (Conduction, Sendent, Nextcloud — last uses theicon-nextcloudCSS class) on the top row plus afileswidget below. Admin-template dashboards untouched.NcLoadingIconrenders whileloading=trueandactiveDashboardis null.Backend
DashboardService::createDashboard()gainsbool $seedDefaults = false; controller path opts in. Bootstrap path keeps it false (its own role-default seed runs).seedDefaultWidgets()inserts the four placements withtileType='preset'soWidgetPlacement::jsonSerialize()emits the flat tile* fields the renderer reads.findPlacements(int $dashboardId): arrayexposes the placement mapper to the controller.DashboardApiController::create()returns placements in the same envelope shape asgetActive()so the store populateswidgetPlacementswithout an extra round-trip.Frontend
Views.vueadds av-else-if="loading"branch withNcLoadingIcon.createDashboardaction readsresponse.data.placements ?? [].Tests
DashboardServiceCreateDefaultsTest(2 cases) — seed contract.Views.loadingState.spec.js(2 cases) — loading-shim vs empty-state.placements.length === 4, per-tile shape (widgetId, tileType, tileTitle, tileLinkValue, grid coords), plus widgetId order on empty-body create path.(Note: this is a re-open of PR #126 after a branch rename —
feat/*→feature/*to satisfy the org Branch Policy.)