## 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
143 lines
5.3 KiB
Markdown
143 lines
5.3 KiB
Markdown
# Data Model: Empty State Consistency Pass
|
|
|
|
**Feature**: 122-empty-state-consistency | **Date**: 2026-03-08
|
|
|
|
## Overview
|
|
|
|
This feature does not add or modify database tables. It standardizes the UI contract for six existing Filament list surfaces when their datasets are empty.
|
|
|
|
The feature operates on existing resource/page configuration and existing authorization decisions.
|
|
|
|
## Existing UI Contract Concepts
|
|
|
|
### EmptyStateSurface
|
|
|
|
| Attribute | Type | Notes |
|
|
|-----------|------|-------|
|
|
| `resource` | string | Filament resource owning the list surface |
|
|
| `ownership_scope` | enum | `tenant`, `workspace`, or `workspace-context monitoring` |
|
|
| `heading` | string | Specific, contextual title for the empty state |
|
|
| `description` | string | Short explanation of why the list is empty and what to do next |
|
|
| `icon` | string | Heroicon name matching the module semantics |
|
|
| `primary_cta_label` | string | Exactly one user-facing CTA label |
|
|
| `primary_cta_type` | enum | `create`, `navigate`, or `queue-operation` |
|
|
| `capability_behavior` | enum | `disabled-with-explanation` or `hidden`, preserved per existing resource behavior |
|
|
| `definition_source` | enum | Prefer `resource.table`; fallback `list-page helper` only when required |
|
|
|
|
### EmptyStatePrimaryAction
|
|
|
|
| Attribute | Type | Notes |
|
|
|-----------|------|-------|
|
|
| `label` | string | Single guided next-step action |
|
|
| `target` | string | Destination page or mounted Filament action |
|
|
| `enforcement_helper` | string | Existing `UiEnforcement` / `WorkspaceUiEnforcement` pattern when applicable |
|
|
| `capability` | string/null | Existing canonical capability required to execute the action |
|
|
| `header_relocation_rule` | string | Same CTA appears in the table header when records exist, unless the surface has an explicit documented exemption |
|
|
|
|
### VisualQaEvidence
|
|
|
|
| Attribute | Type | Notes |
|
|
|-----------|------|-------|
|
|
| `surface` | string | One of the six in-scope list pages |
|
|
| `mode` | enum | `light` or `dark` |
|
|
| `artifact_location` | string | PR/review attachment reference; not committed repo data |
|
|
| `review_result` | enum | `pass` or `follow-up` |
|
|
|
|
## In-Scope Surface Instances
|
|
|
|
### Policy list
|
|
|
|
| Field | Value |
|
|
|------|-------|
|
|
| Scope | Tenant-owned |
|
|
| Empty reason | Policies have not been synced for the tenant yet |
|
|
| Primary CTA type | Queue operation |
|
|
| Primary CTA label | `Sync from Intune` |
|
|
| Existing capability behavior | Capability-aware action using existing tenant sync enforcement |
|
|
|
|
### Backup Sets list
|
|
|
|
| Field | Value |
|
|
|------|-------|
|
|
| Scope | Tenant-owned |
|
|
| Empty reason | No backup sets have been created yet |
|
|
| Primary CTA type | Create |
|
|
| Primary CTA label | `Create backup set` |
|
|
| Existing capability behavior | Preserved from current create action behavior |
|
|
|
|
### Restore Runs list
|
|
|
|
| Field | Value |
|
|
|------|-------|
|
|
| Scope | Tenant-owned |
|
|
| Empty reason | No restore workflows have been initiated yet |
|
|
| Primary CTA type | Create |
|
|
| Primary CTA label | `New restore run` |
|
|
| Existing capability behavior | Preserved from current create action behavior |
|
|
|
|
### Backup Schedules list
|
|
|
|
| Field | Value |
|
|
|------|-------|
|
|
| Scope | Tenant-owned |
|
|
| Empty reason | No automated backup schedules are configured |
|
|
| Primary CTA type | Create |
|
|
| Primary CTA label | `New backup schedule` |
|
|
| Existing capability behavior | Disabled-with-tooltip for valid members without schedule-manage capability |
|
|
|
|
### Workspaces list
|
|
|
|
| Field | Value |
|
|
|------|-------|
|
|
| Scope | Workspace-owned |
|
|
| Empty reason | No active workspaces are available to the member |
|
|
| Primary CTA type | Create |
|
|
| Primary CTA label | `New workspace` |
|
|
| Existing capability behavior | Preserved from current workspace create action behavior |
|
|
|
|
### Alert Deliveries list
|
|
|
|
| Field | Value |
|
|
|------|-------|
|
|
| Scope | Workspace-context monitoring |
|
|
| Empty reason | No alert deliveries have occurred yet |
|
|
| Primary CTA type | Navigate |
|
|
| Primary CTA label | `View alert rules` |
|
|
| Existing capability behavior | Read-only list; CTA navigates to the configuration surface most likely to explain the empty history |
|
|
| Header relocation rule | Explicit exemption: CTA appears only while the list is empty; non-empty state remains header-action free |
|
|
|
|
## Relationships
|
|
|
|
```text
|
|
EmptyStateSurface
|
|
-> has one EmptyStatePrimaryAction
|
|
-> belongs to one existing Filament resource list page
|
|
-> is validated by programmatic tests
|
|
-> is visually confirmed by PR/review evidence in light and dark mode
|
|
```
|
|
|
|
## State Transition
|
|
|
|
```text
|
|
[0 records on list page]
|
|
-> render complete empty-state contract
|
|
(icon + heading + description + exactly 1 CTA)
|
|
-> user follows CTA or waits for data-producing event
|
|
[records exist]
|
|
-> empty state disappears
|
|
-> primary CTA relocates to the table header when applicable
|
|
-> Alert Deliveries remains header-action free by explicit exemption
|
|
-> populated table behavior remains unchanged
|
|
```
|
|
|
|
## Validation Rules
|
|
|
|
| Rule | Result |
|
|
|------|--------|
|
|
| Exactly one empty-state CTA per in-scope list | Required |
|
|
| Empty-state CTA must preserve existing authorization behavior | Required |
|
|
| Non-members continue to receive 404 semantics | Required |
|
|
| Members missing capability continue to get 403 on execution | Required |
|
|
| Alert Deliveries CTA is navigational, not mutating | Required |
|
|
| No schema, route, or Graph contract changes | Required |
|