isAllowed(); } public static function canView(Model $record): bool { $tenant = Filament::getTenant(); if (! $tenant instanceof Tenant) { return false; } if (! UiEnforcement::for(Capabilities::TENANT_VIEW)->isAllowed()) { return false; } if ($record instanceof InventorySyncRun) { return (int) $record->tenant_id === (int) $tenant->getKey(); } return true; } public static function getNavigationLabel(): string { return 'Sync History'; } public static function form(Schema $schema): Schema { return $schema; } public static function infolist(Schema $schema): Schema { return $schema ->schema([ Section::make('Legacy run view') ->description('Canonical monitoring is now available in Monitoring → Operations.') ->schema([ TextEntry::make('canonical_view') ->label('Canonical view') ->state('View in Operations') ->url(fn (InventorySyncRun $record): string => OperationRunLinks::index(Tenant::current() ?? $record->tenant)) ->badge() ->color('primary'), ]) ->columnSpanFull(), Section::make('Sync Run') ->schema([ TextEntry::make('user.name') ->label('Initiator') ->placeholder('—'), TextEntry::make('status') ->badge() ->formatStateUsing(BadgeRenderer::label(BadgeDomain::InventorySyncRunStatus)) ->color(BadgeRenderer::color(BadgeDomain::InventorySyncRunStatus)) ->icon(BadgeRenderer::icon(BadgeDomain::InventorySyncRunStatus)) ->iconColor(BadgeRenderer::iconColor(BadgeDomain::InventorySyncRunStatus)), TextEntry::make('selection_hash')->label('Selection hash')->copyable(), TextEntry::make('started_at')->dateTime(), TextEntry::make('finished_at')->dateTime(), TextEntry::make('items_observed_count')->label('Observed')->numeric(), TextEntry::make('items_upserted_count')->label('Upserted')->numeric(), TextEntry::make('errors_count')->label('Errors')->numeric(), TextEntry::make('had_errors') ->label('Had errors') ->badge() ->formatStateUsing(BadgeRenderer::label(BadgeDomain::BooleanHasErrors)) ->color(BadgeRenderer::color(BadgeDomain::BooleanHasErrors)) ->icon(BadgeRenderer::icon(BadgeDomain::BooleanHasErrors)) ->iconColor(BadgeRenderer::iconColor(BadgeDomain::BooleanHasErrors)), ]) ->columns(2) ->columnSpanFull(), Section::make('Selection Payload') ->schema([ ViewEntry::make('selection_payload') ->label('') ->view('filament.infolists.entries.snapshot-json') ->state(fn (InventorySyncRun $record) => $record->selection_payload ?? []) ->columnSpanFull(), ]) ->columnSpanFull(), Section::make('Error Summary') ->schema([ ViewEntry::make('error_codes') ->label('Error codes') ->view('filament.infolists.entries.snapshot-json') ->state(fn (InventorySyncRun $record) => $record->error_codes ?? []) ->columnSpanFull(), ViewEntry::make('error_context') ->label('Safe error context') ->view('filament.infolists.entries.snapshot-json') ->state(fn (InventorySyncRun $record) => $record->error_context ?? []) ->columnSpanFull(), ]) ->columnSpanFull(), ]); } public static function table(Table $table): Table { return $table ->defaultSort('id', 'desc') ->columns([ Tables\Columns\TextColumn::make('user.name') ->label('Initiator') ->placeholder('—') ->toggleable(), Tables\Columns\TextColumn::make('status') ->badge() ->formatStateUsing(BadgeRenderer::label(BadgeDomain::InventorySyncRunStatus)) ->color(BadgeRenderer::color(BadgeDomain::InventorySyncRunStatus)) ->icon(BadgeRenderer::icon(BadgeDomain::InventorySyncRunStatus)) ->iconColor(BadgeRenderer::iconColor(BadgeDomain::InventorySyncRunStatus)), Tables\Columns\TextColumn::make('selection_hash') ->label('Selection') ->copyable() ->limit(12), Tables\Columns\TextColumn::make('started_at')->since(), Tables\Columns\TextColumn::make('finished_at')->since(), Tables\Columns\TextColumn::make('items_observed_count') ->label('Observed') ->numeric(), Tables\Columns\TextColumn::make('items_upserted_count') ->label('Upserted') ->numeric(), Tables\Columns\TextColumn::make('errors_count') ->label('Errors') ->numeric(), ]) ->actions([ Actions\ViewAction::make(), ]) ->bulkActions([]); } public static function getEloquentQuery(): Builder { $tenantId = Tenant::current()?->getKey(); return parent::getEloquentQuery() ->with('user') ->when($tenantId, fn (Builder $query) => $query->where('tenant_id', $tenantId)); } public static function getPages(): array { return [ 'index' => Pages\ListInventorySyncRuns::route('/'), 'view' => Pages\ViewInventorySyncRun::route('/{record}'), ]; } }