*/ public array $supportDiagnosticsAuditKeys = []; /** * @param array $parameters */ public static function getUrl(array $parameters = [], bool $isAbsolute = true, ?string $panel = null, ?Model $tenant = null, bool $shouldGuessMissingParameters = false): string { return parent::getUrl($parameters, $isAbsolute, $panel ?? 'tenant', $tenant, $shouldGuessMissingParameters); } /** * @return array | WidgetConfiguration> */ public function getWidgets(): array { return [ TenantTriageArrivalContinuity::class, RecoveryReadiness::class, DashboardKpis::class, NeedsAttention::class, BaselineCompareNow::class, RecentDriftFindings::class, RecentOperations::class, ]; } public function getColumns(): int|array { return 2; } /** * @return array */ protected function getHeaderActions(): array { return [ $this->openSupportDiagnosticsAction(), ]; } private function openSupportDiagnosticsAction(): Action { $action = Action::make('openSupportDiagnostics') ->label('Open support diagnostics') ->icon('heroicon-o-lifebuoy') ->color('gray') ->modal() ->slideOver() ->stickyModalHeader() ->modalHeading('Support diagnostics') ->modalDescription('Redacted tenant context from existing records.') ->modalSubmitAction(false) ->modalCancelAction(fn (Action $action): Action => $action->label('Close')) ->mountUsing(function (): void { $this->auditTenantSupportDiagnosticsOpen(); }) ->modalContent(fn (): View => view('filament.modals.support-diagnostic-bundle', [ 'bundle' => $this->tenantSupportDiagnosticBundle(), ])); return UiEnforcement::forAction($action) ->requireCapability(Capabilities::SUPPORT_DIAGNOSTICS_VIEW) ->apply(); } /** * @return array */ public function tenantSupportDiagnosticBundle(): array { $user = auth()->user(); $tenant = Filament::getTenant(); if (! $user instanceof User || ! $tenant instanceof Tenant) { abort(404); } $resolver = app(CapabilityResolver::class); if (! $resolver->isMember($user, $tenant)) { abort(404); } if (! $resolver->can($user, $tenant, Capabilities::SUPPORT_DIAGNOSTICS_VIEW)) { abort(403); } return app(SupportDiagnosticBundleBuilder::class)->forTenant($tenant, $user); } private function auditTenantSupportDiagnosticsOpen(): void { $user = auth()->user(); $tenant = Filament::getTenant(); if (! $user instanceof User || ! $tenant instanceof Tenant) { abort(404); } $this->recordSupportDiagnosticsOpened( tenant: $tenant, bundle: $this->tenantSupportDiagnosticBundle(), user: $user, ); } /** * @param array $bundle */ private function recordSupportDiagnosticsOpened(Tenant $tenant, array $bundle, User $user): void { $auditKey = 'tenant:'.$tenant->getKey(); if (in_array($auditKey, $this->supportDiagnosticsAuditKeys, true)) { return; } app(WorkspaceAuditLogger::class)->logSupportDiagnosticsOpened( tenant: $tenant, contextType: 'tenant', bundle: $bundle, actor: $user, ); $this->supportDiagnosticsAuditKeys[] = $auditKey; } }