columns([ IconColumn::make('type'), TextColumn::make('endpoint') ->label(trans('admin/webhook.table.endpoint')) ->formatStateUsing(fn (string $state) => str($state)->after('://')) ->limit(60) ->wrap(), TextColumn::make('description') ->label(trans('admin/webhook.table.description')), TextColumn::make('endpoint') ->label(trans('admin/webhook.table.endpoint')), ]) ->actions([ ViewAction::make() ->hidden(fn (WebhookConfiguration $record) => static::canEdit($record)), EditAction::make(), ReplicateAction::make() ->iconButton() ->tooltip(trans('filament-actions::replicate.single.label')) ->modal(false) ->excludeAttributes(['created_at', 'updated_at']) ->beforeReplicaSaved(fn (WebhookConfiguration $replica) => $replica->description .= ' Copy ' . now()->format('Y-m-d H:i:s')) ->successRedirectUrl(fn (WebhookConfiguration $replica) => EditWebhookConfiguration::getUrl(['record' => $replica])), ]) ->groupedBulkActions([ DeleteBulkAction::make(), ]) ->emptyStateIcon('tabler-webhook') ->emptyStateDescription('') ->emptyStateHeading(trans('admin/webhook.no_webhooks')) ->emptyStateActions([ CreateAction::make(), ]) ->persistFiltersInSession() ->filters([ SelectFilter::make('type') ->options(WebhookType::class) ->attribute('type'), ]); } public static function defaultForm(Form $form): Form { return $form ->schema([ ToggleButtons::make('type') ->live() ->inline() ->options(WebhookType::class) ->default(WebhookType::Regular->value) ->afterStateHydrated(function (string $state) { if ($state === WebhookType::Discord->value) { self::sendHelpBanner(); } }) ->afterStateUpdated(function (string $state) { if ($state === WebhookType::Discord->value) { self::sendHelpBanner(); } }), TextInput::make('description') ->label(trans('admin/webhook.description')) ->required(), TextInput::make('endpoint') ->label(trans('admin/webhook.endpoint')) ->activeUrl() ->required() ->columnSpanFull() ->afterStateUpdated(fn (string $state, Set $set) => $set('type', str($state)->contains('discord.com') ? WebhookType::Discord->value : WebhookType::Regular->value)), Section::make(trans('admin/webhook.regular')) ->hidden(fn (Get $get) => $get('type') === WebhookType::Discord->value) ->dehydratedWhenHidden() ->schema(fn () => self::getRegularFields()) ->formBefore(), Section::make(trans('admin/webhook.discord')) ->hidden(fn (Get $get) => $get('type') === WebhookType::Regular->value) ->dehydratedWhenHidden() ->afterStateUpdated(fn (Livewire $livewire) => $livewire->dispatch('refresh-widget')) ->schema(fn () => self::getDiscordFields()) ->view('filament.components.webhooksection') ->aside() ->formBefore(), Section::make(trans('admin/webhook.events')) ->collapsible() ->collapsed(fn (Get $get) => count($get('events') ?? [])) ->schema([ CheckboxList::make('events') ->live() ->options(fn () => WebhookConfiguration::filamentCheckboxList()) ->searchable() ->bulkToggleable() ->columns(3) ->columnSpanFull() ->required(), ]), ]); } /** @return Component[] */ private static function getRegularFields(): array { return [ KeyValue::make('headers') ->label(trans('admin/webhook.headers')), ]; } /** @return Component[] */ private static function getDiscordFields(): array { return [ Section::make(trans('admin/webhook.discord_message.profile')) ->collapsible() ->schema([ TextInput::make('username') ->live(debounce: 500) ->label(trans('admin/webhook.discord_message.username')), TextInput::make('avatar_url') ->live(debounce: 500) ->label(trans('admin/webhook.discord_message.avatar_url')), ]), Section::make(trans('admin/webhook.discord_message.message')) ->collapsible() ->schema([ TextInput::make('content') ->label(trans('admin/webhook.discord_message.message')) ->live(debounce: 500) ->required(fn (Get $get) => empty($get('embeds'))), TextInput::make('thread_name') ->label(trans('admin/webhook.discord_message.forum_thread')), CheckboxList::make('flags') ->label('Flags') ->options([ (1 << 2) => trans('admin/webhook.discord_message.supress_embeds'), (1 << 12) => trans('admin/webhook.discord_message.supress_notifications'), ]) ->descriptions([ (1 << 2) => trans('admin/webhook.discord_message.supress_embeds_text'), (1 << 12) => trans('admin/webhook.discord_message.supress_notifications_text'), ]), CheckboxList::make('allowed_mentions') ->label(trans('admin/webhook.discord_embed.allowed_mentions')) ->options([ 'roles' => trans('admin/webhook.discord_embed.roles'), 'users' => trans('admin/webhook.discord_embed.users'), 'everyone' => trans('admin/webhook.discord_embed.everyone'), ]), ]), Repeater::make('embeds') ->live(debounce: 500) ->itemLabel(fn (array $state) => $state['title']) ->addActionLabel(trans('admin/webhook.discord_embed.add_embed')) ->required(fn (Get $get) => empty($get('content'))) ->reorderable() ->collapsible() ->maxItems(10) ->schema([ Section::make(trans('admin/webhook.discord_embed.author')) ->collapsible() ->collapsed() ->schema([ TextInput::make('author.name') ->live(debounce: 500) ->label(trans('admin/webhook.discord_embed.author')) ->required(fn (Get $get) => filled($get('author.url')) || filled($get('author.icon_url'))), TextInput::make('author.url') ->live(debounce: 500) ->label(trans('admin/webhook.discord_embed.author_url')), TextInput::make('author.icon_url') ->live(debounce: 500) ->label(trans('admin/webhook.discord_embed.author_icon_url')), ]), Section::make(trans('admin/webhook.discord_embed.body')) ->collapsible() ->collapsed() ->schema([ TextInput::make('title') ->live(debounce: 500) ->label(trans('admin/webhook.discord_embed.title')) ->required(fn (Get $get) => $get('description') === null), Textarea::make('description') ->live(debounce: 500) ->label(trans('admin/webhook.discord_embed.body')) ->required(fn (Get $get) => $get('title') === null), ColorPicker::make('color') ->live(debounce: 500) ->label(trans('admin/webhook.discord_embed.color')) ->hex(), TextInput::make('url') ->live(debounce: 500) ->label(trans('admin/webhook.discord_embed.url')), ]), Section::make(trans('admin/webhook.discord_embed.images')) ->collapsible() ->collapsed() ->schema([ TextInput::make('image.url') ->live(debounce: 500) ->label(trans('admin/webhook.discord_embed.image_url')), TextInput::make('thumbnail.url') ->live(debounce: 500) ->label(trans('admin/webhook.discord_embed.image_thumbnail')), ]), Section::make(trans('admin/webhook.discord_embed.footer')) ->collapsible() ->collapsed() ->schema([ TextInput::make('footer.text') ->live(debounce: 500) ->label(trans('admin/webhook.discord_embed.footer')), Checkbox::make('has_timestamp') ->live(debounce: 500) ->label(trans('admin/webhook.discord_embed.has_timestamp')), TextInput::make('footer.icon_url') ->live(debounce: 500) ->label(trans('admin/webhook.discord_embed.footer_icon_url')), ]), Section::make(trans('admin/webhook.discord_embed.fields')) ->collapsible()->collapsed() ->schema([ Repeater::make('fields') ->reorderable() ->addActionLabel(trans('admin/webhook.discord_embed.add_field')) ->collapsible() ->schema([ TextInput::make('name') ->live(debounce: 500) ->label(trans('admin/webhook.discord_embed.field_name')) ->required(), Textarea::make('value') ->live(debounce: 500) ->label(trans('admin/webhook.discord_embed.field_value')) ->rows(4) ->required(), Checkbox::make('inline') ->live(debounce: 500) ->label(trans('admin/webhook.discord_embed.inline_field')), ]), ]), ]), ]; } public static function sendHelpBanner(): void { AlertBanner::make('discord_webhook_help') ->title(trans('admin/webhook.help')) ->body(trans('admin/webhook.help_text')) ->icon('tabler-question-mark') ->info() ->send(); } /** @return array */ public static function getDefaultPages(): array { return [ 'index' => Pages\ListWebhookConfigurations::route('/'), 'create' => Pages\CreateWebhookConfiguration::route('/create'), 'view' => Pages\ViewWebhookConfiguration::route('/{record}'), 'edit' => Pages\EditWebhookConfiguration::route('/{record}/edit'), ]; } }