Skip to content

feat(dashboard): seed default widget bundle on new dashboards + loading shim#126

Closed
rubenvdlinde wants to merge 2 commits intodevelopmentfrom
feat/default-widgets-and-loading-state
Closed

feat(dashboard): seed default widget bundle on new dashboards + loading shim#126
rubenvdlinde wants to merge 2 commits intodevelopmentfrom
feat/default-widgets-and-loading-state

Conversation

@rubenvdlinde
Copy link
Copy Markdown
Contributor

Summary

  • Every user-created dashboard now bootstraps with a preconfigured widget bundle: three tile widgets (Conduction, Sendent, Nextcloud — the last using the icon-nextcloud CSS class) on the top row plus a files widget below. Admin-template dashboards are untouched.
  • The empty-state CTA ("No dashboard yet" / Create dashboard) no longer flashes during the initial fetch. A loading shim with NcLoadingIcon renders while loading=true and activeDashboard is null.

What changed

Backend

  • DashboardService::createDashboard() gains a bool $seedDefaults = false parameter and delegates to a new private seedDefaultWidgets() helper. The bootstrap path keeps seedDefaults=false (its own role-default seed already runs); the controller path opts in.
  • The legacy createDefaultPlacements() delegates to the new seed so first-login bootstrap users get the same bundle.
  • New public findPlacements(int $dashboardId): array exposes the placement mapper to the controller without injecting the mapper into it.
  • DashboardApiController::create() returns placements in the same envelope shape as getActive().

Frontend

  • Views.vue adds a v-else-if="loading" branch with NcLoadingIcon.
  • The dashboard store's createDashboard action reads response.data.placements ?? [] instead of hard-coding an empty array (older servers without the seed still render cleanly).

Tests

  • New DashboardServiceCreateDefaultsTest (2 cases) pins the seed contract.
  • New Views.loadingState.spec.js (2 cases) pins the loading-shim vs empty-state branch.
  • NcLoadingIcon added to the Conduction stub used by Vitest.

Test plan

  • vitest run — 67 files / 848 tests passed
  • phpunit — 1057 tests / 2697 assertions passed
  • phpcs / phpstan / eslint clean on touched files
  • Manual UI: create a new dashboard via the sidebar "+" — confirm 3 tiles on row 0 (cols 0-3 / 4-7 / 8-11) and Files on row 3 spanning all 12 cols
  • Manual UI: hard refresh while signed in — confirm the loading shim renders briefly instead of the empty-state flash

…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.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 5, 2026

Quality Report — ConductionNL/mydash @ f3ae426

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 13:06 UTC

Download the full PDF report from the workflow artifacts.

…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
@rubenvdlinde rubenvdlinde requested a review from Rem-Dam as a code owner May 5, 2026 13:10
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 5, 2026

Quality Report — ConductionNL/mydash @ 8242903

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 13:13 UTC

Download the full PDF report from the workflow artifacts.

@rubenvdlinde rubenvdlinde deleted the feat/default-widgets-and-loading-state branch May 5, 2026 20:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant