mirror of
https://github.com/pelican-dev/panel.git
synced 2025-09-25 17:58:08 +02:00
Allow clipboard.writeText without HTTPS (#1723)
This commit is contained in:
parent
e3b3c92dcb
commit
a5858a6d9b
@ -79,7 +79,7 @@ class ApiKeyResource extends Resource
|
|||||||
->label(trans('admin/apikey.table.key'))
|
->label(trans('admin/apikey.table.key'))
|
||||||
->icon('tabler-clipboard-text')
|
->icon('tabler-clipboard-text')
|
||||||
->state(fn (ApiKey $key) => $key->identifier . $key->token)
|
->state(fn (ApiKey $key) => $key->identifier . $key->token)
|
||||||
->copyable(fn () => request()->isSecure()),
|
->copyable(),
|
||||||
TextColumn::make('memo')
|
TextColumn::make('memo')
|
||||||
->label(trans('admin/apikey.table.description'))
|
->label(trans('admin/apikey.table.description'))
|
||||||
->wrap()
|
->wrap()
|
||||||
|
@ -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)
|
||||||
->copyable(fn () => request()->isSecure())
|
->copyable()
|
||||||
->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)
|
||||||
->copyable(fn () => request()->isSecure())
|
->copyable()
|
||||||
->columnSpanFull(),
|
->columnSpanFull(),
|
||||||
TextEntry::make('cli_exit')
|
TextEntry::make('cli_exit')
|
||||||
->hiddenLabel()
|
->hiddenLabel()
|
||||||
|
@ -179,7 +179,7 @@ class EditServer extends EditRecord
|
|||||||
|
|
||||||
TextInput::make('uuid')
|
TextInput::make('uuid')
|
||||||
->label(trans('admin/server.uuid'))
|
->label(trans('admin/server.uuid'))
|
||||||
->copyable(fn () => request()->isSecure())
|
->copyable()
|
||||||
->columnSpan([
|
->columnSpan([
|
||||||
'default' => 2,
|
'default' => 2,
|
||||||
'sm' => 1,
|
'sm' => 1,
|
||||||
@ -190,7 +190,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'))
|
||||||
->copyable(fn () => request()->isSecure())
|
->copyable()
|
||||||
->columnSpan([
|
->columnSpan([
|
||||||
'default' => 2,
|
'default' => 2,
|
||||||
'sm' => 1,
|
'sm' => 1,
|
||||||
|
@ -77,7 +77,7 @@ class ListServers extends ListRecords
|
|||||||
->label('')
|
->label('')
|
||||||
->badge()
|
->badge()
|
||||||
->visibleFrom('md')
|
->visibleFrom('md')
|
||||||
->copyable(request()->isSecure())
|
->copyable()
|
||||||
->state(fn (Server $server) => $server->allocation->address ?? 'None'),
|
->state(fn (Server $server) => $server->allocation->address ?? 'None'),
|
||||||
TextColumn::make('cpuUsage')
|
TextColumn::make('cpuUsage')
|
||||||
->label(trans('server/dashboard.resources'))
|
->label(trans('server/dashboard.resources'))
|
||||||
|
@ -2,28 +2,12 @@
|
|||||||
|
|
||||||
namespace App\Filament\Server\Components;
|
namespace App\Filament\Server\Components;
|
||||||
|
|
||||||
use Closure;
|
use Filament\Support\Concerns\CanBeCopied;
|
||||||
use Filament\Widgets\StatsOverviewWidget\Stat;
|
use Filament\Widgets\StatsOverviewWidget\Stat;
|
||||||
use Illuminate\Contracts\View\View;
|
|
||||||
|
|
||||||
class SmallStatBlock extends Stat
|
class SmallStatBlock extends Stat
|
||||||
{
|
{
|
||||||
protected bool|Closure $copyOnClick = false;
|
use CanBeCopied;
|
||||||
|
|
||||||
public function copyOnClick(bool|Closure $copyOnClick = true): static
|
protected string $view = 'filament.components.server-small-data-block';
|
||||||
{
|
|
||||||
$this->copyOnClick = $copyOnClick;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function shouldCopyOnClick(): bool
|
|
||||||
{
|
|
||||||
return $this->evaluate($this->copyOnClick);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function render(): View
|
|
||||||
{
|
|
||||||
return view('filament.components.server-small-data-block', array_merge($this->getViewData(), $this->extractPublicMethods()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -165,7 +165,7 @@ class Settings extends ServerFormPage
|
|||||||
->label(trans('server/setting.server_info.sftp.connection'))
|
->label(trans('server/setting.server_info.sftp.connection'))
|
||||||
->columnSpan(1)
|
->columnSpan(1)
|
||||||
->disabled()
|
->disabled()
|
||||||
->copyable(fn () => request()->isSecure())
|
->copyable()
|
||||||
->hintAction(
|
->hintAction(
|
||||||
Action::make('connect_sftp')
|
Action::make('connect_sftp')
|
||||||
->label(trans('server/setting.server_info.sftp.action'))
|
->label(trans('server/setting.server_info.sftp.action'))
|
||||||
@ -185,7 +185,7 @@ class Settings extends ServerFormPage
|
|||||||
TextInput::make('username')
|
TextInput::make('username')
|
||||||
->label(trans('server/setting.server_info.sftp.username'))
|
->label(trans('server/setting.server_info.sftp.username'))
|
||||||
->columnSpan(1)
|
->columnSpan(1)
|
||||||
->copyable(fn () => request()->isSecure())
|
->copyable()
|
||||||
->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')
|
||||||
|
@ -78,13 +78,13 @@ class DatabaseResource extends Resource
|
|||||||
TextInput::make('host')
|
TextInput::make('host')
|
||||||
->label(trans('server/database.host'))
|
->label(trans('server/database.host'))
|
||||||
->formatStateUsing(fn (Database $database) => $database->address())
|
->formatStateUsing(fn (Database $database) => $database->address())
|
||||||
->copyable(fn () => request()->isSecure()),
|
->copyable(),
|
||||||
TextInput::make('database')
|
TextInput::make('database')
|
||||||
->label(trans('server/database.database'))
|
->label(trans('server/database.database'))
|
||||||
->copyable(fn () => request()->isSecure()),
|
->copyable(),
|
||||||
TextInput::make('username')
|
TextInput::make('username')
|
||||||
->label(trans('server/database.username'))
|
->label(trans('server/database.username'))
|
||||||
->copyable(fn () => request()->isSecure()),
|
->copyable(),
|
||||||
TextInput::make('password')
|
TextInput::make('password')
|
||||||
->label(trans('server/database.password'))
|
->label(trans('server/database.password'))
|
||||||
->password()->revealable()
|
->password()->revealable()
|
||||||
@ -93,7 +93,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))
|
||||||
)
|
)
|
||||||
->copyable(fn () => request()->isSecure())
|
->copyable()
|
||||||
->formatStateUsing(fn (Database $database) => $database->password),
|
->formatStateUsing(fn (Database $database) => $database->password),
|
||||||
TextInput::make('remote')
|
TextInput::make('remote')
|
||||||
->label(trans('server/database.remote')),
|
->label(trans('server/database.remote')),
|
||||||
@ -104,7 +104,7 @@ class DatabaseResource extends Resource
|
|||||||
->label(trans('server/database.jdbc'))
|
->label(trans('server/database.jdbc'))
|
||||||
->password()->revealable()
|
->password()->revealable()
|
||||||
->hidden(!auth()->user()->can(Permission::ACTION_DATABASE_VIEW_PASSWORD, $server))
|
->hidden(!auth()->user()->can(Permission::ACTION_DATABASE_VIEW_PASSWORD, $server))
|
||||||
->copyable(fn () => request()->isSecure())
|
->copyable()
|
||||||
->columnSpanFull()
|
->columnSpanFull()
|
||||||
->formatStateUsing(fn (Database $database) => $database->jdbc),
|
->formatStateUsing(fn (Database $database) => $database->jdbc),
|
||||||
]);
|
]);
|
||||||
|
@ -6,9 +6,7 @@ use App\Enums\ContainerStatus;
|
|||||||
use App\Filament\Server\Components\SmallStatBlock;
|
use App\Filament\Server\Components\SmallStatBlock;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Carbon\CarbonInterface;
|
use Carbon\CarbonInterface;
|
||||||
use Filament\Notifications\Notification;
|
|
||||||
use Filament\Widgets\StatsOverviewWidget;
|
use Filament\Widgets\StatsOverviewWidget;
|
||||||
use Livewire\Attributes\On;
|
|
||||||
|
|
||||||
class ServerOverview extends StatsOverviewWidget
|
class ServerOverview extends StatsOverviewWidget
|
||||||
{
|
{
|
||||||
@ -20,10 +18,10 @@ class ServerOverview extends StatsOverviewWidget
|
|||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
SmallStatBlock::make(trans('server/console.labels.name'), $this->server->name)
|
SmallStatBlock::make(trans('server/console.labels.name'), $this->server->name)
|
||||||
->copyOnClick(fn () => request()->isSecure()),
|
->copyable(),
|
||||||
SmallStatBlock::make(trans('server/console.labels.status'), $this->status()),
|
SmallStatBlock::make(trans('server/console.labels.status'), $this->status()),
|
||||||
SmallStatBlock::make(trans('server/console.labels.address'), $this->server?->allocation->address ?? 'None')
|
SmallStatBlock::make(trans('server/console.labels.address'), $this->server?->allocation->address ?? 'None')
|
||||||
->copyOnClick(fn () => request()->isSecure()),
|
->copyable(),
|
||||||
SmallStatBlock::make(trans('server/console.labels.cpu'), $this->cpuUsage()),
|
SmallStatBlock::make(trans('server/console.labels.cpu'), $this->cpuUsage()),
|
||||||
SmallStatBlock::make(trans('server/console.labels.memory'), $this->memoryUsage()),
|
SmallStatBlock::make(trans('server/console.labels.memory'), $this->memoryUsage()),
|
||||||
SmallStatBlock::make(trans('server/console.labels.disk'), $this->diskUsage()),
|
SmallStatBlock::make(trans('server/console.labels.disk'), $this->diskUsage()),
|
||||||
@ -90,16 +88,4 @@ class ServerOverview extends StatsOverviewWidget
|
|||||||
|
|
||||||
return $used . ($this->server->disk > 0 ? ' / ' . $total : ' / ∞');
|
return $used . ($this->server->disk > 0 ? ' / ' . $total : ' / ∞');
|
||||||
}
|
}
|
||||||
|
|
||||||
#[On('copyClick')]
|
|
||||||
public function copyClick(string $value): void
|
|
||||||
{
|
|
||||||
$this->js("window.navigator.clipboard.writeText('{$value}');");
|
|
||||||
|
|
||||||
Notification::make()
|
|
||||||
->title(trans('server/dashboard.copied'))
|
|
||||||
->body($value)
|
|
||||||
->success()
|
|
||||||
->send();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -152,7 +152,7 @@ class AppServiceProvider extends ServiceProvider
|
|||||||
|
|
||||||
Field::macro('hintCopy', function () {
|
Field::macro('hintCopy', function () {
|
||||||
/** @var Field $this */
|
/** @var Field $this */
|
||||||
return $this->hintAction(fn () => request()->isSecure() ? CopyAction::make() : null); // @phpstan-ignore varTag.nativeType
|
return $this->hintAction(CopyAction::make()); // @phpstan-ignore varTag.nativeType
|
||||||
});
|
});
|
||||||
|
|
||||||
// Don't run any health checks during tests
|
// Don't run any health checks during tests
|
||||||
|
@ -25,6 +25,4 @@ return [
|
|||||||
|
|
||||||
'power_actions' => 'Power Actions',
|
'power_actions' => 'Power Actions',
|
||||||
'power_action_sent' => ':action sent to :name',
|
'power_action_sent' => ':action sent to :name',
|
||||||
|
|
||||||
'copied' => 'Copied to clipboard',
|
|
||||||
];
|
];
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
(() => {
|
||||||
|
if (navigator.clipboard && typeof navigator.clipboard.writeText === 'function') return;
|
||||||
|
navigator.clipboard = navigator.clipboard || {};
|
||||||
|
navigator.clipboard.writeText = async (text) =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
const textarea = document.createElement('textarea');
|
||||||
|
textarea.value = text;
|
||||||
|
textarea.style.position = 'fixed';
|
||||||
|
textarea.style.left = '-9999px';
|
||||||
|
textarea.style.opacity = '0';
|
||||||
|
document.body.appendChild(textarea);
|
||||||
|
textarea.select();
|
||||||
|
const success = document.execCommand('copy');
|
||||||
|
document.body.removeChild(textarea);
|
||||||
|
success ? resolve() : reject('Fallback copy failed');
|
||||||
|
});
|
||||||
|
})();
|
@ -102,7 +102,7 @@
|
|||||||
|
|
||||||
terminal.attachCustomKeyEventHandler((event) => {
|
terminal.attachCustomKeyEventHandler((event) => {
|
||||||
if ((event.ctrlKey || event.metaKey) && event.key === 'c') {
|
if ((event.ctrlKey || event.metaKey) && event.key === 'c') {
|
||||||
document.execCommand('copy'); // navigator.clipboard.writeText() only works on ssl..
|
navigator.clipboard.writeText(terminal.getSelection())
|
||||||
return false;
|
return false;
|
||||||
} else if ((event.ctrlKey || event.metaKey) && event.key === 'f') {
|
} else if ((event.ctrlKey || event.metaKey) && event.key === 'f') {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
<div class="fi-small-stat-block grid grid-flow-row w-full p-3 rounded-lg bg-white shadow-sm overflow-hidden overflow-x-auto ring-1 ring-gray-950/5 dark:bg-gray-900 dark:ring-white/10">
|
<div class="fi-small-stat-block grid grid-flow-row w-full p-3 rounded-lg bg-white shadow-sm overflow-hidden overflow-x-auto ring-1 ring-gray-950/5 dark:bg-gray-900 dark:ring-white/10">
|
||||||
@if ($shouldCopyOnClick())
|
@if ($isCopyable($value = $getValue()))
|
||||||
<span class="cursor-pointer" wire:click="copyClick('{{ $getValue() }}')">
|
<span class="cursor-pointer" x-on:click="
|
||||||
|
navigator.clipboard.writeText(@js($value));
|
||||||
|
$tooltip(@js($getCopyMessage($value)), {
|
||||||
|
theme: $store.theme,
|
||||||
|
timeout: 2000,
|
||||||
|
})">
|
||||||
@else
|
@else
|
||||||
<span>
|
<span>
|
||||||
@endif
|
@endif
|
||||||
@ -8,7 +13,7 @@
|
|||||||
{{ $getLabel() }}
|
{{ $getLabel() }}
|
||||||
</span>
|
</span>
|
||||||
<span class="text-md font-semibold">
|
<span class="text-md font-semibold">
|
||||||
{{ $getValue() }}
|
{{ $value }}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user