# 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