Skip to content

Make the Dashboard always reachable and gate its widgets by permission #1099

Description

@sfmskywalker

Problem

The Dashboard is the landing page (/), but it is all-or-nothing: the page and its menu item require dashboard:view. A user without that permission can't use the landing page at all.

Since #1093 such a user is no longer shown access-denied after sign-in. They are sent to the first page they can open, or shown "No pages are available for your role" when there is none. That removes the dead end. It still leaves those users without a home page, and the Dashboard can't show a restricted user the parts that are relevant to them.

Idea

Every signed-in user can open the Dashboard. Permission is decided per widget: modules contribute widgets, and the Dashboard shows a user only the widgets they are allowed to see. Whether a widget the user can't see is hidden or shown disabled is still to be decided.

Current state

  • Pages/Index.razor and DashboardMenu require dashboard:view.
  • DashboardWidgetDescriptor has no permission metadata. It has an id, a zone, an order, a component type, and an optional backend capability. A widget is visible whenever a snapshot is loaded.
  • All built-in widgets (metrics, trend, recent activity, needs attention, hotspots) draw from one snapshot, which comes from core's dashboard endpoints: overview, trends, recent activity, needs attention and hotspots.
  • Every one of those core endpoints requires the single dashboard:view permission.
  • So today one permission gates everything. Per-widget gating in Studio needs either per-widget permissions that core also enforces, or widgets mapped onto the domain permissions of the data they show, for example workflow-instance metrics onto workflows/instances:view.

Questions to settle

  1. Hidden or disabled? Does a widget the user can't view disappear, or show as a locked placeholder?
  2. Which permission gates a widget? A new permission per dashboard widget, or the domain permission of the data the widget shows.
  3. What is dashboard:view for afterwards? Dropped, kept as "see every widget", or kept to gate only the built-in operational widgets.
  4. What does a user with no visible widgets see? An empty-state message, a welcome or shortcut panel, or the feat(shell): send users who can't view the landing page to their first accessible page #1093 redirect to their first accessible page.
  5. Core: the snapshot endpoints have to enforce the same split, or Studio's gating would be cosmetic.
  6. Landing redirect (feat(shell): send users who can't view the landing page to their first accessible page #1093): once the Dashboard is always reachable, the redirect and the "no pages" notice are only needed if an empty Dashboard is not an acceptable landing page.

Acceptance criteria (draft, to refine after the design is settled)

  • Any signed-in user can open / without an access-denied message.
  • Each widget declares the permission it needs, and third-party widgets can do the same.
  • A user sees only the widgets they are permitted to see, or sees the rest clearly marked as unavailable.
  • Core refuses the data behind a widget the user isn't permitted to see.
  • A user with no permitted widgets gets a deliberate experience, not a blank page.

Activity

  1. sfmskywalker commented on Sep 30, 2026

    @sfmskywalker
    MemberAuthor

    Design decisions (2026-09-30)

    Settled with the maintainer:

    1. A widget the user can't view is hidden, not shown disabled. This matches how navigation and in-page actions already behave, and keeps the page clean for restricted roles.
    2. A widget is gated by the permission of the data it shows. There is no separate set of per-widget permissions. For example, workflow-instance metrics, trends and recent activity need workflows/instances:view.
      • DashboardWidgetDescriptor gains required permissions, so third-party widgets declare theirs the same way.
      • Core must enforce the same rule on the dashboard data endpoints, so the gating is real and not only cosmetic.
    3. A user with no visible widgets gets a welcome panel with shortcuts to the pages they can open. It uses the navigation order from feat(shell): send users who can't view the landing page to their first accessible page #1093's MenuServiceExtensions, and replaces the landing redirect and the "no pages" notice from feat(shell): send users who can't view the landing page to their first accessible page #1093.

    Consequences:

    • The Dashboard page and its menu item no longer require dashboard:view. Every signed-in user can open /.
    • dashboard:view remains the permission for the built-in operational overview, so existing roles keep working. How it maps onto the data permissions is part of the core change.
    • This needs a companion elsa-core issue for the dashboard endpoints.
  2. added this to the 3.9 milestone on Sep 30, 2026
  3. sfmskywalker commented on Sep 30, 2026

    @sfmskywalker
    MemberAuthor

    Implementation plan

    The core side is elsa-workflows/elsa-core#8561. dashboard:view still covers everything. Each overview section, and each single-purpose endpoint, also accepts the permission of its data. The overview marks a section the caller can't read as Capability = Unauthorized instead of refusing the whole call.

    Studio:

    • The Dashboard page and its menu item no longer require dashboard:view, so every signed-in user can open /.
    • DashboardWidgetDescriptor and AddDashboardWidget gain the permissions a widget needs. A widget is visible when the user holds any of them, and a widget that declares none is visible to everyone.
      • Built-in widgets declare dashboard:view plus the permission of their data: workflows/instances:view for instance metrics, trends, activity, findings and hotspots; workflows/runtime:view for runtime status; the diagnostics/* permissions for the log summaries.
    • The page only calls the endpoints its visible widgets need, and treats an Unauthorized section as absent, so a restricted user never sees a 403.
    • With no visible widget, the page shows a welcome panel with shortcuts to the pages the user can open. It uses the navigation order from MenuServiceExtensions.
    • The Dashboard no longer triggers feat(shell): send users who can't view the landing page to their first accessible page #1093's landing redirect, because it isn't gated any more. PermissionPageGuard keeps that behaviour as a generic fallback for hosts whose / is some other gated page.
  4. sfmskywalker commented on Sep 30, 2026

    @sfmskywalker
    MemberAuthor

    Picking this up — autonomous delivery started.

  5. sfmskywalker commented on Oct 1, 2026

    @sfmskywalker
    MemberAuthor

    Delivered in #1103 (bd44366) on release/3.9.0, paired with elsa-workflows/elsa-core#8562.

    • Every signed-in user can open the Dashboard.
    • Each widget is shown only to users holding any of its declared permissions: dashboard:view plus the permission of its data. Widgets the user can't see are hidden.
    • The page loads only the data its visible widgets need. It leaves out sections the backend marks Unauthorized, and keeps what loaded when a secondary endpoint refuses.
    • Runtime status shows with dashboard:view or workflows/runtime:view.
    • A user with no visible widget gets a welcome panel with shortcuts to the pages they can open.
    • Third-party widgets declare their permissions through the new AddDashboardWidget overload. See the Dashboard README.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions