user()?->tenant_id; return $schema->components([ Section::make(__('Task Collection Details')) ->schema([ TextInput::make('name_translations.de') ->label(__('Name (DE)')) ->required() ->maxLength(255) ->disabled(fn (?TaskCollection $record) => $record?->tenant_id !== $tenantId && $record !== null), TextInput::make('name_translations.en') ->label(__('Name (EN)')) ->maxLength(255) ->disabled(fn (?TaskCollection $record) => $record?->tenant_id !== $tenantId && $record !== null), Select::make('event_type_id') ->label(__('Event Type')) ->options(fn () => EventType::orderBy('name->' . app()->getLocale()) ->get() ->mapWithKeys(function (EventType $type) { $name = $type->name[app()->getLocale()] ?? $type->name['de'] ?? reset($type->name); return [$type->id => $name]; })->toArray()) ->searchable() ->required() ->disabled(fn (?TaskCollection $record) => $record?->tenant_id !== $tenantId && $record !== null), Textarea::make('description_translations.de') ->label(__('Description (DE)')) ->rows(3) ->disabled(fn (?TaskCollection $record) => $record?->tenant_id !== $tenantId && $record !== null), Textarea::make('description_translations.en') ->label(__('Description (EN)')) ->rows(3) ->disabled(fn (?TaskCollection $record) => $record?->tenant_id !== $tenantId && $record !== null), ])->columns(2), ]); } public static function table(Table $table): Table { return $table ->columns([ TextColumn::make('name') ->label(__('Name')) ->searchable(['name_translations->de', 'name_translations->en']) ->sortable(), BadgeColumn::make('eventType.name') ->label(__('Event Type')) ->color('info'), IconColumn::make('tenant_id') ->label(__('Scope')) ->boolean() ->trueIcon('heroicon-o-user-group') ->falseIcon('heroicon-o-globe-alt') ->state(fn (TaskCollection $record) => $record->tenant_id !== null) ->tooltip(fn (TaskCollection $record) => $record->tenant_id ? __('Tenant-only') : __('Global template')), TextColumn::make('tasks_count') ->label(__('Tasks')) ->counts('tasks') ->sortable(), ]) ->filters([ SelectFilter::make('event_type_id') ->label(__('Event Type')) ->relationship('eventType', 'name->' . app()->getLocale()), SelectFilter::make('scope') ->options([ 'global' => __('Global template'), 'tenant' => __('Tenant-owned'), ]) ->query(function ($query, $value) { $tenantId = auth()->user()?->tenant_id; if ($value === 'global') { $query->whereNull('tenant_id'); } if ($value === 'tenant') { $query->where('tenant_id', $tenantId); } }), ]) ->actions([ \Filament\Actions\Action::make('import') ->label(__('Import to Event')) ->icon('heroicon-o-cloud-arrow-down') ->form([ Select::make('event_slug') ->label(__('Select Event')) ->options(function () { $tenantId = auth()->user()?->tenant_id; return Event::where('tenant_id', $tenantId) ->orderBy('date', 'desc') ->get() ->mapWithKeys(function (Event $event) { $name = $event->name[app()->getLocale()] ?? $event->name['de'] ?? reset($event->name); return [ $event->slug => sprintf('%s (%s)', $name, $event->date?->format('d.m.Y')), ]; })->toArray(); }) ->required() ->searchable(), ]) ->action(function (TaskCollection $record, array $data) { $event = Event::where('slug', $data['event_slug']) ->where('tenant_id', auth()->user()?->tenant_id) ->firstOrFail(); /** @var TaskCollectionImportService $service */ $service = app(TaskCollectionImportService::class); $service->import($record, $event); Notification::make() ->title(__('Task collection imported')) ->body(__('The collection :name has been imported.', ['name' => $record->name])) ->success() ->send(); }), Actions\EditAction::make() ->label(__('Edit')) ->visible(fn (TaskCollection $record) => $record->tenant_id === auth()->user()?->tenant_id), ]) ->headerActions([ Actions\CreateAction::make() ->label(__('Create Task Collection')) ->mutateFormDataUsing(function (array $data) { $tenantId = auth()->user()?->tenant_id; $data['tenant_id'] = $tenantId; $data['slug'] = static::generateSlug($data['name_translations']['en'] ?? $data['name_translations']['de'] ?? 'collection', $tenantId); return $data; }), ]) ->bulkActions([ Actions\DeleteBulkAction::make() ->visible(fn () => false), ]); } public static function getPages(): array { return [ 'index' => Pages\ListTaskCollections::route('/'), 'create' => Pages\CreateTaskCollection::route('/create'), 'edit' => Pages\EditTaskCollection::route('/{record}/edit'), ]; } public static function getEloquentQuery(): Builder { $tenantId = auth()->user()?->tenant_id; return parent::getEloquentQuery() ->forTenant($tenantId) ->with('eventType') ->withCount('tasks'); } public static function getGloballySearchableAttributes(): array { return ['name_translations->de', 'name_translations->en']; } public static function generateSlug(string $base, int $tenantId): string { $slugBase = Str::slug($base) ?: 'collection'; do { $candidate = $slugBase . '-' . $tenantId . '-' . Str::random(4); } while (TaskCollection::where('slug', $candidate)->exists()); return $candidate; } public static function scopeEloquentQueryToTenant(Builder $query, ?Model $tenant): Builder { $tenant ??= Filament::getTenant(); if (! $tenant) { return $query; } return $query->where(function (Builder $innerQuery) use ($tenant) { $innerQuery->whereNull('tenant_id') ->orWhere('tenant_id', $tenant->getKey()); }); } }