# Shared Diff Presentation Foundation ## Purpose Use the shared diff presentation foundation when a screen already has simple before/after data and needs: - one consistent state vocabulary (`changed`, `unchanged`, `added`, `removed`) - shared summary badges - shared row rendering - inline list add/remove rendering - one display policy for nulls, booleans, scalars, lists, and compact structured values This foundation is presentation-only. It does not compare domain records for you, does not fetch data, and does not replace domain-specific diff rules. ## Use It When - a consumer already has keyed baseline/current values - the comparison can be represented as row-level fields or simple scalar lists - the screen benefits from reusable summary and row partials without needing a new Filament component type ## Do Not Use It When - the screen needs token-level or line-level diff behavior - the layout would become less clear if flattened into generic rows - the screen relies on domain-specific compare semantics that are not simple value presentation The current specialized renderers stay specialized unless a later spec chooses otherwise: - `resources/views/filament/infolists/entries/normalized-diff.blade.php` - `resources/views/filament/infolists/entries/assignments-diff.blade.php` - `resources/views/filament/infolists/entries/scope-tags-diff.blade.php` ## Presenter Usage ```php use App\Support\Diff\DiffPresenter; $presentation = app(DiffPresenter::class)->present( baseline: $baseline, current: $current, changedKeys: $changedKeys, labels: $labels, meta: $meta, ); ``` Expected input shape: - `baseline`: keyed prior values - `current`: keyed current values - `changedKeys`: optional presenter hint for keys that should be treated as changed - `labels`: optional display labels keyed by field key - `meta`: optional view-safe metadata keyed by field key `DiffPresenter` returns a `DiffPresentation` containing: - `summary`: `DiffSummary` - `rows`: ordered `DiffRow` instances ## Blade Usage ```blade @include('filament.partials.diff.summary-badges', [ 'summary' => $presentation->summary, ]) @foreach ($presentation->rows as $row) @include('filament.partials.diff.row', [ 'row' => $row, 'compact' => false, 'dimUnchanged' => true, ]) @endforeach ``` `compact` reduces spacing for dense layouts. `dimUnchanged` keeps unchanged content quieter than meaningful changes. ## RBAC Role Definition Adoption `resources/views/filament/infolists/entries/rbac-role-definition-diff.blade.php` is the first concrete consumer of the shared diff foundation. Its consumer-local builder lives in `app/Support/Diff/RbacRoleDefinitionDiffBuilder.php` and is responsible for: - preserving the existing RBAC evidence payload as the input contract - adding fallback rows for `Role source` and `Permission blocks` when side metadata exists - keeping top-level role metadata ahead of permission-block detail in a deterministic order - designating these RBAC list-like keys for inline add/remove rendering: - `Role definition > Scope tag IDs` - `Permission block * > Allowed actions` - `Permission block * > Denied actions` - `Permission block * > Conditions` Consumer-local choices for the first RBAC pass: - unchanged rows stay visible but muted through `dimUnchanged` - one-sided RBAC rows render through the shared `added` and `removed` states - no local “show only changes” toggle is shipped in this first pass ## Standalone Stringifier Usage If a specialized renderer should not adopt `DiffPresenter`, it can still reuse `ValueStringifier`: ```php use App\Support\Diff\ValueStringifier; $displayValue = app(ValueStringifier::class)->stringify($value); ``` Current shared formatting rules are: - `null` -> `—` - `true` / `false` -> `Enabled` / `Disabled` - empty string -> `""` - empty list -> `[]` - simple scalar lists -> comma-separated values - structured values -> compact JSON ## Adoption Checklist Before adopting the foundation in a consumer spec: 1. Confirm the consumer already owns authorization and compare-shape decisions. 2. Confirm the data is simple row/list presentation, not specialized diff logic. 3. Add or update Pest coverage for presenter output and rendered partial output. 4. Keep destructive actions, routes, and resource/global-search behavior unchanged unless the consumer spec explicitly covers them. See `specs/141-shared-diff-presentation-foundation/quickstart.md` for the matching feature-level quickstart.