# Filament Table Standard ## Standard TenantPilot standardizes production Filament list surfaces with a convention-first model: - Primary: searchable identifier or record title that anchors the row. - Context: status, ownership, recency, and counts needed for a normal scan. - Detail: technical IDs, secondary timestamps, verbose metadata, and low-frequency troubleshooting fields. ## Required Rules - Every production table defines an explicit default sort unless a documented exception exists. - Every production table provides a domain-specific empty state heading and description. - General-purpose tables should expose seven or fewer columns by default unless density is part of the job. - Primary identifiers should be searchable and sortable when query-safe. - Technical identifiers and secondary metadata should be toggleable and hidden by default where practical. - Resource lists in the critical set persist search, sort, and filters in session. - Existing action surfaces, RBAC behavior, confirmations, and centralized badge semantics stay unchanged. ## Pagination Profiles | Surface | Page sizes | Default | |---|---|---| | Resource | `25, 50, 100` | `25` | | Relation manager | `10, 25, 50` | `10` | | Widget | `10` | `10` | | Picker | `25, 50, 100` | `25` | | Custom page | `25, 50, all` | `25` unless a page overrides it explicitly | Implementation uses [TablePaginationProfiles.php](/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Support/Filament/TablePaginationProfiles.php). ## Timestamp, Null, and ID Rules - Prefer `->since()` for scan-first timestamps unless exact chronology is the primary task. - Use `—` for missing values unless the domain needs a more specific placeholder. - Long identifiers should remain copyable and readable without dominating the default layout. - Prefer monospaced styling and tooltips for truncated technical identifiers. ## Review Checklist - Primary column is obvious and query-safe. - Default sort matches the table’s operational purpose. - Empty-state copy explains what the list is waiting for. - Hidden detail can be revealed in one toggle or one drill-in. - Pagination profile matches the table class. - Critical resource lists declare session persistence. - No destructive action lost its confirmation or authorization guard. ## Rollout Audit ### Persistence Surfaces The following resource lists must persist search, sort, and filters in session: - `TenantResource` - `PolicyResource` - `BackupSetResource` - `BackupScheduleResource` - `ProviderConnectionResource` - `FindingResource` - `OperationRunResource` ### Documented Exceptions - `RecentDriftFindings` and `RecentOperations` do not add table search because dashboard widgets are glance surfaces, not investigative workbenches. - `Directory/Workspaces` keeps computed health and recent-failure metrics non-sortable and non-searchable because those values are derived per row. - `InventoryCoverage` uses the custom-page pagination profile but keeps the broader `all` option and a `50`-row default because operators sometimes need a full matrix pass. - Picker tables keep workflow-local search only; they do not persist state in session. ### Surface Inventory | Surface | Class | Pagination | Default sort | Empty state | Persistence | Notes | |---|---|---|---|---|---|---| | Tenant list | `resource` | resource | `name asc` | yes | yes | Workspace-scoped create CTA remains in list page | | Policy list | `resource` | resource | `display_name asc` | yes | yes | Sync CTA remains list-local | | Backup set list | `resource` | resource | `created_at desc` | yes | yes | Create CTA remains list-local | | Backup schedule list | `resource` | resource | `next_run_at asc` | yes | yes | Create CTA remains list-local | | Provider connections | `resource` | resource | `display_name asc` | yes | yes | Empty-state CTA remains tenant-aware | | Findings | `resource` | resource | `created_at desc` | yes | yes | Open filter remains the default | | Monitoring operations | `resource-backed page` | resource | `created_at desc` | yes | yes | Canonical operations view uses `OperationRunResource::table()` | | Entra groups | `resource` | resource | `display_name asc` | yes | no | Directory browse remains read-only | | Alert deliveries | `resource` | resource | `id desc` | yes | no | Delivery history stays read-only | | Alert rules | `resource` | resource | `name asc` | yes | no | Rule actions remain explicit per row | | Alert destinations | `resource` | resource | `name asc` | yes | no | Destination test/send actions remain unchanged | | Baseline profiles | `resource` | resource | `name asc` | yes | no | Create CTA remains list-local | | Baseline snapshots | `resource` | resource | `captured_at desc` | yes | no | Snapshot browsing remains read-only | | Inventory items | `resource` | resource | `last_seen_at desc` | yes | no | Scan-first recency view | | Policy versions resource | `resource` | resource | `captured_at desc` | yes | no | Version history remains inspectable and immutable | | Review packs | `resource` | resource | `created_at desc` | yes | no | Review workflow actions unchanged | | Workspace resource | `resource` | resource | `name asc` | yes | no | Workspace create CTA remains list-local | | Backup items | `relation_manager` | relation manager | `policy.display_name asc` | yes | no | Action semantics unchanged | | Policy versions | `relation_manager` | relation manager | `version_number desc` | yes | no | Existing relation query preserved | | Backup schedule operation runs | `relation_manager` | relation manager | `created_at desc` | yes | no | Existing record view preserved | | Tenant memberships | `relation_manager` | relation manager | `created_at desc` | yes | no | Role management unchanged | | Workspace memberships | `relation_manager` | relation manager | `created_at desc` | yes | no | Role management unchanged | | Baseline tenant assignments | `relation_manager` | relation manager | `created_at desc` | yes | no | Assignment action unchanged | | Inventory coverage | `custom_page` | custom page | `label asc` | yes | no | Keeps `all` pagination option | | System directory tenants | `custom_page` | custom page | `name asc` | yes | no | Search stays on meaningful identity fields | | System directory workspaces | `custom_page` | custom page | `name asc` | yes | no | Computed metrics remain exceptions | | Ops runs | `custom_page` | custom page | `id desc` | yes | no | Platform triage actions unchanged | | Ops failures | `custom_page` | custom page | `id desc` | yes | no | Platform triage actions unchanged | | Ops stuck | `custom_page` | custom page | `id desc` | yes | no | Platform triage actions unchanged | | Access logs | `custom_page` | custom page | `recorded_at desc` | yes | no | Read-only operational surface | | Repair workspace owners | `custom_page` | custom page | `name asc` | yes | no | Repair action unchanged | | Recent drift findings | `widget` | widget | `created_at desc` | yes | no | No search by design | | Recent operations | `widget` | widget | `created_at desc` | yes | no | No search by design | | Backup set policy picker | `picker` | picker | `display_name asc` | yes | no | Workflow-local search only | | Entra group picker | `picker` | picker | `display_name asc` | yes | no | Workflow-local search only | | Settings catalog table | `picker` | picker | `definition asc` | yes | no | Workflow-local search only |