## Summary - unify empty-state UX across the six in-scope Filament list pages - move empty-state ownership toward resource `table()` definitions while preserving existing RBAC behavior - add focused Pest coverage for empty-state rendering, CTA outcomes, populated-state regression behavior, and action-surface compliance - add the Spec 122 planning artifacts and product discovery documents used for this pass ## Changed surfaces - `PolicyResource` - `BackupSetResource` - `RestoreRunResource` - `BackupScheduleResource` - `WorkspaceResource` - `AlertDeliveryResource` ## Tests - `vendor/bin/sail artisan test --compact tests/Feature/Filament/EmptyStateConsistencyTest.php` - `vendor/bin/sail artisan test --compact tests/Feature/Filament/Alerts/AlertDeliveryViewerTest.php` - `vendor/bin/sail artisan test --compact tests/Feature/Filament/CreateCtaPlacementTest.php` - `vendor/bin/sail artisan test --compact tests/Feature/PolicySyncStartSurfaceTest.php` - `vendor/bin/sail artisan test --compact tests/Feature/BackupScheduling/BackupScheduleLifecycleAuthorizationTest.php` - `vendor/bin/sail artisan test --compact tests/Feature/Filament/BackupSetUiEnforcementTest.php` - `vendor/bin/sail artisan test --compact tests/Feature/Filament/RestoreRunUiEnforcementTest.php` - `vendor/bin/sail artisan test --compact tests/Feature/Guards/ActionSurfaceContractTest.php` - `vendor/bin/sail bin pint --dirty --format agent` ## Notes - Filament v5 / Livewire v4.0+ compliance is preserved. - Panel provider registration remains unchanged in `bootstrap/providers.php`. - No new globally searchable resources were added. - Destructive actions were not introduced by this pass. - Alert Deliveries is documented as the explicit no-header-action exemption for the empty-state CTA relocation rule. - Manual light/dark visual QA evidence is still expected in the PR/review artifact set for the remaining checklist items (`T018`, `T025`). Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #148
14 KiB
Feature Specification: Empty State Consistency Pass
Feature Branch: 122-empty-state-consistency
Created: 2026-03-08
Status: Ready for Implementation
Input: Spec 122 — Empty State Consistency Pass (Unified empty states across all primary list pages)
Clarifications
Session 2026-03-08
- Q: What should the single empty-state CTA be for the read-only Alert Deliveries list? → A: Use “View alert rules” as the single CTA.
- Q: How should empty-state CTA visibility behave for members who lack the required capability? → A: Preserve existing per-resource behavior (disabled or hidden), but require explanation when shown disabled.
- Q: Where should the final empty-state configuration live? → A: Prefer resource
table()definitions for empty-state heading/description/icon/action, and allow page helpers only when technically required. - Q: How should screenshots and visual QA evidence be handled for this feature? → A: Attach screenshots / visual QA evidence to the PR or review, not as committed repo artifacts.
Spec Scope Fields (mandatory)
- Scope: workspace
- Primary Routes:
- Admin UI list pages: Policies, Backup Sets, Restore Runs, Backup Schedules, Workspaces, Alert Deliveries
- Data Ownership:
- Tenant-owned lists: Policies, Backup Sets, Restore Runs, Backup Schedules
- Workspace-owned / workspace-context lists: Workspaces
- Workspace-context monitoring history list: Alert Deliveries (may include tenant-bound rows; tenant entitlement still applies)
- RBAC:
- Membership isolation: non-members are deny-as-not-found (404 semantics)
- Capability gating: members without the required capability receive authorization denial (403 on execution); UI may show disabled actions with explanatory tooltip
- Empty-state primary actions MUST remain capability-aware and MUST use the existing UI enforcement helpers already used by each module
User Scenarios & Testing (mandatory)
User Story 1 - First-run clarity on empty lists (Priority: P1)
As a first-time admin, I want to immediately understand what each list page represents when it has no data yet, and what my next best action is.
Why this priority: This is the first impression for new tenants/workspaces and for demos.
Independent Test: For each in-scope list page, with zero records, the page renders a complete empty state (icon + heading + description + one primary action).
Acceptance Scenarios:
- Given I open an in-scope list page with no records, When the table renders, Then I see an icon, heading, description, and a single primary action.
- Given I click the primary empty-state action, When I have the required permission, Then I am taken to the intended next step (or the intended operation is queued) without errors.
User Story 2 - Enterprise-grade consistency during evaluation (Priority: P2)
As a product evaluator, I want empty pages to feel intentional and guided, with consistent hierarchy and tone.
Why this priority: In low-data environments, evaluators spend disproportionate time on empty states.
Independent Test: Visual and UI assertions confirm consistent presence and ordering of empty-state elements across all in-scope pages.
Acceptance Scenarios:
- Given I visit each in-scope list page with no records, When I compare the empty states, Then they share consistent structure and enterprise-appropriate wording (no scaffold-like presentation).
User Story 3 - Permission-aware guidance (Priority: P3)
As a workspace/tenant member without a required capability, I want to understand what I’m missing without the UI leaking access outside my membership scope.
Why this priority: Capability-aware UX reduces support load and aligns with RBAC-UX.
Independent Test: With membership but missing capability, the empty-state action is not actionable and explains why; server-side authorization remains enforced.
Acceptance Scenarios:
- Given I am a valid member but lack the capability for the primary action, When I view the empty page, Then the CTA is disabled (or hidden where that’s the existing pattern) and communicates the missing permission.
- Given I am not entitled to the workspace/tenant scope, When I attempt to access the list page, Then the app responds as not found (404 semantics).
Edge Cases
- Empty state must still render correctly in dark mode and light mode.
- Empty state must behave correctly when the tenant context is missing/invalid (records are not shown and the page does not leak data).
- Alert Deliveries list can be empty even when alerts are configured (e.g., no alerts fired yet); copy must set that expectation.
Requirements (mandatory)
Constitution alignment (required): This feature introduces no new external integrations and no new background work. It only adjusts how existing list pages communicate “no records” states and which single next-step action is presented.
Constitution alignment (OPS-UX): This feature MUST NOT change operation UX semantics. Where an empty-state action already queues an operation (e.g., sync), it continues to follow the existing 3-surface feedback contract and uses the canonical operation UX presenter.
Constitution alignment (RBAC-UX): This feature MUST NOT relax authorization. It reuses existing capability gating and server-side authorization. Membership remains deny-as-not-found (404 semantics); missing capability remains 403 on execution.
Constitution alignment (Filament Action Surfaces): This feature modifies list empty states and therefore MUST satisfy the Action Surface Contract for the “ListEmptyState” slot for each in-scope resource.
Constitution alignment (UX-001 — Layout & Information Architecture): Each in-scope list page’s empty state must have a specific title, an explanation, and exactly 1 CTA.
Functional Requirements
- FR-001: Each in-scope primary list page MUST render a complete empty state when there are zero records.
- FR-002: Each empty state MUST include: icon, heading, description, and exactly one primary action.
- FR-003: Empty-state copy MUST be contextual to the module and explain both (a) why it’s empty and (b) the next best action.
- FR-004: Empty-state primary actions MUST remain capability-aware and MUST respect existing UI enforcement rules.
- FR-004a: The feature MUST preserve each resource’s existing CTA visibility model for capability enforcement rather than forcing all empty-state actions into a single visible-disabled or hidden-only pattern.
- FR-004b: When an empty-state CTA is shown disabled for a valid member, it MUST explain the missing permission using the resource’s existing helper text or tooltip pattern.
- FR-005: Empty-state rendering MUST remain correct in both light and dark mode.
- FR-006: Empty-state configuration MUST be defined in a single, consistent place per list page (to prevent drift and scaffold-like inconsistencies).
- FR-006a: Where Filament supports it, empty-state heading, description, icon, and action MUST be defined in the resource
table()configuration. - FR-006b: Page-level empty-state helpers MAY be used only when technically required, and MUST NOT split responsibility in a way that causes drift between heading/description/icon/action definitions.
- FR-007: Out-of-scope resources MUST remain unchanged, including: Finding, Entra Group, Policy Version, Operation Run.
- FR-008: The Alert Deliveries empty state MUST use a single navigational CTA labeled “View alert rules” to direct operators to the configuration surface most likely to explain or resolve an empty history.
- FR-008a: Alert Deliveries is the sole explicit UX-001 relocation exemption for this feature: the
View alert rulesCTA appears only in the empty state and MUST NOT persist as a table-header action once deliveries exist, because the surface remains intentionally read-only and header-action free.
Module-specific empty-state copy (baseline direction)
- Policies: “No policies synced yet. Sync your first tenant to see Intune policies here.”
- Backup Sets: “No backup sets. Create a backup set to start protecting your configurations.”
- Restore Runs: “No restore runs. Start a restoration from a backup set.”
- Backup Schedules: “No schedules configured. Set up automated backups.”
- Workspaces: “No workspaces. Create your first workspace.”
- Alert Deliveries: “No alert deliveries. Deliveries appear automatically when alert rules fire.”
Clarified CTA direction
- Alert Deliveries: use a single CTA labeled “View alert rules”.
UI Action Matrix (mandatory when Filament is changed)
| Surface | Location | Header Actions | Inspect Affordance (List/Table) | Row Actions (max 2 visible) | Bulk Actions (grouped) | Empty-State CTA(s) | View Header Actions | Create/Edit Save+Cancel | Audit log? | Notes / Exemptions |
|---|---|---|---|---|---|---|---|---|---|---|
| Policy list | Admin UI — Policies list page | “Sync from Intune” | View action | View + “More” (as-is) | As-is | “Sync from Intune” | As-is | N/A (read-only details) | No | CTA continues to queue the existing sync operation; no change to operation UX semantics. |
| Backup Sets list | Admin UI — Backup Sets list page | “Create” (existing behavior) | View action | View + “More” | Yes | “Create backup set” | As-is | Create/Edit as-is | Yes (existing audit logger) | Empty state becomes contextual and guided; CTA remains capability gated. |
| Restore Runs list | Admin UI — Restore Runs list page | “Create” (existing behavior) | As-is | As-is | Yes | “New restore run” | As-is | Create wizard as-is | Yes (existing audit logger) | Empty state becomes contextual and guided; CTA remains capability gated. |
| Backup Schedules list | Admin UI — Backup Schedules list page | “New backup schedule” (existing behavior) | Clickable row | View/Edit as-is | Yes | “New backup schedule” | Edit page header as-is | Save/Cancel as-is | No | CTA remains capability-aware; disabled state explains missing permission. |
| Workspaces list | Admin UI — Workspaces list page | “New workspace” (existing behavior) | View action | View/Edit as-is | No | “New workspace” | As-is | Save/Cancel as-is | No | Workspace membership isolation remains deny-as-not-found. |
| Alert Deliveries list | Monitoring — Alert Deliveries list page | None (read-only) | Clickable row | None | None | “View alert rules” (navigation) | View page (read-only) | N/A | No | Adds guided empty state despite read-only list; CTA is a next-step navigation to alert rule configuration, not a mutation. Explicit UX-001 exemption: this CTA does not relocate to the header when records exist. |
RBAC clarification
- Preserve each resource’s current capability-aware CTA behavior (disabled vs hidden) rather than standardizing all empty-state actions to one pattern.
Placement clarification
- Prefer resource
table()definitions for empty-state heading, description, icon, and action; use page helpers only when technically required.
Visual QA evidence clarification
- Screenshot and dark-mode visual QA evidence for affected resources must be attached to the PR or review record, not committed into the repository.
Explicit exemptions
- Alert Deliveries header-action exemption: Alert Deliveries remains a read-only monitoring history surface with no persistent header action. Its single CTA (
View alert rules) exists only while the list is empty. Once deliveries exist, the CTA does not relocate to the header; this is an explicit UX-001 exemption for this feature and must remain documented in the PR or review.
Acceptance Criteria / Definition of Done
- All in-scope resources render a full empty state when the table has no records.
- Each empty state includes icon, heading, description, and exactly one primary CTA.
- Empty-state actions preserve existing RBAC/UI-enforcement behavior.
- Visual review confirms centered, intentional hierarchy consistent with the baseline reference pattern.
- Dark mode renders correctly for every affected list page.
- Populated-table behavior remains unchanged.
- Screenshot or visual QA evidence for all affected resources is attached to the PR or review artifact set, rather than committed to the repository.
Testing Requirements
- Feature/UI test per in-scope resource for empty table rendering.
- Feature/UI test coverage for each in-scope CTA outcome so empty-state actions either navigate to the intended next step or queue the intended existing operation.
- Permission test coverage to ensure CTA visibility or disabled state remains aligned with existing resource behavior.
- Manual visual verification in light and dark mode for every affected list page.
- Automated regression coverage for representative populated-table behavior, including CTA relocation for create-capable surfaces and the documented no-header-action exemption for Alert Deliveries.
- Smoke test confirming populated resources still render their standard tables and existing actions.
- PR/review attachment checklist confirming screenshots or equivalent visual QA evidence were captured for all affected resources.
Success Criteria (mandatory)
Measurable Outcomes
- SC-001: 100% of in-scope list pages display icon + heading + description + 1 CTA when empty.
- SC-002: In a first-run demo with no records, an evaluator can correctly identify the purpose and next action on each in-scope page without guidance.
- SC-003: Users without capability can still understand the required permission from the disabled/hidden state messaging, without any cross-scope leakage.
- SC-004: No regressions: populated tables continue to render their existing columns, actions, and behaviors unchanged.