resetTable(); } public function isReadOnly(): bool { return false; } public function reorderTable(array $order, int|string|null $draggedRecordKey = null): void { parent::reorderTable($order, $draggedRecordKey); $this->dispatch('process-reordered'); } public function form(Schema $schema): Schema { return $schema ->columns(1) ->components([ TextInput::make('name') ->label('Name') ->required() ->maxLength(255) ->columnSpanFull(), Textarea::make('description') ->label('Description') ->required() ->columnSpanFull(), TextInput::make('auditee') ->label('Auditee') ->required() ->maxLength(255) ->columnSpanFull(), TagsInput::make('label') ->label('Label') ->reorderable() ->suggestions(fn (): array => Filament::getTenant() ->processes() ->whereNotNull('label') ->pluck('label') ->filter() ->flatten() ->unique() ->sort() ->values() ->toArray() ) ->splitKeys([',']) ->helperText('Separate labels using a comma'), Repeater::make('processItems') ->label('Items') ->relationship() ->addActionLabel('Select item') ->addActionAlignment(Alignment::Right) ->reorderableWithDragAndDrop() ->orderColumn('sort_order') ->table([ TableColumn::make('Item') ->width('50%'), TableColumn::make('Standard') ->width('50%'), ]) ->schema([ Select::make('item_id') ->label('Item') ->relationship( 'item', 'title', function (Builder $query): Builder { $program = $this->getOwnerRecord(); $process = $this->getMountedTableActionRecord(); $standards = $program->standards ->pluck('id'); // Filter out items that don't belong to the standards that are assigned to the parent program $query->whereHas('standard', fn (Builder $standardQuery): Builder => $standardQuery->whereIn('standards.id', $standards) ); // If context is editing process, then exclude already attached items to the process if ($process) { $query->whereDoesntHave('processes', fn (Builder $processesQuery): Builder => $processesQuery->where('processes.id', '=', $process->id) ); } return $query; } ) ->getOptionLabelUsing(function (mixed $value): string { $itemId = $value; if (!$itemId) { return ''; } $item = Item::find($value); return $item ? $item->title : $value; } ) ->searchable() ->preload() ->required() ->live(), TextEntry::make('standard') ->disableLabel() ->getStateUsing(function (Get $get): string { $itemId = $get('item_id'); if (!$itemId) { return '-'; } $item = Item::with('standard:id,name')->find($itemId); return $item->standard->name; }), ]), ]); } public function table(Table $table): Table { return $table ->reorderable('sort_order') ->defaultSort('sort_order') ->deferColumnManager(false) ->recordTitleAttribute('name') ->columns([ TextColumn::make('name') ->label('Name') ->sortable() ->searchable() ->formatStateUsing(function (Process $process, string $state): string { $tags = collect($process->label ?? []) ->map(fn (string $tag): string => " {$tag} ") ->implode(''); return "{$state} {$tags}"; }) ->html() ->toggleable(isToggledHiddenByDefault: false), TextColumn::make('involved_in_audits') ->label('Involved in audits') ->getStateUsing(function (Process $process): string { $auditsList = $process->audits ->pluck('title') ->unique() ->implode(', '); return $auditsList === '' ? '-' : $auditsList; }) ->toggleable(isToggledHiddenByDefault: false), TextColumn::make('auditee') ->label('Auditee') ->sortable() ->searchable() ->toggleable(isToggledHiddenByDefault: false), TextColumn::make('standards_list') ->label('Standards') ->toggleable(isToggledHiddenByDefault: false), ]) ->headerActions([ CreateAction::make() ->label('Add Process') ->modalHeading('Add new process') ->modalSubmitActionLabel('Save') ->disableCreateAnother() ->icon(Heroicon::OutlinedPlus) ->successNotification(fn (): Notification => Notification::make() ->title('Process added') ->body('New process has succesfully been added to the program.') ->success() ) ->after(function (): void { $this->dispatch('process-created'); }), ]) ->recordActions([ EditAction::make() ->modalSubmitActionLabel('Save') ->successNotification(fn (): Notification => Notification::make() ->title('Process updated') ->body('Process has been updated.') ->success() ) ->after(function (): void { $this->dispatch('process-updated'); }), ]) ->toolbarActions([ BulkActionGroup::make([ // ]), ]) ->emptyStateHeading('No processes found.') ->emptyStateDescription('This program doesn\'t have any processes yet.') ->emptyStateIcon(Heroicon::OutlinedArrowPath); } }