label('Grant admin consent') ->icon('heroicon-o-clipboard-document') ->url(function (): ?string { $tenant = ProviderConnectionResource::resolveTenantForRecord($this->record); return $tenant instanceof Tenant ? RequiredPermissionsLinks::adminConsentPrimaryUrl($tenant) : null; }) ->visible(function (): bool { return ProviderConnectionResource::resolveTenantForRecord($this->record) instanceof Tenant; }) ->openUrlInNewTab() ) ->requireCapability(Capabilities::PROVIDER_MANAGE) ->apply(), UiEnforcement::forAction( Actions\Action::make('edit') ->label('Edit') ->icon('heroicon-o-pencil-square') ->url(fn (): string => ProviderConnectionResource::getUrl('edit', ['record' => $this->record])) ) ->requireCapability(Capabilities::PROVIDER_MANAGE) ->apply(), Actions\ActionGroup::make([ UiEnforcement::forAction( Actions\Action::make('enable_dedicated_override') ->label('Enable dedicated override') ->icon('heroicon-o-key') ->color('primary') ->requiresConfirmation() ->modalDescription('Dedicated credentials are stored encrypted and reset consent to the dedicated app registration.') ->visible(fn (): bool => $this->record->connection_type !== ProviderConnectionType::Dedicated) ->form([ TextInput::make('client_id') ->label('Dedicated app (client) ID') ->required() ->maxLength(255), TextInput::make('client_secret') ->label('Dedicated client secret') ->password() ->required() ->maxLength(255), ]) ->action(function (array $data, ProviderConnectionMutationService $mutations, AuditLogger $auditLogger): void { $tenant = ProviderConnectionResource::resolveTenantForRecord($this->record); if (! $tenant instanceof Tenant) { abort(404); } $mutations->enableDedicatedOverride( connection: $this->record, clientId: (string) $data['client_id'], clientSecret: (string) $data['client_secret'], ); $user = auth()->user(); $actorId = $user instanceof User ? (int) $user->getKey() : null; $actorEmail = $user instanceof User ? $user->email : null; $actorName = $user instanceof User ? $user->name : null; $auditLogger->log( tenant: $tenant, action: 'provider_connection.connection_type_changed', context: [ 'metadata' => [ 'provider_connection_id' => (int) $this->record->getKey(), 'provider' => $this->record->provider, 'entra_tenant_id' => $this->record->entra_tenant_id, 'from_connection_type' => ProviderConnectionType::Platform->value, 'to_connection_type' => ProviderConnectionType::Dedicated->value, 'client_id' => (string) $data['client_id'], 'source' => 'provider_connection.view_page', ], ], actorId: $actorId, actorEmail: $actorEmail, actorName: $actorName, resourceType: 'provider_connection', resourceId: (string) $this->record->getKey(), status: 'success', ); Notification::make() ->title('Dedicated override enabled') ->success() ->send(); }) ) ->requireCapability(Capabilities::PROVIDER_MANAGE_DEDICATED) ->preserveVisibility() ->apply(), UiEnforcement::forAction( Actions\Action::make('rotate_dedicated_credential') ->label('Rotate dedicated credential') ->icon('heroicon-o-arrow-path') ->color('primary') ->requiresConfirmation() ->visible(fn (): bool => $this->record->connection_type === ProviderConnectionType::Dedicated) ->form([ TextInput::make('client_id') ->label('Dedicated app (client) ID') ->default(function (): string { $payload = $this->record->credential?->payload; return is_array($payload) ? (string) ($payload['client_id'] ?? '') : ''; }) ->required() ->maxLength(255), TextInput::make('client_secret') ->label('Dedicated client secret') ->password() ->required() ->maxLength(255), ]) ->action(function (array $data, ProviderConnectionMutationService $mutations): void { $tenant = ProviderConnectionResource::resolveTenantForRecord($this->record); if (! $tenant instanceof Tenant) { abort(404); } $mutations->enableDedicatedOverride( connection: $this->record, clientId: (string) $data['client_id'], clientSecret: (string) $data['client_secret'], ); Notification::make() ->title('Dedicated credential rotated') ->success() ->send(); }) ) ->requireCapability(Capabilities::PROVIDER_MANAGE_DEDICATED) ->preserveVisibility() ->apply(), UiEnforcement::forAction( Actions\Action::make('delete_dedicated_credential') ->label('Delete dedicated credential') ->icon('heroicon-o-trash') ->color('danger') ->requiresConfirmation() ->visible(fn (): bool => $this->record->connection_type === ProviderConnectionType::Dedicated && $this->record->credential()->exists()) ->action(function (ProviderConnectionMutationService $mutations): void { $tenant = ProviderConnectionResource::resolveTenantForRecord($this->record); if (! $tenant instanceof Tenant) { abort(404); } $mutations->deleteDedicatedCredential($this->record); Notification::make() ->title('Dedicated credential deleted') ->warning() ->send(); }) ) ->requireCapability(Capabilities::PROVIDER_MANAGE_DEDICATED) ->preserveVisibility() ->apply(), UiEnforcement::forAction( Actions\Action::make('revert_to_platform') ->label('Revert to platform') ->icon('heroicon-o-arrow-uturn-left') ->color('gray') ->requiresConfirmation() ->visible(fn (): bool => $this->record->connection_type === ProviderConnectionType::Dedicated) ->action(function (ProviderConnectionMutationService $mutations, AuditLogger $auditLogger): void { $tenant = ProviderConnectionResource::resolveTenantForRecord($this->record); if (! $tenant instanceof Tenant) { abort(404); } $mutations->revertToPlatform($this->record); $user = auth()->user(); $actorId = $user instanceof User ? (int) $user->getKey() : null; $actorEmail = $user instanceof User ? $user->email : null; $actorName = $user instanceof User ? $user->name : null; $auditLogger->log( tenant: $tenant, action: 'provider_connection.connection_type_changed', context: [ 'metadata' => [ 'provider_connection_id' => (int) $this->record->getKey(), 'provider' => $this->record->provider, 'entra_tenant_id' => $this->record->entra_tenant_id, 'from_connection_type' => ProviderConnectionType::Dedicated->value, 'to_connection_type' => ProviderConnectionType::Platform->value, 'source' => 'provider_connection.view_page', ], ], actorId: $actorId, actorEmail: $actorEmail, actorName: $actorName, resourceType: 'provider_connection', resourceId: (string) $this->record->getKey(), status: 'success', ); Notification::make() ->title('Connection reverted to platform') ->success() ->send(); }) ) ->requireCapability(Capabilities::PROVIDER_MANAGE_DEDICATED) ->preserveVisibility() ->apply(), ]) ->label('Manage dedicated override') ->icon('heroicon-o-cog-6-tooth') ->color('gray'), ]; } }