add own CopyAction

This commit is contained in:
Boy132 2025-07-01 08:47:30 +02:00
parent f40e125d2f
commit 9da52c24c0
12 changed files with 91 additions and 31 deletions

View File

@ -42,7 +42,7 @@ final class DiscordProvider extends OAuthProvider
->label('Redirect URL') ->label('Redirect URL')
->dehydrated() ->dehydrated()
->disabled() ->disabled()
//TODO ->hintAction(fn (string $state) => request()->isSecure() ? CopyAction::make()->copyable($state) : null) ->hintCopy()
->formatStateUsing(fn () => url('/auth/oauth/callback/discord')), ->formatStateUsing(fn () => url('/auth/oauth/callback/discord')),
]), ]),
], parent::getSetupSteps()); ], parent::getSetupSteps());

View File

@ -8,7 +8,6 @@ use Filament\Forms\Components\TextInput;
use Illuminate\Foundation\Application; use Illuminate\Foundation\Application;
use Illuminate\Support\Facades\Blade; use Illuminate\Support\Facades\Blade;
use Illuminate\Support\HtmlString; use Illuminate\Support\HtmlString;
use Webbingbrasil\FilamentCopyActions\Forms\Actions\CopyAction;
final class GithubProvider extends OAuthProvider final class GithubProvider extends OAuthProvider
{ {
@ -34,7 +33,7 @@ final class GithubProvider extends OAuthProvider
->label('Authorization callback URL') ->label('Authorization callback URL')
->dehydrated() ->dehydrated()
->disabled() ->disabled()
//TODO ->hintAction(fn (string $state) => request()->isSecure() ? CopyAction::make()->copyable($state) : null) ->hintCopy()
->default(fn () => url('/auth/oauth/callback/github')), ->default(fn () => url('/auth/oauth/callback/github')),
TextEntry::make('register_application') TextEntry::make('register_application')
->hiddenLabel() ->hiddenLabel()

View File

@ -8,7 +8,6 @@ use Filament\Forms\Components\TextInput;
use Illuminate\Foundation\Application; use Illuminate\Foundation\Application;
use Illuminate\Support\Facades\Blade; use Illuminate\Support\Facades\Blade;
use Illuminate\Support\HtmlString; use Illuminate\Support\HtmlString;
use Webbingbrasil\FilamentCopyActions\Forms\Actions\CopyAction;
final class GitlabProvider extends OAuthProvider final class GitlabProvider extends OAuthProvider
{ {
@ -54,7 +53,7 @@ final class GitlabProvider extends OAuthProvider
->label('Redirect URI') ->label('Redirect URI')
->dehydrated() ->dehydrated()
->disabled() ->disabled()
//TODO ->hintAction(fn (string $state) => request()->isSecure() ? CopyAction::make()->copyable($state) : null) ->hintCopy()
->default(fn () => url('/auth/oauth/callback/gitlab')), ->default(fn () => url('/auth/oauth/callback/gitlab')),
]), ]),
], parent::getSetupSteps()); ], parent::getSetupSteps());

View File

@ -97,14 +97,14 @@ class CreateDatabaseHost extends CreateRecord
->default(fn (Get $get) => "CREATE USER '{$get('username')}'@'{$get('panel_ip')}' IDENTIFIED BY '{$get('password')}';") ->default(fn (Get $get) => "CREATE USER '{$get('username')}'@'{$get('panel_ip')}' IDENTIFIED BY '{$get('password')}';")
->disabled() ->disabled()
->dehydrated(false) ->dehydrated(false)
// TODO ->suffixAction(fn (string $state) => request()->isSecure() ? CopyAction::make()->copyable($state) : null) ->suffixCopy()
->columnSpanFull(), ->columnSpanFull(),
TextInput::make('assign_permissions') TextInput::make('assign_permissions')
->label(trans('admin/databasehost.setup.command_assign_permissions')) ->label(trans('admin/databasehost.setup.command_assign_permissions'))
->default(fn (Get $get) => "GRANT ALL PRIVILEGES ON *.* TO '{$get('username')}'@'{$get('panel_ip')}' WITH GRANT OPTION;") ->default(fn (Get $get) => "GRANT ALL PRIVILEGES ON *.* TO '{$get('username')}'@'{$get('panel_ip')}' WITH GRANT OPTION;")
->disabled() ->disabled()
->dehydrated(false) ->dehydrated(false)
// TODO ->suffixAction(fn (string $state) => request()->isSecure() ? CopyAction::make()->copyable($state) : null) ->suffixCopy()
->columnSpanFull(), ->columnSpanFull(),
TextEntry::make('cli_exit') TextEntry::make('cli_exit')
->hiddenLabel() ->hiddenLabel()

View File

@ -293,7 +293,7 @@ class EditNode extends EditRecord
'lg' => 2, 'lg' => 2,
]) ])
->label(trans('admin/node.node_uuid')) ->label(trans('admin/node.node_uuid'))
// TODO ->hintAction(fn () => request()->isSecure() ? CopyAction::make() : null) ->hintCopy()
->disabled(), ->disabled(),
TagsInput::make('tags') TagsInput::make('tags')
->label(trans('admin/node.tags')) ->label(trans('admin/node.tags'))
@ -554,7 +554,7 @@ class EditNode extends EditRecord
->label('/etc/pelican/config.yml') ->label('/etc/pelican/config.yml')
->disabled() ->disabled()
->rows(19) ->rows(19)
//TODO ->hintAction(fn () => request()->isSecure() ? CopyAction::make() : null) ->hintCopy()
->columnSpanFull(), ->columnSpanFull(),
Grid::make() Grid::make()
->columns() ->columns()
@ -591,7 +591,7 @@ class EditNode extends EditRecord
->label(trans('admin/node.auto_command')) ->label(trans('admin/node.auto_command'))
->readOnly() ->readOnly()
->autosize() ->autosize()
//TODO ->hintAction(fn (string $state) => request()->isSecure() ? CopyAction::make()->copyable($state) : null) ->hintCopy()
->formatStateUsing(fn (NodeAutoDeployService $service, Node $node, Set $set, Get $get) => $set('generatedToken', $service->handle(request(), $node, $get('docker')))), ->formatStateUsing(fn (NodeAutoDeployService $service, Node $node, Set $set, Get $get) => $set('generatedToken', $service->handle(request(), $node, $get('docker')))),
]) ])
->mountUsing(function (Schema $schema) { ->mountUsing(function (Schema $schema) {

View File

@ -180,7 +180,7 @@ class EditServer extends EditRecord
TextInput::make('uuid') TextInput::make('uuid')
->label(trans('admin/server.uuid')) ->label(trans('admin/server.uuid'))
//TODO ->suffixAction(fn () => request()->isSecure() ? CopyAction::make() : null) ->suffixCopy()
->columnSpan([ ->columnSpan([
'default' => 2, 'default' => 2,
'sm' => 1, 'sm' => 1,
@ -191,7 +191,7 @@ class EditServer extends EditRecord
->dehydrated(false), ->dehydrated(false),
TextInput::make('uuid_short') TextInput::make('uuid_short')
->label(trans('admin/server.short_uuid')) ->label(trans('admin/server.short_uuid'))
//TODO ->suffixAction(fn () => request()->isSecure() ? CopyAction::make() : null) ->suffixCopy()
->columnSpan([ ->columnSpan([
'default' => 2, 'default' => 2,
'sm' => 1, 'sm' => 1,
@ -620,7 +620,7 @@ class EditServer extends EditRecord
->hintAction(PreviewStartupAction::make('preview')), ->hintAction(PreviewStartupAction::make('preview')),
Textarea::make('defaultStartup') Textarea::make('defaultStartup')
//TODO ->hintAction(fn () => request()->isSecure() ? CopyAction::make() : null) ->hintCopy()
->label(trans('admin/server.default_startup')) ->label(trans('admin/server.default_startup'))
->disabled() ->disabled()
->autosize() ->autosize()
@ -719,13 +719,13 @@ class EditServer extends EditRecord
->label(trans('admin/databasehost.table.host')) ->label(trans('admin/databasehost.table.host'))
->disabled() ->disabled()
->formatStateUsing(fn ($record) => $record->address()) ->formatStateUsing(fn ($record) => $record->address())
//TODO ->suffixAction(fn (string $state) => request()->isSecure() ? CopyAction::make()->copyable($state) : null) ->suffixCopy()
->columnSpan(1), ->columnSpan(1),
TextInput::make('database') TextInput::make('database')
->label(trans('admin/databasehost.table.database')) ->label(trans('admin/databasehost.table.database'))
->disabled() ->disabled()
->formatStateUsing(fn ($record) => $record->database) ->formatStateUsing(fn ($record) => $record->database)
//TODO ->suffixAction(fn (string $state) => request()->isSecure() ? CopyAction::make()->copyable($state) : null) ->suffixCopy()
->hintAction( ->hintAction(
Action::make('Delete') Action::make('Delete')
->label(trans('filament-actions::delete.single.modal.actions.delete.label')) ->label(trans('filament-actions::delete.single.modal.actions.delete.label'))
@ -746,7 +746,7 @@ class EditServer extends EditRecord
->label(trans('admin/databasehost.table.username')) ->label(trans('admin/databasehost.table.username'))
->disabled() ->disabled()
->formatStateUsing(fn ($record) => $record->username) ->formatStateUsing(fn ($record) => $record->username)
//TODO ->suffixAction(fn (string $state) => request()->isSecure() ? CopyAction::make()->copyable($state) : null) ->suffixCopy()
->columnSpan(1), ->columnSpan(1),
TextInput::make('password') TextInput::make('password')
->label(trans('admin/databasehost.table.password')) ->label(trans('admin/databasehost.table.password'))
@ -755,7 +755,7 @@ class EditServer extends EditRecord
->revealable() ->revealable()
->columnSpan(1) ->columnSpan(1)
->hintAction(RotateDatabasePasswordAction::make()) ->hintAction(RotateDatabasePasswordAction::make())
//TODO ->suffixAction(fn (string $state) => request()->isSecure() ? CopyAction::make()->copyable($state) : null) ->suffixCopy()
->formatStateUsing(fn (Database $database) => $database->password), ->formatStateUsing(fn (Database $database) => $database->password),
TextInput::make('remote') TextInput::make('remote')
->disabled() ->disabled()
@ -773,8 +773,8 @@ class EditServer extends EditRecord
->revealable() ->revealable()
->label(trans('admin/databasehost.table.connection_string')) ->label(trans('admin/databasehost.table.connection_string'))
->columnSpan(2) ->columnSpan(2)
->formatStateUsing(fn (Database $record) => $record->jdbc), ->formatStateUsing(fn (Database $record) => $record->jdbc)
//TODO ->suffixAction(fn (string $state) => request()->isSecure() ? CopyAction::make()->copyable($state) : null), ->suffixCopy(),
]) ])
->relationship('databases') ->relationship('databases')
->deletable(false) ->deletable(false)

View File

@ -0,0 +1,46 @@
<?php
namespace App\Filament\Components\Actions;
use Closure;
use Filament\Actions\Action;
use Illuminate\Support\HtmlString;
use Illuminate\Support\Js;
use Livewire\Features\SupportJsEvaluation\HandlesJsEvaluation;
class CopyAction extends Action
{
use HandlesJsEvaluation;
protected Closure|string|null $copyable = null;
public static function getDefaultName(): ?string
{
return 'copy';
}
public function setUp(): void
{
parent::setUp();
$this->icon('tabler-clipboard-copy');
$this->successNotificationTitle(trans('filament::components/copyable.messages.copied'));
$this->extraAttributes(fn () => [
'x-on:click' => new HtmlString('window.navigator.clipboard.writeText('.$this->getCopyable().'); $tooltip('.Js::from($this->getSuccessNotificationTitle()).');'),
]);
}
public function copyable(Closure|string|null $copyable): self
{
$this->copyable = $copyable;
return $this;
}
public function getCopyable(): ?string
{
return Js::from($this->evaluate($this->copyable));
}
}

View File

@ -165,7 +165,7 @@ class Settings extends ServerFormPage
->label('Connection') ->label('Connection')
->columnSpan(1) ->columnSpan(1)
->disabled() ->disabled()
//TODO ->suffixAction(fn () => request()->isSecure() ? CopyAction::make() : null) ->suffixCopy()
->hintAction( ->hintAction(
Action::make('connect_sftp') Action::make('connect_sftp')
->label('Connect to SFTP') ->label('Connect to SFTP')
@ -185,7 +185,7 @@ class Settings extends ServerFormPage
TextInput::make('username') TextInput::make('username')
->label('Username') ->label('Username')
->columnSpan(1) ->columnSpan(1)
//TODO ->suffixAction(fn () => request()->isSecure() ? CopyAction::make() : null) ->suffixCopy()
->disabled() ->disabled()
->formatStateUsing(fn (Server $server) => auth()->user()->username . '.' . $server->uuid_short), ->formatStateUsing(fn (Server $server) => auth()->user()->username . '.' . $server->uuid_short),
TextEntry::make('password') TextEntry::make('password')

View File

@ -69,12 +69,12 @@ class DatabaseResource extends Resource
return $schema return $schema
->components([ ->components([
TextInput::make('host') TextInput::make('host')
->formatStateUsing(fn (Database $database) => $database->address()), ->formatStateUsing(fn (Database $database) => $database->address())
// TODO ->suffixAction(fn (string $state) => request()->isSecure() ? CopyAction::make()->copyable($state) : null), ->suffixCopy(),
TextInput::make('database'), TextInput::make('database')
//TODO ->suffixAction(fn (string $state) => request()->isSecure() ? CopyAction::make()->copyable($state) : null), ->suffixCopy(),
TextInput::make('username'), TextInput::make('username')
//TODO ->suffixAction(fn (string $state) => request()->isSecure() ? CopyAction::make()->copyable($state) : null), ->suffixCopy(),
TextInput::make('password') TextInput::make('password')
->password()->revealable() ->password()->revealable()
->hidden(fn () => !auth()->user()->can(Permission::ACTION_DATABASE_VIEW_PASSWORD, $server)) ->hidden(fn () => !auth()->user()->can(Permission::ACTION_DATABASE_VIEW_PASSWORD, $server))
@ -82,7 +82,7 @@ class DatabaseResource extends Resource
RotateDatabasePasswordAction::make() RotateDatabasePasswordAction::make()
->authorize(fn () => auth()->user()->can(Permission::ACTION_DATABASE_UPDATE, $server)) ->authorize(fn () => auth()->user()->can(Permission::ACTION_DATABASE_UPDATE, $server))
) )
//TODO ->suffixAction(fn (string $state) => request()->isSecure() ? CopyAction::make()->copyable($state) : null) ->suffixCopy()
->formatStateUsing(fn (Database $database) => $database->password), ->formatStateUsing(fn (Database $database) => $database->password),
TextInput::make('remote') TextInput::make('remote')
->label('Connections From'), ->label('Connections From'),
@ -92,7 +92,7 @@ class DatabaseResource extends Resource
->label('JDBC Connection String') ->label('JDBC Connection String')
->password()->revealable() ->password()->revealable()
->hidden(!auth()->user()->can(Permission::ACTION_DATABASE_VIEW_PASSWORD, $server)) ->hidden(!auth()->user()->can(Permission::ACTION_DATABASE_VIEW_PASSWORD, $server))
//TODO ->suffixAction(fn (string $state) => request()->isSecure() ? CopyAction::make()->copyable($state) : null) ->suffixCopy()
->columnSpanFull() ->columnSpanFull()
->formatStateUsing(fn (Database $database) => $database->jdbc), ->formatStateUsing(fn (Database $database) => $database->jdbc),
]); ]);

View File

@ -48,14 +48,14 @@ class QueueStep
TextInput::make('crontab') TextInput::make('crontab')
->label(new HtmlString('Run the following command to set up your crontab. Note that <code>www-data</code> is your webserver user. On some systems this username might be different!')) ->label(new HtmlString('Run the following command to set up your crontab. Note that <code>www-data</code> is your webserver user. On some systems this username might be different!'))
->disabled() ->disabled()
//TODO ->hintAction(fn () => request()->isSecure() ? CopyAction::make() : null) ->hintCopy()
->default('(crontab -l -u www-data 2>/dev/null; echo "* * * * * php ' . base_path() . '/artisan schedule:run >> /dev/null 2>&1") | crontab -u www-data -') ->default('(crontab -l -u www-data 2>/dev/null; echo "* * * * * php ' . base_path() . '/artisan schedule:run >> /dev/null 2>&1") | crontab -u www-data -')
->hidden(fn () => @file_exists('/.dockerenv')) ->hidden(fn () => @file_exists('/.dockerenv'))
->columnSpanFull(), ->columnSpanFull(),
TextInput::make('queueService') TextInput::make('queueService')
->label(new HtmlString('To setup the queue worker service you simply have to run the following command.')) ->label(new HtmlString('To setup the queue worker service you simply have to run the following command.'))
->disabled() ->disabled()
//TODO ->hintAction(fn () => request()->isSecure() ? CopyAction::make() : null) ->hintCopy()
->default('sudo php ' . base_path() . '/artisan p:environment:queue-service') ->default('sudo php ' . base_path() . '/artisan p:environment:queue-service')
->hidden(fn () => @file_exists('/.dockerenv')) ->hidden(fn () => @file_exists('/.dockerenv'))
->columnSpanFull(), ->columnSpanFull(),

View File

@ -36,10 +36,13 @@ use App\Extensions\OAuth\Providers\CommonProvider;
use App\Extensions\OAuth\Providers\DiscordProvider; use App\Extensions\OAuth\Providers\DiscordProvider;
use App\Extensions\OAuth\Providers\GithubProvider; use App\Extensions\OAuth\Providers\GithubProvider;
use App\Extensions\OAuth\Providers\SteamProvider; use App\Extensions\OAuth\Providers\SteamProvider;
use App\Filament\Components\Actions\CopyAction;
use App\Services\Helpers\SoftwareVersionService; use App\Services\Helpers\SoftwareVersionService;
use Dedoc\Scramble\Scramble; use Dedoc\Scramble\Scramble;
use Dedoc\Scramble\Support\Generator\OpenApi; use Dedoc\Scramble\Support\Generator\OpenApi;
use Dedoc\Scramble\Support\Generator\SecurityScheme; use Dedoc\Scramble\Support\Generator\SecurityScheme;
use Filament\Forms\Components\Field;
use Filament\Forms\Components\TextInput;
use Filament\Support\Colors\Color; use Filament\Support\Colors\Color;
use Filament\Support\Facades\FilamentColor; use Filament\Support\Facades\FilamentColor;
use Filament\Support\Facades\FilamentView; use Filament\Support\Facades\FilamentView;
@ -190,6 +193,16 @@ class AppServiceProvider extends ServiceProvider
$component->dispatch('alertBannerSent'); $component->dispatch('alertBannerSent');
}); });
Field::macro('suffixCopy', function () {
/** @var TextInput $this */
return $this->suffixAction(fn (string $state) => request()->isSecure() ? CopyAction::make()->copyable($state) : null); // @phpstan-ignore varTag.nativeType
});
Field::macro('hintCopy', function () {
/** @var Field $this */
return $this->hintAction(fn (string $state) => request()->isSecure() ? CopyAction::make()->copyable($state) : null); // @phpstan-ignore varTag.nativeType
});
// Don't run any health checks during tests // Don't run any health checks during tests
if (!$app->runningUnitTests()) { if (!$app->runningUnitTests()) {
Health::checks([ Health::checks([

View File

@ -14,6 +14,9 @@ parameters:
ignoreErrors: ignoreErrors:
- identifier: argument.templateType - identifier: argument.templateType
- identifier: missingType.generics - identifier: missingType.generics
- '#Call to an undefined method Filament\\Forms\\Components\\TextInput::suffixCopy\(\)#'
- '#Call to an undefined method Filament\\Forms\\Components\\TextInput::hintCopy\(\)#'
- '#Call to an undefined method Filament\\Forms\\Components\\Textarea::hintCopy\(\)#'
# We are getting and setting environment variables directly # We are getting and setting environment variables directly
- -