386 lines
11 KiB
Markdown
386 lines
11 KiB
Markdown
# 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
|
|
? '<pre class="text-xs font-mono overflow-x-auto bg-gray-50 dark:bg-gray-900 p-4 rounded-lg max-h-96 overflow-y-auto">'
|
|
. htmlspecialchars(json_encode($state, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES))
|
|
. '</pre>'
|
|
: '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) =>
|
|
'<pre class="text-xs font-mono overflow-x-auto bg-gray-50 dark:bg-gray-900 p-4 rounded-lg max-h-96">'
|
|
. htmlspecialchars(json_encode($state, JSON_PRETTY_PRINT))
|
|
. '</pre>'
|
|
)
|
|
->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
|
|
? '<span class="text-warning-600 dark:text-warning-400 font-semibold">⚠️ Large payload (' . number_format($state / 1024, 0) . ' KB) - May impact performance</span>'
|
|
: 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) =>
|
|
'<pre class="text-xs font-mono overflow-x-auto bg-gray-50 dark:bg-gray-900 p-4 rounded-lg max-h-96">'
|
|
. htmlspecialchars(json_encode($state, JSON_PRETTY_PRINT))
|
|
. '</pre>'
|
|
)
|
|
->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
|
|
'<pre class="
|
|
text-xs // Small font for readability
|
|
font-mono // Monospace for JSON
|
|
overflow-x-auto // Horizontal scroll
|
|
bg-gray-50 // Light background
|
|
dark:bg-gray-900 // Dark mode background
|
|
p-4 // Padding (matches Filament sections)
|
|
rounded-lg // Rounded corners
|
|
max-h-96 // Max height (24rem)
|
|
overflow-y-auto // Vertical scroll
|
|
">'
|
|
```
|
|
|
|
---
|
|
|
|
## 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('<pre')
|
|
->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 `<pre>` tag:
|
|
```php
|
|
'<pre class="overflow-x-auto">'
|
|
```
|
|
|
|
---
|
|
|
|
**Status**: ✅ Phase 2 Complete - Ready for Phase 3 implementation
|