# Quickstart: Feature 002 - Filament JSON UI **Feature**: 002-filament-json **Date**: 2025-12-13 **Status**: Implementation Guide --- ## Installation ### 1. Install Package (T001) ✅ Complete ```bash cd /Users/ahmeddarrazi/Documents/projects/TenantAtlas ./vendor/bin/sail composer require pepperfm/filament-json:^4 ``` **Result**: Package installed, assets published to `public/css/pepperfm/filament-json/` --- ## Usage Examples ### Basic Integration (MVP - Phase 3) **Location**: `app/Filament/Resources/PolicyResource/Pages/ViewPolicy.php` #### Option A: Simple Pretty-Print JSON (Fastest MVP) ```php use Filament\Infolists\Components\TextEntry; use Filament\Infolists\Components\Section; protected function getSchema(): array { return [ Section::make('Policy Details') ->schema([ TextEntry::make('name'), TextEntry::make('platform'), // ... other fields ]), Section::make('Policy Snapshot') ->schema([ TextEntry::make('snapshot') ->label('JSON Configuration') ->formatStateUsing(fn ($state) => $state ? '
' 
                                . htmlspecialchars(json_encode($state, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)) 
                                . '
' : 'No snapshot available' ) ->html() ->columnSpanFull() ->copyable() ->copyableState(fn ($state) => json_encode($state, JSON_PRETTY_PRINT)) ->copyMessage('JSON copied to clipboard!') ->helperText('Click the copy icon to copy the full JSON configuration.'), ]) ->collapsible() ->collapsed(false), ]; } ``` **Features**: - ✅ Pretty-printed JSON with monospace font - ✅ Copy-to-clipboard via Filament's built-in copyable() - ✅ Scrollable container (max height 24rem) - ✅ Dark mode support - ✅ Collapsible section - ✅ Helper text for user guidance --- ### With Tabs (Phase 4 - Settings Catalog) ```php use Filament\Infolists\Components\Tabs; use Filament\Infolists\Components\Tabs\Tab; protected function getSchema(): array { return [ Tabs::make('Policy Data') ->tabs([ Tab::make('Settings') ->visible(fn ($record) => $record->odatatype === 'settingsCatalogPolicy') ->schema([ // Existing settings table component ViewEntry::make('settings_table') ->view('filament.infolists.entries.settings-table'), ]), Tab::make('JSON') ->schema([ TextEntry::make('snapshot') ->label('Full Policy JSON') ->formatStateUsing(fn ($state) => '
' 
                                    . htmlspecialchars(json_encode($state, JSON_PRETTY_PRINT)) 
                                    . '
' ) ->html() ->columnSpanFull() ->copyable() ->copyableState(fn ($state) => json_encode($state, JSON_PRETTY_PRINT)), ]), ]), ]; } ``` --- ### Large Payload Warning (Phase 4 - T014) ```php use Filament\Infolists\Components\TextEntry; use Filament\Support\Colors\Color; protected function getSchema(): array { return [ Section::make('Policy Snapshot') ->schema([ // Warning badge for large payloads TextEntry::make('snapshot_size') ->label('Payload Size') ->state(fn ($record) => strlen(json_encode($record->snapshot ?? []))) ->formatStateUsing(fn ($state) => $state > 512000 ? '⚠️ Large payload (' . number_format($state / 1024, 0) . ' KB) - May impact performance' : number_format($state / 1024, 1) . ' KB' ) ->html() ->visible(fn ($record) => strlen(json_encode($record->snapshot ?? [])) > 512000), TextEntry::make('snapshot') ->label('JSON Configuration') ->formatStateUsing(fn ($state) => '
' 
                            . htmlspecialchars(json_encode($state, JSON_PRETTY_PRINT)) 
                            . '
' ) ->html() ->columnSpanFull() ->copyable(), ]) ->collapsed(fn ($record) => strlen(json_encode($record->snapshot ?? [])) > 512000), // Auto-collapse if large ]; } ``` **Features**: - ✅ Size detection: `strlen(json_encode($record->snapshot))` > 512,000 bytes (500 KB) - ✅ Warning badge for large payloads - ✅ Auto-collapse section if payload is large - ✅ Formatted size display (KB) --- ## Configuration ### Payload Size Thresholds (NFR-036.1) ```php // In PolicyResource ViewPolicy page const INLINE_VIEWER_MAX_BYTES = 512000; // 500 KB soft limit protected function isLargePayload($record): bool { return strlen(json_encode($record->snapshot ?? [])) > self::INLINE_VIEWER_MAX_BYTES; } ``` ### Styling Consistency (NFR-036.5) Match Filament section padding using Tailwind classes: ```php '
'
```

---

## Testing

### Manual QA Checklist

```bash
# 1. Open Policy View page
php artisan serve  # or ./vendor/bin/sail up

# Navigate to: /admin/policies/{id}
```

**Test Scenarios**:

1. **Small Policy (<500 KB)**:
   - ✅ JSON renders inline without scroll
   - ✅ Copy button copies full JSON
   - ✅ Section not collapsed by default

2. **Large Policy (>500 KB)**:
   - ✅ Warning badge shows
   - ✅ Section collapsed by default
   - ✅ Copy button still functional

3. **Settings Catalog Policy**:
   - ✅ "Settings" tab shows table
   - ✅ "JSON" tab shows full snapshot
   - ✅ Tab switching works without layout breaks

4. **Dark Mode**:
   - ✅ Switch to dark mode
   - ✅ JSON background is dark gray
   - ✅ Text is readable (light color)

### Feature Tests (Optional)

```bash
./vendor/bin/sail artisan test --filter=PolicyResourceViewTest
```

**Test Example**:

```php
// tests/Feature/Filament/PolicyResourceViewTest.php

it('displays JSON viewer on policy view page', function () {
    $policy = Policy::factory()->create([
        'snapshot' => ['test' => 'data'],
    ]);
    
    livewire(ViewPolicy::class, ['record' => $policy->id])
        ->assertSeeHtml('assertSeeHtml('font-mono')
        ->assertSee('JSON Configuration');
});

it('shows large payload warning for policies over 500 KB', function () {
    $largeSnapshot = array_fill(0, 10000, ['key' => str_repeat('x', 100)]);
    $policy = Policy::factory()->create(['snapshot' => $largeSnapshot]);
    
    livewire(ViewPolicy::class, ['record' => $policy->id])
        ->assertSeeHtml('⚠️ Large payload')
        ->assertSeeHtml('KB');
});
```

### Browser Tests (Pest 4)

```php
// tests/Browser/PolicyJsonViewerTest.php

it('allows copying JSON to clipboard', function () {
    $policy = Policy::factory()->create();
    
    visit('/admin/policies/' . $policy->id)
        ->assertSee('JSON Configuration')
        ->click('[wire:click="copyJsonToClipboard"]')
        ->assertSee('JSON copied to clipboard!');
});
```

---

## Deployment Notes

### Assets

✅ **Assets committed to repository** (12 KB total):
- `public/css/pepperfm/filament-json/filament-json-styles.css`

**No build steps required** - assets are already published and ready.

### Staging Validation

```bash
# On Staging server (Dokploy deployment)
1. Deploy via git push
2. Run migrations (if any): php artisan migrate
3. Clear cache: php artisan config:clear && php artisan view:clear
4. Test: Open /admin/policies/{id} and verify JSON viewer renders
```

### Rollback Plan

If issues occur:

```bash
# Remove package
./vendor/bin/sail composer remove pepperfm/filament-json

# Revert ViewPolicy.php changes
git checkout HEAD -- app/Filament/Resources/PolicyResource/Pages/ViewPolicy.php

# Clear cache
php artisan config:clear
```

---

## Performance Considerations

### Rendering 500 KB JSON

- **Inline rendering**: Browser handles JSON display natively (fast)
- **Copy action**: JavaScript clipboard API (async, non-blocking)
- **No server overhead**: JSON is already in `$record->snapshot`

### Large Payload Strategy

For payloads >1 MB:
- Auto-collapse section (requires manual expand)
- Optional: Add download action instead of copy

```php
use Filament\Infolists\Components\Actions\Action;

Actions\Action::make('downloadSnapshot')
    ->label('Download JSON')
    ->icon('heroicon-o-arrow-down-tray')
    ->action(function ($record) {
        return response()->streamDownload(function () use ($record) {
            echo json_encode($record->snapshot, JSON_PRETTY_PRINT);
        }, "policy-{$record->id}-snapshot.json");
    })
    ->visible(fn ($record) => strlen(json_encode($record->snapshot ?? [])) > 1048576), // >1 MB
```

---

## Next Steps

1. ✅ Phase 1 complete: Package installed, assets documented
2. ✅ Phase 2 complete: Research findings documented
3. **Phase 3**: Implement User Story 1 (T007-T012) - Basic JSON viewer
4. **Phase 4**: Implement User Story 2 (T013-T015) - Tabs for Settings Catalog
5. **Phase 5**: Implement User Story 3 (T016-T018) - Copy/download actions

**Estimated time remaining**: 3-4 hours for Phases 3-8

---

## Troubleshooting

### Issue: JSON not rendering

**Solution**: Verify `$record->snapshot` is not null:
```php
->formatStateUsing(fn ($state) => $state ? /* render JSON */ : 'No snapshot available')
```

### Issue: Copy button not working

**Solution**: Ensure `->copyable()` and `->copyableState()` are both set:
```php
->copyable()
->copyableState(fn ($state) => json_encode($state, JSON_PRETTY_PRINT))
```

### Issue: Horizontal overflow

**Solution**: Add `overflow-x-auto` class to `
` tag:
```php
'
'
```

---

**Status**: ✅ Phase 2 Complete - Ready for Phase 3 implementation