This repository was archived by the owner on May 29, 2026. It is now read-only.
feat: dashboard sharing, resource uploads, SVG sanitiser, config menu#73
Closed
rubenvdlinde wants to merge 16 commits into
Closed
feat: dashboard sharing, resource uploads, SVG sanitiser, config menu#73rubenvdlinde wants to merge 16 commits into
rubenvdlinde wants to merge 16 commits into
Conversation
Walkthrough of all 9 archived OpenSpec features uncovered three critical
runtime bugs in features marked "implemented". This commit restores them
and clears the supporting quality stack.
Critical fixes
--------------
- ConditionalRule.createdAt: switch ?DateTime to ?string ('c' format) to
match sibling entities. Doctrine DBAL cannot bind a DateTime without
an explicit addType registration; INSERT now succeeds. Same change in
AdminSetting.updatedAt.
- AdminTemplateService + TemplateService: drop the ramsey/uuid require
and inline the random_bytes(16) UUID generator already used by
DashboardFactory. The ramsey class was never autoloaded at runtime
(Application.php does not require vendor/autoload.php), so admin
template creation and template-based dashboard provisioning both
threw 500.
- DashboardService: stop hardcoding PERMISSION_FULL when auto-creating
user dashboards. Read defaultPermissionLevel and defaultGridColumns
from AdminSettingMapper and pass them to DashboardFactory.
Quality
-------
- NamedParametersSniff: skip Entity-magic accessors (set*/get*/is*) on
classes extending OCP\AppFramework\Db\Entity. Entity::__call uses
args[0], so named arguments break those calls. Eliminates 4 false
positives.
- DashboardService: add the missing WidgetPlacement import (PHPMD).
- PageController: replace \OC::server->get(IManager::class) with proper
DI (Psalm).
- UserAttributeResolver: drop the non-existent IUser::getLanguage() call
and read 'core/lang' from IConfig instead (Psalm).
Frontend warnings
-----------------
- TileEditor + WidgetStyleEditor: NcSelect was passing 'Icon' as the
vue-select label key (option.Icon does not exist). Use input-label
for the visible label and label="label" for the option key.
- AdminSettings: replace HTML <label> + bare NcSelect with input-label
prop, satisfying NcSelect's accessibility requirement.
- DashboardSwitcher / WidgetPicker / WidgetWrapper / TileEditor /
WidgetStyleEditor: add aria-label or input-label to icon-only NcButton
/ unlabeled NcTextField / inline color-pick NcButton instances.
Tests: 106 / 106 passing (293 assertions). composer phpcs / phpmd /
psalm clean. End-to-end API verified for conditional rules, admin
templates, prometheus metrics.
…creenshots PHPStan ------- - Add autoload-dev mapping for nextcloud/ocp's OCP\* and NCU\* namespaces. The package ships PHP stubs but declares no autoload section, so PHPStan could not resolve any Nextcloud type and reported every OCP\IUser / IL10N / IURLGenerator etc. call as "unknown class" - 722 errors total. Registering the namespace in our autoload-dev makes the stubs reachable. - Tighten phpstan.neon scanDirectories to point at the OCP/ and NCU/ subdirectories (not the package root) and add focused ignoreErrors for Doctrine\DBAL\Schema\Table calls (provided by Nextcloud's 3rdparty bundle, not our app's vendor) and the JSONResponse strict-status union / Entity::jsonSerialize stub gaps. - Result: 722 -> 0 errors. PHPStan is now meaningful CI signal. Real type fixes surfaced once OCP became visible ------------------------------------------------ - AdminSettingMapper::setSetting(): pass formatted ISO string to setUpdatedAt() instead of a DateTime instance (the entity stores the timestamp as ?string). - DashboardResolver, DashboardService, TemplateService: use 1 instead of true for setIsActive(int), and 0 instead of false for the getIsCompulsory()/getIsVisible() comparisons. Same coercion semantics at runtime, but PHPStan can verify the types. - AdminTemplateService::createTemplate(): cast bool $isDefault to int before passing to the SMALLINT column setter. - DashboardResolver::getEffectivePermissionLevel(): drop the unreachable null-fallback branch (Dashboard::permissionLevel is non-nullable with PERMISSION_FULL default) and the unused settingMapper / AdminSetting imports that only existed to feed it. - ConditionalService / PermissionService: switch getIsVisible()/getIsCompulsory() === false to === 0 (the Entity stores these as int flags, not booleans). phpunit-unit.xml rename ----------------------- - git mv phpunit.xml -> phpunit-unit.xml to match the convention used across other Conduction apps. Composer scripts (test:unit, test:all, test:coverage, test) updated to pass --configuration explicitly so PHPUnit no longer needs to auto-discover. Screenshots ----------- - Add docs/screenshots/admin-settings.png, customize-panel-widgets.png, customize-panel-dashboards.png, template-create-modal.png to document the main customize / admin / template flows. Captured at 1440x1100. Tests: 106 / 106 passing, 293 assertions. PHPCS / PHPMD / Psalm / PHPStan: all clean.
…form Adds 25 OpenSpec change proposals modelling a complete dashboard sharing and runtime experience for MyDash. Specs are organised across 4 dependency layers (foundation → extensions → UI surfaces → runtime shell): Dashboards capability (4): multi-scope-dashboards, default-dashboard-flag, active-dashboard-resolution, fork-current-as-personal — adds group_shared type, default flag, 7-step resolution chain, fork-from-current action. Admin (3): group-priority-order, group-routing, allow-personal-dashboards-flag — admin-controlled group ordering, primary-group resolver, runtime gating. Grid layout (2): responsive-grid-breakpoints, widget-collision-placement — 4 viewport breakpoints, moveScale reflow, deterministic add-widget placement. Widgets (5 + 2 modal/menu): text-display-widget, label-widget, image-widget, link-button-widget, nc-dashboard-widget-proxy, widget-add-edit-modal, widget-context-menu — five widget types plus shared add/edit modal and right-click menu. Resources (3): resource-uploads, resource-serving, svg-sanitisation — admin-only base64 upload pipeline, immutable-cached serve route, DOM-based SVG whitelist. Icons (2): dashboard-icons, custom-icon-upload-pattern — curated MDI registry plus URL discriminator for uploaded icons. UI (2): dashboard-switcher-sidebar, runtime-shell — slide-in 3-section sidebar, page-level shell with canEdit gate. Infra (1): initial-state-contract — typed PHP→JS bootstrap contract. Sharing follow-ups (1): dashboard-sharing-followups — extends the existing dashboard-sharing capability with notifications, bulk management, and deletion cascade with admin-retention guard. Includes the baseline dashboard-sharing capability spec under openspec/specs/. All 25 changes pass openspec validate --strict. Implementation (opsx-apply) is the next step for each.
…into feature/replica-spec-proposals
- Add /sendent-workspace-main/ and /2026.*_sendent-workspace-main.zip to .gitignore (research-only vendor extract, not part of the app). - Remove explicit "Sendent" mentions from image-widget and link-button-widget proposals; keep the technical content intact.
Strips active content (script tags, on* handlers, javascript: URLs, external entities) from SVG payloads before they hit storage. Used by the resource-upload pipeline to make user-supplied SVGs safe to serve inline. New InvalidSvgException is thrown when the input cannot be made safe.
- ResourceController exposes the upload + serve endpoints, with a dedicated ResourceUploadRequestParser to handle PUT/PATCH multipart payloads (PHP $_FILES doesn't populate for those verbs). - ResourceService owns the upload pipeline and routes SVGs through SvgSanitiser before persisting. - ImageMimeValidator enforces declared-vs-actual MIME parity to block smuggled-payload attacks (image/png claim with non-PNG bytes, etc.). - New typed exceptions (ResourceException base + nine concrete kinds) produce predictable HTTP responses from the controller.
…cade - DashboardShare entity, mapper, service, and API controller for user/group sharing with view/edit permission grants. - Migration Version001005 adds the oc_mydash_dashboard_shares table via DashboardShareTableBuilder. - Notifier renders dashboard_shared and dashboard_ownership_transferred notifications (REQ-SHARE-011). - UserDeletedListener cascades share cleanup and transfers admin-retained dashboards on user deletion (REQ-SHARE-012, 013). - New PersonalDashboardsDisabledException for the admin-disabled-personal scope path used by DashboardService.
- DashboardConfigMenu: top-bar entry with Conduction + Sendent brand links and access to the dashboard config modal. - DashboardConfigModal: edit dashboard metadata, manage shares. - WidgetPickerModal: dedicated picker UI for adding widgets. - Add img/conduction-logo.png and img/sendent-logo.png brand assets used by the menu.
- Register share, resource, getById, sharee-search, and revoke routes in appinfo/routes.php. - Extend DashboardApiController + DashboardService + DashboardFactory + DashboardMapper + Dashboard entity to surface share-aware lookups, ownership transfer, and the personal-disabled scope path. - PermissionService gains share-derived view/edit checks. - Frontend store + api.js learn to fetch shares, sharees, and to call the new endpoints; Views.vue mounts DashboardConfigMenu / DashboardConfigModal / WidgetPickerModal. - Bump appinfo version to 1.0.4-unstable.0.
Captured walkthrough notes from a working session through the dashboard flows; left as raw findings for follow-up tickets and spec refinement.
The DashboardShare entity declares an updatedAt field but the table builder forgot to add the matching column, so updates would silently fail to persist on a fresh schema. Adds the nullable DATETIME column.
Contributor
Author
|
Closing as duplicate. This branch was built from a stale base and parallel-implements work that has already shipped to `development` through other PRs:
Both branches added the same files (`SvgSanitiser`, `ImageMimeValidator`, `DashboardShareService`, `ResourceController`, `DashboardShareApiController`, etc.) with different implementations, plus a duplicate migration version (`Version001005Date20260430120000` here vs `Version001005Date20260430000000` on dev) — merging would either overwrite shipped code or fail to apply the migration. Resubmitting the truly unique deltas (walkthrough findings, screenshots, sendent-name scrub on the dev versions of the image-widget / link-button-widget proposals) as a smaller follow-up PR. |
3 tasks
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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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
Lands the next batch of dashboard work in 7 logically-split commits:
dashboard_shared,dashboard_ownership_transferred), and aUserDeletedListenerthat cascades cleanup + admin-retention transfer per REQ-SHARE-011/012/013. Includes migrationVersion001005Date20260430120000(tableoc_mydash_dashboard_shares).ResourceController+ResourceServicewith PUT/PATCH multipart support (viaResourceUploadRequestParser), MIME parity validation (ImageMimeValidator), and a typed exception hierarchy.DashboardConfigMenu,DashboardConfigModal,WidgetPickerModal+ Conduction/Sendent brand assets.DashboardService+PermissionService+ frontend store/api updates;appinfobumped to1.0.4-unstable.0..gitignorenow excludes the local sendent vendor extract; openspec proposals scrubbed of explicit competitor name (kept the technical content).mydash-walkthrough/findings.md.Test plan
composer check:strictpasses (PHPCS, PHPMD, Psalm, PHPStan)composer test:unitgreen (new tests forSvgSanitiser,ImageMimeValidator,ResourceService,ResourceServiceSvgIntegrationTest,DashboardShareServiceFollowupsTest,UserDeletedListenerTest)Version001005Date20260430120000applies cleanly on a fresh DB and is idempotent on re-run<script>is stripped; mismatched MIME rejectedDashboardConfigMenuandWidgetPickerModalfrom the dashboard view