Fix various Translations & add Installer & add Notifications (#1632)

This commit is contained in:
MartinOscar 2025-09-04 20:17:59 +02:00 committed by GitHub
parent 3543b4773a
commit 6671d45651
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
67 changed files with 415 additions and 191 deletions

View File

@ -64,7 +64,7 @@ class ProcessRunnableCommand extends Command
} catch (Throwable $exception) { } catch (Throwable $exception) {
logger()->error($exception, ['schedule_id' => $schedule->id]); logger()->error($exception, ['schedule_id' => $schedule->id]);
$this->error(trans('commands.schedule.process.no_tasks') . " #$schedule->id: " . $exception->getMessage()); $this->error(trans('commands.schedule.process.error_message', ['schedules' => " #$schedule->id: " . $exception->getMessage()]));
} }
} }
} }

View File

@ -19,7 +19,7 @@ class DisableTwoFactorCommand extends Command
public function handle(): void public function handle(): void
{ {
if ($this->input->isInteractive()) { if ($this->input->isInteractive()) {
$this->output->warning(trans('command/messages.user.2fa_help_text.0') . trans('command/messages.user.2fa_help_text.1')); $this->output->warning(trans('command/messages.user.2fa_help_text'));
} }
$email = $this->option('email') ?? $this->ask(trans('command/messages.user.ask_email')); $email = $this->option('email') ?? $this->ask(trans('command/messages.user.ask_email'));

View File

@ -32,6 +32,6 @@ enum BackupStatus: string implements HasColor, HasIcon, HasLabel
public function getLabel(): string public function getLabel(): string
{ {
return trans('server/backup.backup_status.' . strtolower($this->value)); return trans('server/backup.backup_status.' . $this->value);
} }
} }

View File

@ -68,7 +68,7 @@ enum ContainerStatus: string implements HasColor, HasIcon, HasLabel
public function getLabel(): string public function getLabel(): string
{ {
return trans('server/console.status.' . strtolower($this->value)); return trans('server/console.status.' . $this->value);
} }
public function isOffline(): bool public function isOffline(): bool

View File

@ -123,7 +123,7 @@ class Health extends Page
return $carry; return $carry;
}, []); }, []);
return trans('admin/health.checks.failed') . implode(', ', $failedNames); return trans('admin/health.checks.failed', ['checks' => implode(', ', $failedNames)]);
} }
public static function getNavigationIcon(): string public static function getNavigationIcon(): string

View File

@ -119,7 +119,7 @@ class Settings extends Page implements HasForms
->label(trans('admin/setting.navigation.backup')) ->label(trans('admin/setting.navigation.backup'))
->icon('tabler-box') ->icon('tabler-box')
->schema($this->backupSettings()), ->schema($this->backupSettings()),
Tab::make('OAuth') Tab::make('oauth')
->label(trans('admin/setting.navigation.oauth')) ->label(trans('admin/setting.navigation.oauth'))
->icon('tabler-brand-oauth') ->icon('tabler-brand-oauth')
->schema($this->oauthSettings()), ->schema($this->oauthSettings()),
@ -553,7 +553,7 @@ class Settings extends Page implements HasForms
->label(trans('admin/setting.oauth.enable')) ->label(trans('admin/setting.oauth.enable'))
->color('success') ->color('success')
->steps($schema->getSetupSteps()) ->steps($schema->getSetupSteps())
->modalHeading(trans('admin/setting.oauth.enable') . ' ' . $schema->getName()) ->modalHeading(trans('admin/setting.oauth.enable_schema', ['schema' => $schema->getName()]))
->modalSubmitActionLabel(trans('admin/setting.oauth.enable')) ->modalSubmitActionLabel(trans('admin/setting.oauth.enable'))
->modalCancelAction(false) ->modalCancelAction(false)
->action(function ($data, Set $set) use ($key) { ->action(function ($data, Set $set) use ($key) {

View File

@ -96,7 +96,7 @@ class ApiKeyResource extends Resource
]) ])
->emptyStateIcon('tabler-key') ->emptyStateIcon('tabler-key')
->emptyStateDescription('') ->emptyStateDescription('')
->emptyStateHeading(trans('admin/apikey.empty_table')) ->emptyStateHeading(trans('admin/apikey.empty'))
->emptyStateActions([ ->emptyStateActions([
CreateAction::make(), CreateAction::make(),
]); ]);

View File

@ -57,7 +57,8 @@ class CreateEgg extends CreateRecord
return $form return $form
->schema([ ->schema([
Tabs::make()->tabs([ Tabs::make()->tabs([
Tab::make(trans('admin/egg.tabs.configuration')) Tab::make('configuration')
->label(trans('admin/egg.tabs.configuration'))
->columns(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 4]) ->columns(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 4])
->schema([ ->schema([
TextInput::make('name') TextInput::make('name')
@ -123,7 +124,8 @@ class CreateEgg extends CreateRecord
->helperText(trans('admin/egg.docker_help')), ->helperText(trans('admin/egg.docker_help')),
]), ]),
Tab::make(trans('admin/egg.tabs.process_management')) Tab::make('process_management')
->label(trans('admin/egg.tabs.process_management'))
->columns() ->columns()
->schema([ ->schema([
CopyFrom::make('copy_process_from') CopyFrom::make('copy_process_from')
@ -146,7 +148,8 @@ class CreateEgg extends CreateRecord
->default('{}') ->default('{}')
->helperText(trans('admin/egg.log_config_help')), ->helperText(trans('admin/egg.log_config_help')),
]), ]),
Tab::make(trans('admin/egg.tabs.egg_variables')) Tab::make('egg_variables')
->label(trans('admin/egg.tabs.egg_variables'))
->columnSpanFull() ->columnSpanFull()
->schema([ ->schema([
Repeater::make('variables') Repeater::make('variables')
@ -239,7 +242,8 @@ class CreateEgg extends CreateRecord
]), ]),
]), ]),
]), ]),
Tab::make(trans('admin/egg.tabs.install_script')) Tab::make('install_script')
->label(trans('admin/egg.tabs.install_script'))
->columns(3) ->columns(3)
->schema([ ->schema([
CopyFrom::make('copy_script_from') CopyFrom::make('copy_script_from')

View File

@ -44,7 +44,8 @@ class EditEgg extends EditRecord
return $form return $form
->schema([ ->schema([
Tabs::make()->tabs([ Tabs::make()->tabs([
Tab::make(trans('admin/egg.tabs.configuration')) Tab::make('configuration')
->label(trans('admin/egg.tabs.configuration'))
->columns(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 4]) ->columns(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 4])
->icon('tabler-egg') ->icon('tabler-egg')
->schema([ ->schema([
@ -115,7 +116,8 @@ class EditEgg extends EditRecord
->valueLabel(trans('admin/egg.docker_uri')) ->valueLabel(trans('admin/egg.docker_uri'))
->helperText(trans('admin/egg.docker_help')), ->helperText(trans('admin/egg.docker_help')),
]), ]),
Tab::make(trans('admin/egg.tabs.process_management')) Tab::make('process_management')
->label(trans('admin/egg.tabs.process_management'))
->columns() ->columns()
->icon('tabler-server-cog') ->icon('tabler-server-cog')
->schema([ ->schema([
@ -135,7 +137,8 @@ class EditEgg extends EditRecord
->label(trans('admin/egg.log_config')) ->label(trans('admin/egg.log_config'))
->helperText(trans('admin/egg.log_config_help')), ->helperText(trans('admin/egg.log_config_help')),
]), ]),
Tab::make(trans('admin/egg.tabs.egg_variables')) Tab::make('egg_variables')
->label(trans('admin/egg.tabs.egg_variables'))
->columnSpanFull() ->columnSpanFull()
->icon('tabler-variable') ->icon('tabler-variable')
->schema([ ->schema([
@ -228,7 +231,8 @@ class EditEgg extends EditRecord
]), ]),
]), ]),
]), ]),
Tab::make(trans('admin/egg.tabs.install_script')) Tab::make('install_script')
->label(trans('admin/egg.tabs.install_script'))
->columns(3) ->columns(3)
->icon('tabler-file-download') ->icon('tabler-file-download')
->schema([ ->schema([

View File

@ -22,7 +22,7 @@ class ServersRelationManager extends RelationManager
->heading(trans('admin/egg.servers')) ->heading(trans('admin/egg.servers'))
->columns([ ->columns([
TextColumn::make('user.username') TextColumn::make('user.username')
->label('Owner') ->label(trans('admin/server.owner'))
->icon('tabler-user') ->icon('tabler-user')
->url(fn (Server $server): string => route('filament.admin.resources.users.edit', ['record' => $server->user])) ->url(fn (Server $server): string => route('filament.admin.resources.users.edit', ['record' => $server->user]))
->sortable(), ->sortable(),

View File

@ -64,7 +64,7 @@ class EditNode extends EditRecord
->persistTabInQueryString() ->persistTabInQueryString()
->columnSpanFull() ->columnSpanFull()
->tabs([ ->tabs([
Tab::make('') Tab::make('overview')
->label(trans('admin/node.tabs.overview')) ->label(trans('admin/node.tabs.overview'))
->icon('tabler-chart-area-line-filled') ->icon('tabler-chart-area-line-filled')
->columns([ ->columns([
@ -80,7 +80,7 @@ class EditNode extends EditRecord
->schema([ ->schema([
Placeholder::make('') Placeholder::make('')
->label(trans('admin/node.wings_version')) ->label(trans('admin/node.wings_version'))
->content(fn (Node $node, SoftwareVersionService $versionService) => ($node->systemInformation()['version'] ?? trans('admin/node.unknown')) . ' (' . trans('admin/node.latest') . ': ' . $versionService->latestWingsVersion() . ')'), ->content(fn (Node $node, SoftwareVersionService $versionService) => ($node->systemInformation()['version'] ?? trans('admin/node.unknown')) . ' ' . trans('admin/node.latest', ['version' => $versionService->latestWingsVersion()])),
Placeholder::make('') Placeholder::make('')
->label(trans('admin/node.cpu_threads')) ->label(trans('admin/node.cpu_threads'))
->content(fn (Node $node) => $node->systemInformation()['cpu_count'] ?? 0), ->content(fn (Node $node) => $node->systemInformation()['cpu_count'] ?? 0),
@ -108,7 +108,8 @@ class EditNode extends EditRecord
View::make('filament.components.node-storage-chart') View::make('filament.components.node-storage-chart')
->columnSpanFull(), ->columnSpanFull(),
]), ]),
Tab::make(trans('admin/node.tabs.basic_settings')) Tab::make('basic_settings')
->label(trans('admin/node.tabs.basic_settings'))
->icon('tabler-server') ->icon('tabler-server')
->schema([ ->schema([
TextInput::make('fqdn') TextInput::make('fqdn')
@ -257,7 +258,7 @@ class EditNode extends EditRecord
->integer() ->integer()
->visible(fn (Get $get) => $get('connection') === 'https_proxy'), ->visible(fn (Get $get) => $get('connection') === 'https_proxy'),
]), ]),
Tab::make('adv') Tab::make('advanced_settings')
->label(trans('admin/node.tabs.advanced_settings')) ->label(trans('admin/node.tabs.advanced_settings'))
->columns([ ->columns([
'default' => 1, 'default' => 1,
@ -525,7 +526,7 @@ class EditNode extends EditRecord
->suffix('%'), ->suffix('%'),
]), ]),
]), ]),
Tab::make('Config') Tab::make('config_file')
->label(trans('admin/node.tabs.config_file')) ->label(trans('admin/node.tabs.config_file'))
->icon('tabler-code') ->icon('tabler-code')
->schema([ ->schema([
@ -553,7 +554,7 @@ class EditNode extends EditRecord
->modalFooterActionsAlignment(Alignment::Center) ->modalFooterActionsAlignment(Alignment::Center)
->form([ ->form([
ToggleButtons::make('docker') ToggleButtons::make('docker')
->label('Type') ->label(trans('admin/node.auto_label'))
->live() ->live()
->helperText(trans('admin/node.auto_question')) ->helperText(trans('admin/node.auto_question'))
->inline() ->inline()

View File

@ -129,7 +129,6 @@ class RoleResource extends Resource
->required() ->required()
->disabled(fn (Get $get) => $get('name') === Role::ROOT_ADMIN), ->disabled(fn (Get $get) => $get('name') === Role::ROOT_ADMIN),
TextInput::make('guard_name') TextInput::make('guard_name')
->label('Guard Name')
->default(Role::DEFAULT_GUARD_NAME) ->default(Role::DEFAULT_GUARD_NAME)
->nullable() ->nullable()
->hidden(), ->hidden(),

View File

@ -264,7 +264,7 @@ class CreateServer extends CreateRecord
->preload() ->preload()
->disableOptionsWhenSelectedInSiblingRepeaterItems() ->disableOptionsWhenSelectedInSiblingRepeaterItems()
->prefixIcon('tabler-network') ->prefixIcon('tabler-network')
->label('Additional Allocations') ->label(trans('admin/server.additional_allocations'))
->columnSpan(2) ->columnSpan(2)
->disabled(fn (Get $get) => $get('../../allocation_id') === null || $get('../../node_id') === null) ->disabled(fn (Get $get) => $get('../../allocation_id') === null || $get('../../node_id') === null)
->searchable(['ip', 'port', 'ip_alias']) ->searchable(['ip', 'port', 'ip_alias'])
@ -761,7 +761,7 @@ class CreateServer extends CreateRecord
KeyValue::make('docker_labels') KeyValue::make('docker_labels')
->live() ->live()
->label('Container Labels') ->label(trans('admin/server.container_labels'))
->keyLabel(trans('admin/server.title')) ->keyLabel(trans('admin/server.title'))
->valueLabel(trans('admin/server.description')) ->valueLabel(trans('admin/server.description'))
->columnSpanFull(), ->columnSpanFull(),

View File

@ -87,7 +87,8 @@ class EditServer extends EditRecord
]) ])
->columnSpanFull() ->columnSpanFull()
->tabs([ ->tabs([
Tab::make(trans('admin/server.tabs.information')) Tab::make('information')
->label(trans('admin/server.tabs.information'))
->icon('tabler-info-circle') ->icon('tabler-info-circle')
->schema([ ->schema([
TextInput::make('name') TextInput::make('name')
@ -219,7 +220,8 @@ class EditServer extends EditRecord
]) ])
->disabled(), ->disabled(),
]), ]),
Tab::make(trans('admin/server.tabs.environment_configuration')) Tab::make('environment_configuration')
->label(trans('admin/server.tabs.environment_configuration'))
->icon('tabler-brand-docker') ->icon('tabler-brand-docker')
->schema([ ->schema([
Fieldset::make(trans('admin/server.resource_limits')) Fieldset::make(trans('admin/server.resource_limits'))
@ -526,7 +528,8 @@ class EditServer extends EditRecord
->columnSpanFull(), ->columnSpanFull(),
]), ]),
]), ]),
Tab::make(trans('admin/server.egg')) Tab::make('egg')
->label(trans('admin/server.egg'))
->icon('tabler-egg') ->icon('tabler-egg')
->columns([ ->columns([
'default' => 1, 'default' => 1,
@ -644,12 +647,14 @@ class EditServer extends EditRecord
]) ])
->columnSpan(6), ->columnSpan(6),
]), ]),
Tab::make(trans('admin/server.mounts')) Tab::make('mounts')
->label(trans('admin/server.mounts'))
->icon('tabler-layers-linked') ->icon('tabler-layers-linked')
->schema(fn (Get $get) => [ ->schema(fn (Get $get) => [
ServerResource::getMountCheckboxList($get), ServerResource::getMountCheckboxList($get),
]), ]),
Tab::make(trans('admin/server.databases')) Tab::make('databases')
->label(trans('admin/server.databases'))
->hidden(fn () => !auth()->user()->can('viewAny', Database::class)) ->hidden(fn () => !auth()->user()->can('viewAny', Database::class))
->icon('tabler-database') ->icon('tabler-database')
->columns(4) ->columns(4)
@ -779,7 +784,8 @@ class EditServer extends EditRecord
]), ]),
])->alignCenter()->columnSpanFull(), ])->alignCenter()->columnSpanFull(),
]), ]),
Tab::make(trans('admin/server.actions')) Tab::make('actions')
->label(trans('admin/server.actions'))
->icon('tabler-settings') ->icon('tabler-settings')
->schema([ ->schema([
Fieldset::make(trans('admin/server.actions')) Fieldset::make(trans('admin/server.actions'))
@ -912,12 +918,12 @@ class EditServer extends EditRecord
$transfer->handle($server, Arr::get($data, 'node_id'), Arr::get($data, 'allocation_id'), Arr::get($data, 'allocation_additional', [])); $transfer->handle($server, Arr::get($data, 'node_id'), Arr::get($data, 'allocation_id'), Arr::get($data, 'allocation_additional', []));
Notification::make() Notification::make()
->title('Transfer started') ->title(trans('admin/server.notifications.transfer_started'))
->success() ->success()
->send(); ->send();
} catch (Exception $exception) { } catch (Exception $exception) {
Notification::make() Notification::make()
->title('Transfer failed') ->title(trans('admin/server.notifications.transfer_failed'))
->body($exception->getMessage()) ->body($exception->getMessage())
->danger() ->danger()
->send(); ->send();

View File

@ -80,7 +80,7 @@ class UserResource extends Resource
->label(trans('admin/user.email')) ->label(trans('admin/user.email'))
->icon('tabler-mail'), ->icon('tabler-mail'),
IconColumn::make('use_totp') IconColumn::make('use_totp')
->label('2FA') ->label(trans('profile.tabs.2fa'))
->visibleFrom('lg') ->visibleFrom('lg')
->icon(fn (User $user) => $user->use_totp ? 'tabler-lock' : 'tabler-lock-open-off') ->icon(fn (User $user) => $user->use_totp ? 'tabler-lock' : 'tabler-lock-open-off')
->boolean(), ->boolean(),

View File

@ -211,7 +211,7 @@ class WebhookResource extends Resource
TextInput::make('thread_name') TextInput::make('thread_name')
->label(trans('admin/webhook.discord_message.forum_thread')), ->label(trans('admin/webhook.discord_message.forum_thread')),
CheckboxList::make('flags') CheckboxList::make('flags')
->label('Flags') ->label(trans('admin/webhook.discord_embed.flags'))
->options([ ->options([
(1 << 2) => trans('admin/webhook.discord_message.supress_embeds'), (1 << 2) => trans('admin/webhook.discord_message.supress_embeds'),
(1 << 12) => trans('admin/webhook.discord_message.supress_notifications'), (1 << 12) => trans('admin/webhook.discord_message.supress_notifications'),

View File

@ -61,13 +61,13 @@ class ListServers extends ListRecords
{ {
return [ return [
TextColumn::make('condition') TextColumn::make('condition')
->label('Status') ->label(trans('server/dashboard.status'))
->badge() ->badge()
->tooltip(fn (Server $server) => $server->formatResource(ServerResourceType::Uptime)) ->tooltip(fn (Server $server) => $server->formatResource(ServerResourceType::Uptime))
->icon(fn (Server $server) => $server->condition->getIcon()) ->icon(fn (Server $server) => $server->condition->getIcon())
->color(fn (Server $server) => $server->condition->getColor()), ->color(fn (Server $server) => $server->condition->getColor()),
TextColumn::make('name') TextColumn::make('name')
->label('Server') ->label(trans('server/dashboard.title'))
->description(fn (Server $server) => $server->description) ->description(fn (Server $server) => $server->description)
->grow() ->grow()
->searchable(), ->searchable(),
@ -142,15 +142,18 @@ class ListServers extends ListRecords
$other = (clone $all)->whereNot('owner_id', auth()->user()->id); $other = (clone $all)->whereNot('owner_id', auth()->user()->id);
return [ return [
'my' => Tab::make('My Servers') 'my' => Tab::make('my')
->label(trans('server/dashboard.tabs.my'))
->badge(fn () => $my->count()) ->badge(fn () => $my->count())
->modifyQueryUsing(fn () => $my), ->modifyQueryUsing(fn () => $my),
'other' => Tab::make('Others\' Servers') 'other' => Tab::make('other')
->label(trans('server/dashboard.tabs.other'))
->badge(fn () => $other->count()) ->badge(fn () => $other->count())
->modifyQueryUsing(fn () => $other), ->modifyQueryUsing(fn () => $other),
'all' => Tab::make('All Servers') 'all' => Tab::make('all')
->label(trans('server/dashboard.tabs.all'))
->badge($all->count()), ->badge($all->count()),
]; ];
} }
@ -204,8 +207,8 @@ class ListServers extends ListRecords
$this->daemonPowerRepository->setServer($server)->send($action); $this->daemonPowerRepository->setServer($server)->send($action);
Notification::make() Notification::make()
->title('Power Action') ->title(trans('server/dashboard.power_actions'))
->body($action . ' sent to ' . $server->name) ->body(trans('server/dashboard.power_action_sent', ['action' => $action, 'name' => $server->name]))
->success() ->success()
->send(); ->send();

View File

@ -37,13 +37,13 @@ class ExportEggAction extends Action
$this->modalFooterActions([ $this->modalFooterActions([
Action::make('json') Action::make('json')
->label(trans('admin/egg.export.as') . ' .json') ->label(trans('admin/egg.export.as', ['format' => 'json']))
->action(fn (EggExporterService $service, Egg $egg) => response()->streamDownload(function () use ($service, $egg) { ->action(fn (EggExporterService $service, Egg $egg) => response()->streamDownload(function () use ($service, $egg) {
echo $service->handle($egg->id, EggFormat::JSON); echo $service->handle($egg->id, EggFormat::JSON);
}, 'egg-' . $egg->getKebabName() . '.json')) }, 'egg-' . $egg->getKebabName() . '.json'))
->close(), ->close(),
Action::make('yaml') Action::make('yaml')
->label(trans('admin/egg.export.as') . ' .yaml') ->label(trans('admin/egg.export.as', ['format' => 'yaml']))
->action(fn (EggExporterService $service, Egg $egg) => response()->streamDownload(function () use ($service, $egg) { ->action(fn (EggExporterService $service, Egg $egg) => response()->streamDownload(function () use ($service, $egg) {
echo $service->handle($egg->id, EggFormat::YAML); echo $service->handle($egg->id, EggFormat::YAML);
}, 'egg-' . $egg->getKebabName() . '.yaml')) }, 'egg-' . $egg->getKebabName() . '.yaml'))

View File

@ -106,7 +106,8 @@ class ImportEggAction extends Action
Tabs::make('Tabs') Tabs::make('Tabs')
->contained(false) ->contained(false)
->tabs([ ->tabs([
Tab::make(trans('admin/egg.import.file')) Tab::make('file')
->label(trans('admin/egg.import.file'))
->icon('tabler-file-upload') ->icon('tabler-file-upload')
->schema([ ->schema([
FileUpload::make('files') FileUpload::make('files')
@ -118,7 +119,8 @@ class ImportEggAction extends Action
->storeFiles(false) ->storeFiles(false)
->multiple($isMultiple), ->multiple($isMultiple),
]), ]),
Tab::make(trans('admin/egg.import.url')) Tab::make('url')
->label(trans('admin/egg.import.url'))
->icon('tabler-world-upload') ->icon('tabler-world-upload')
->schema([ ->schema([
Select::make('github') Select::make('github')

View File

@ -39,7 +39,8 @@ class ImportScheduleAction extends Action
Tabs::make('Tabs') Tabs::make('Tabs')
->contained(false) ->contained(false)
->tabs([ ->tabs([
Tab::make(trans('server/schedule.import_action.file')) Tab::make('file')
->label(trans('server/schedule.import_action.file'))
->icon('tabler-file-upload') ->icon('tabler-file-upload')
->schema([ ->schema([
FileUpload::make('files') FileUpload::make('files')
@ -51,7 +52,8 @@ class ImportScheduleAction extends Action
->storeFiles(false) ->storeFiles(false)
->multiple(true), ->multiple(true),
]), ]),
Tab::make(trans('server/schedule.import_action.url')) Tab::make('url')
->label(trans('server/schedule.import_action.url'))
->icon('tabler-world-upload') ->icon('tabler-world-upload')
->schema([ ->schema([
Repeater::make('urls') Repeater::make('urls')

View File

@ -39,13 +39,13 @@ class ExportEggAction extends Action
$this->modalFooterActions([ $this->modalFooterActions([
Action::make('json') Action::make('json')
->label(trans('admin/egg.export.as') . ' .json') ->label(trans('admin/egg.export.as', ['format' => 'json']))
->action(fn (EggExporterService $service, Egg $egg) => response()->streamDownload(function () use ($service, $egg) { ->action(fn (EggExporterService $service, Egg $egg) => response()->streamDownload(function () use ($service, $egg) {
echo $service->handle($egg->id, EggFormat::JSON); echo $service->handle($egg->id, EggFormat::JSON);
}, 'egg-' . $egg->getKebabName() . '.json')) }, 'egg-' . $egg->getKebabName() . '.json'))
->close(), ->close(),
Action::make('yaml') Action::make('yaml')
->label(trans('admin/egg.export.as') . ' .yaml') ->label(trans('admin/egg.export.as', ['format' => 'yaml']))
->action(fn (EggExporterService $service, Egg $egg) => response()->streamDownload(function () use ($service, $egg) { ->action(fn (EggExporterService $service, Egg $egg) => response()->streamDownload(function () use ($service, $egg) {
echo $service->handle($egg->id, EggFormat::YAML); echo $service->handle($egg->id, EggFormat::YAML);
}, 'egg-' . $egg->getKebabName() . '.yaml')) }, 'egg-' . $egg->getKebabName() . '.yaml'))

View File

@ -86,7 +86,8 @@ class ImportEggAction extends Action
Tabs::make('Tabs') Tabs::make('Tabs')
->contained(false) ->contained(false)
->tabs([ ->tabs([
Tab::make(trans('admin/egg.import.file')) Tab::make('file')
->label(trans('admin/egg.import.file'))
->icon('tabler-file-upload') ->icon('tabler-file-upload')
->schema([ ->schema([
FileUpload::make('files') FileUpload::make('files')
@ -98,7 +99,8 @@ class ImportEggAction extends Action
->storeFiles(false) ->storeFiles(false)
->multiple($isMultiple), ->multiple($isMultiple),
]), ]),
Tab::make(trans('admin/egg.import.url')) Tab::make('url')
->label(trans('admin/egg.import.url'))
->icon('tabler-world-upload') ->icon('tabler-world-upload')
->schema([ ->schema([
Select::make('github') Select::make('github')

View File

@ -86,7 +86,8 @@ class EditProfile extends BaseEditProfile
->schema([ ->schema([
Tabs::make()->persistTabInQueryString() Tabs::make()->persistTabInQueryString()
->schema([ ->schema([
Tab::make(trans('profile.tabs.account')) Tab::make('account')
->label(trans('profile.tabs.account'))
->icon('tabler-user') ->icon('tabler-user')
->schema([ ->schema([
TextInput::make('username') TextInput::make('username')
@ -160,7 +161,8 @@ class EditProfile extends BaseEditProfile
}), }),
]), ]),
Tab::make(trans('profile.tabs.oauth')) Tab::make('oauth')
->label(trans('profile.tabs.oauth'))
->icon('tabler-brand-oauth') ->icon('tabler-brand-oauth')
->visible(count($oauthSchemas) > 0) ->visible(count($oauthSchemas) > 0)
->schema(function () use ($oauthSchemas) { ->schema(function () use ($oauthSchemas) {
@ -199,7 +201,8 @@ class EditProfile extends BaseEditProfile
return [Actions::make($actions)]; return [Actions::make($actions)];
}), }),
Tab::make(trans('profile.tabs.2fa')) Tab::make('2fa')
->label(trans('profile.tabs.2fa'))
->icon('tabler-shield-lock') ->icon('tabler-shield-lock')
->schema(function (TwoFactorSetupService $setupService) { ->schema(function (TwoFactorSetupService $setupService) {
if ($this->getUser()->use_totp) { if ($this->getUser()->use_totp) {
@ -263,7 +266,7 @@ class EditProfile extends BaseEditProfile
->content(fn () => new HtmlString(" ->content(fn () => new HtmlString("
<div style='width: 300px; background-color: rgb(24, 24, 27);'>$image</div> <div style='width: 300px; background-color: rgb(24, 24, 27);'>$image</div>
")) "))
->helperText(trans('profile.setup_key') .': '. $secret), ->helperText(trans('profile.setup_key', ['secret' => $secret])),
TextInput::make('2facode') TextInput::make('2facode')
->label(trans('profile.code')) ->label(trans('profile.code'))
->requiredWith('2fapassword') ->requiredWith('2fapassword')
@ -276,7 +279,8 @@ class EditProfile extends BaseEditProfile
]; ];
}), }),
Tab::make(trans('profile.tabs.api_keys')) Tab::make('api_keys')
->label(trans('profile.tabs.api_keys'))
->icon('tabler-key') ->icon('tabler-key')
->schema([ ->schema([
Grid::make('name')->columns(5)->schema([ Grid::make('name')->columns(5)->schema([
@ -358,7 +362,8 @@ class EditProfile extends BaseEditProfile
]), ]),
]), ]),
Tab::make(trans('profile.tabs.ssh_keys')) Tab::make('ssh_keys')
->label(trans('profile.tabs.ssh_keys'))
->icon('tabler-lock-code') ->icon('tabler-lock-code')
->schema([ ->schema([
Grid::make('name')->columns(5)->schema([ Grid::make('name')->columns(5)->schema([
@ -443,7 +448,8 @@ class EditProfile extends BaseEditProfile
]), ]),
]), ]),
Tab::make(trans('profile.tabs.activity')) Tab::make('activity')
->label(trans('profile.tabs.activity'))
->icon('tabler-history') ->icon('tabler-history')
->schema([ ->schema([
Repeater::make('activity') Repeater::make('activity')
@ -461,7 +467,8 @@ class EditProfile extends BaseEditProfile
]), ]),
]), ]),
Tab::make(trans('profile.tabs.customization')) Tab::make('customization')
->label(trans('profile.tabs.customization'))
->icon('tabler-adjustments') ->icon('tabler-adjustments')
->schema([ ->schema([
Section::make(trans('profile.dashboard')) Section::make(trans('profile.dashboard'))

View File

@ -163,7 +163,7 @@ class Login extends BaseLogin
protected function getLoginFormComponent(): Component protected function getLoginFormComponent(): Component
{ {
return TextInput::make('login') return TextInput::make('login')
->label('Login') ->label(trans('filament-panels::pages/auth/login.title'))
->required() ->required()
->autocomplete() ->autocomplete()
->autofocus() ->autofocus()

View File

@ -124,21 +124,21 @@ class Settings extends ServerFormPage
->prefixIcon('tabler-file-zip') ->prefixIcon('tabler-file-zip')
->columnSpan(1) ->columnSpan(1)
->disabled() ->disabled()
->formatStateUsing(fn ($state, Server $server) => !$state ? 'No Backups' : $server->backups->count() . ' ' .trans('server/setting.server_info.limits.of') . ' ' . $state), ->formatStateUsing(fn ($state, Server $server) => !$state ? trans('server/backup.empty') : $server->backups->count() . ' ' .trans('server/setting.server_info.limits.of', ['max' => $state])),
TextInput::make('database_limit') TextInput::make('database_limit')
->label('') ->label('')
->prefix(trans('server/setting.server_info.limits.databases')) ->prefix(trans('server/setting.server_info.limits.databases'))
->prefixIcon('tabler-database') ->prefixIcon('tabler-database')
->columnSpan(1) ->columnSpan(1)
->disabled() ->disabled()
->formatStateUsing(fn ($state, Server $server) => !$state ? 'No Databases' : $server->databases->count() . ' ' . trans('server/setting.server_info.limits.of') . ' ' .$state), ->formatStateUsing(fn ($state, Server $server) => !$state ? trans('server/database.empty') : $server->databases->count() . ' ' . trans('server/setting.server_info.limits.of', ['max' => $state])),
TextInput::make('allocation_limit') TextInput::make('allocation_limit')
->label('') ->label('')
->prefix(trans('server/setting.server_info.limits.allocations')) ->prefix(trans('server/setting.server_info.limits.allocations'))
->prefixIcon('tabler-network') ->prefixIcon('tabler-network')
->columnSpan(1) ->columnSpan(1)
->disabled() ->disabled()
->formatStateUsing(fn ($state, Server $server) => !$state ? trans('server/setting.server_info.limits.no_allocations') : $server->allocations->count() . ' ' .trans('server/setting.server_info.limits.of') . ' ' . $state), ->formatStateUsing(fn ($state, Server $server) => !$state ? trans('server/setting.server_info.limits.no_allocations') : $server->allocations->count() . ' ' .trans('server/setting.server_info.limits.of', ['max' => $state])),
]), ]),
]), ]),
Section::make(trans('server/setting.node_info.title')) Section::make(trans('server/setting.node_info.title'))
@ -257,13 +257,13 @@ class Settings extends ServerFormPage
} }
Notification::make() Notification::make()
->title(trans('server/setting.notification_name')) ->title(trans('server/setting.server_info.notification_name'))
->body(fn () => $original . ' -> ' . $name) ->body(fn () => $original . ' -> ' . $name)
->success() ->success()
->send(); ->send();
} catch (Exception $exception) { } catch (Exception $exception) {
Notification::make() Notification::make()
->title(trans('server/setting.failed')) ->title(trans('server/setting.server_info.failed'))
->body($exception->getMessage()) ->body($exception->getMessage())
->danger() ->danger()
->send(); ->send();
@ -288,13 +288,13 @@ class Settings extends ServerFormPage
} }
Notification::make() Notification::make()
->title(trans('server/setting.notification_description')) ->title(trans('server/setting.server_info.notification_description'))
->body(fn () => $original . ' -> ' . $description) ->body(fn () => $original . ' -> ' . $description)
->success() ->success()
->send(); ->send();
} catch (Exception $exception) { } catch (Exception $exception) {
Notification::make() Notification::make()
->title(trans('server/setting.failed')) ->title(trans('server/setting.server_info.failed'))
->body($exception->getMessage()) ->body($exception->getMessage())
->danger() ->danger()
->send(); ->send();

View File

@ -121,10 +121,10 @@ class BackupResource extends Resource
Action::make('rename') Action::make('rename')
->icon('tabler-pencil') ->icon('tabler-pencil')
->authorize(fn () => auth()->user()->can(Permission::ACTION_BACKUP_DELETE, $server)) ->authorize(fn () => auth()->user()->can(Permission::ACTION_BACKUP_DELETE, $server))
->label('Rename') ->label(trans('server/backup.actions.rename.title'))
->form([ ->form([
TextInput::make('name') TextInput::make('name')
->label('Backup Name') ->label(trans('server/backup.actions.rename.new_name'))
->required() ->required()
->maxLength(255) ->maxLength(255)
->default(fn (Backup $backup) => $backup->name), ->default(fn (Backup $backup) => $backup->name),
@ -143,8 +143,7 @@ class BackupResource extends Resource
} }
Notification::make() Notification::make()
->title('Backup Renamed') ->title(trans('server/backup.actions.rename.notification_success'))
->body('The backup has been successfully renamed.')
->success() ->success()
->send(); ->send();
}) })

View File

@ -120,7 +120,7 @@ class DatabaseResource extends Resource
]) ])
->actions([ ->actions([
ViewAction::make() ViewAction::make()
->modalHeading(fn (Database $database) => 'Viewing ' . $database->database), ->modalHeading(fn (Database $database) => trans('server/database.viewing', ['database' => $database->database])),
DeleteAction::make() DeleteAction::make()
->using(fn (Database $database, DatabaseManagementService $service) => $service->delete($database)), ->using(fn (Database $database, DatabaseManagementService $service) => $service->delete($database)),
]); ]);

View File

@ -134,8 +134,8 @@ class EditFiles extends Page
return $this->getDaemonFileRepository()->getContent($this->path, config('panel.files.max_edit_size')); return $this->getDaemonFileRepository()->getContent($this->path, config('panel.files.max_edit_size'));
} catch (FileSizeTooLargeException) { } catch (FileSizeTooLargeException) {
AlertBanner::make('file_too_large') AlertBanner::make('file_too_large')
->title('<code>' . basename($this->path) . '</code> is too large!') ->title(trans('server/file.alerts.file_too_large.title', ['name' => basename($this->path)]))
->body('Max is ' . convert_bytes_to_readable(config('panel.files.max_edit_size'))) ->body(trans('server/file.alerts.file_too_large.body', ['max' => convert_bytes_to_readable(config('panel.files.max_edit_size'))]))
->danger() ->danger()
->closable() ->closable()
->send(); ->send();
@ -143,7 +143,7 @@ class EditFiles extends Page
$this->redirect(ListFiles::getUrl(['path' => dirname($this->path)])); $this->redirect(ListFiles::getUrl(['path' => dirname($this->path)]));
} catch (FileNotFoundException) { } catch (FileNotFoundException) {
AlertBanner::make('file_not_found') AlertBanner::make('file_not_found')
->title('<code>' . basename($this->path) . '</code> not found!') ->title(trans('server/file.alerts.file_not_found.title', ['name' => basename($this->path)]))
->danger() ->danger()
->closable() ->closable()
->send(); ->send();
@ -151,7 +151,7 @@ class EditFiles extends Page
$this->redirect(ListFiles::getUrl(['path' => dirname($this->path)])); $this->redirect(ListFiles::getUrl(['path' => dirname($this->path)]));
} catch (FileNotEditableException) { } catch (FileNotEditableException) {
AlertBanner::make('file_is_directory') AlertBanner::make('file_is_directory')
->title('<code>' . basename($this->path) . '</code> is a directory') ->title(trans('server/file.alerts.file_not_found.title', ['name' => basename($this->path)]))
->danger() ->danger()
->closable() ->closable()
->send(); ->send();
@ -179,8 +179,8 @@ class EditFiles extends Page
if (str($path)->endsWith('.pelicanignore')) { if (str($path)->endsWith('.pelicanignore')) {
AlertBanner::make('.pelicanignore_info') AlertBanner::make('.pelicanignore_info')
->title('You\'re editing a <code>.pelicanignore</code> file!') ->title(trans('server/file.alerts.pelicanignore.title'))
->body('Any files or directories listed in here will be excluded from backups. Wildcards are supported by using an asterisk (<code>*</code>).<br>You can negate a prior rule by prepending an exclamation point (<code>!</code>).') ->body(trans('server/file.alerts.pelicanignore.body'))
->info() ->info()
->closable() ->closable()
->send(); ->send();

View File

@ -135,7 +135,7 @@ class ListFiles extends ListRecords
->icon('tabler-forms') ->icon('tabler-forms')
->form([ ->form([
TextInput::make('name') TextInput::make('name')
->label(trans('server/file.actions.rename.name')) ->label(trans('server/file.actions.rename.file_name'))
->default(fn (File $file) => $file->name) ->default(fn (File $file) => $file->name)
->required(), ->required(),
]) ])
@ -440,7 +440,7 @@ class ListFiles extends ListRecords
->log(); ->log();
} catch (FileExistsException) { } catch (FileExistsException) {
AlertBanner::make('file_already_exists') AlertBanner::make('file_already_exists')
->title('<code>' . $path . '</code> already exists!') ->title(trans('server/file.alerts.file_already_exists.title', ['name' => $path]))
->danger() ->danger()
->closable() ->closable()
->send(); ->send();
@ -481,7 +481,7 @@ class ListFiles extends ListRecords
} catch (FileExistsException) { } catch (FileExistsException) {
$path = join_paths($this->path, $data['name']); $path = join_paths($this->path, $data['name']);
AlertBanner::make('folder_already_exists') AlertBanner::make('folder_already_exists')
->title('<code>' . $path . '</code> already exists!') ->title(trans('server/file.alerts.file_already_exists.title', ['name' => $path]))
->danger() ->danger()
->closable() ->closable()
->send(); ->send();
@ -525,7 +525,8 @@ class ListFiles extends ListRecords
Tabs::make() Tabs::make()
->contained(false) ->contained(false)
->schema([ ->schema([
Tab::make(trans('server/file.actions.upload.from_files')) Tab::make('from_files')
->label(trans('server/file.actions.upload.from_files'))
->live() ->live()
->schema([ ->schema([
FileUpload::make('files') FileUpload::make('files')
@ -535,7 +536,8 @@ class ListFiles extends ListRecords
->maxSize((int) round($server->node->upload_size * (config('panel.use_binary_prefix') ? 1.048576 * 1024 : 1000))) ->maxSize((int) round($server->node->upload_size * (config('panel.use_binary_prefix') ? 1.048576 * 1024 : 1000)))
->multiple(), ->multiple(),
]), ]),
Tab::make(trans('server/file.actions.upload.url')) Tab::make('url')
->label(trans('server/file.actions.upload.url'))
->live() ->live()
->disabled(fn (Get $get) => count($get('files')) > 0) ->disabled(fn (Get $get) => count($get('files')) > 0)
->schema([ ->schema([

View File

@ -36,7 +36,7 @@ class SearchFiles extends ListRecords
return [ return [
$resource::getUrl() => $resource::getBreadcrumb(), $resource::getUrl() => $resource::getBreadcrumb(),
self::getUrl(['searchTerm' => $this->searchTerm]) => trans('server/file.actions.global_search.search') . ' "' . $this->searchTerm . '"', self::getUrl(['searchTerm' => $this->searchTerm]) => trans('server/file.actions.global_search.search_for_term', ['term' => ' "' . $this->searchTerm . '"']),
]; ];
} }

View File

@ -95,7 +95,8 @@ class UserResource extends Resource
$permissionsArray[$data['name']][] = $permission; $permissionsArray[$data['name']][] = $permission;
} }
$tabs[] = Tab::make(str($data['name'])->headline()) $tabs[] = Tab::make($data['name'])
->label(str($data['name'])->headline())
->schema([ ->schema([
Section::make() Section::make()
->description(trans('server/user.permissions.' . $data['name'] . '_desc')) ->description(trans('server/user.permissions.' . $data['name'] . '_desc'))

View File

@ -53,7 +53,8 @@ class ListUsers extends ListRecords
$permissionsArray[$data['name']][] = $permission; $permissionsArray[$data['name']][] = $permission;
} }
$tabs[] = Tab::make(str($data['name'])->headline()) $tabs[] = Tab::make($data['name'])
->label(str($data['name'])->headline())
->schema([ ->schema([
Section::make() Section::make()
->description(trans('server/user.permissions.' . $data['name'] . '_desc')) ->description(trans('server/user.permissions.' . $data['name'] . '_desc'))

View File

@ -133,8 +133,8 @@ class ServerConsole extends Widget
public function websocketError(): void public function websocketError(): void
{ {
AlertBanner::make('websocket_error') AlertBanner::make('websocket_error')
->title('Could not connect to websocket!') ->title(trans('server/console.websocket_error.title'))
->body('Check your browser console for more details.') ->body(trans('server/console.websocket_error.body'))
->danger() ->danger()
->send(); ->send();
} }

View File

@ -97,7 +97,7 @@ class ServerOverview extends StatsOverviewWidget
$this->js("window.navigator.clipboard.writeText('{$value}');"); $this->js("window.navigator.clipboard.writeText('{$value}');");
Notification::make() Notification::make()
->title('Copied to clipboard') ->title(trans('server/dashboard.copied'))
->body($value) ->body($value)
->success() ->success()
->send(); ->send();

View File

@ -16,12 +16,12 @@ class ServerInstalledListener
Notification::make() Notification::make()
->status($event->successful ? 'success' : 'danger') ->status($event->successful ? 'success' : 'danger')
->title('Server ' . ($event->initialInstall ? 'Installation' : 'Reinstallation') . ' ' . ($event->successful ? 'completed' : 'failed')) ->title(trans('notifications.' . ($event->initialInstall ? 'installation' : 'reinstallation') . '_' . ($event->successful ? 'completed' : 'failed')))
->body('Server Name: ' . $event->server->name) ->body(trans('server/setting.server_info.server_name', ['name' => $event->server->name]))
->actions([ ->actions([
Action::make('view') Action::make('view')
->button() ->button()
->label('Open Server') ->label(trans('notifications.open_server'))
->markAsRead() ->markAsRead()
->url(fn () => Console::getUrl(panel: 'server', tenant: $event->server)), ->url(fn () => Console::getUrl(panel: 'server', tenant: $event->server)),
]) ])

View File

@ -16,12 +16,12 @@ class SubUserAddedListener
$event->subuser->loadMissing('user'); $event->subuser->loadMissing('user');
Notification::make() Notification::make()
->title('Added to Server') ->title(trans('notifications.user_added.title'))
->body('You have been added as a subuser to ' . $event->subuser->server->name . '.') ->body(trans('notifications.user_added.body', ['server' => $event->subuser->server->name]))
->actions([ ->actions([
Action::make('view') Action::make('view')
->button() ->button()
->label('Open Server') ->label(trans('notifications.open_server'))
->markAsRead() ->markAsRead()
->url(fn () => Console::getUrl(panel: 'server', tenant: $event->subuser->server)), ->url(fn () => Console::getUrl(panel: 'server', tenant: $event->subuser->server)),
]) ])

View File

@ -11,8 +11,8 @@ class SubUserRemovedListener
public function handle(SubUserRemoved $event): void public function handle(SubUserRemoved $event): void
{ {
Notification::make() Notification::make()
->title('Removed from Server') ->title(trans('notifications.user_removed.title'))
->body('You have been removed as a subuser from ' . $event->server->name . '.') ->body(trans('notifications.user_removed.body', ['server' => $event->server->name]))
->sendToDatabase($event->user); ->sendToDatabase($event->user);
$event->user->notify(new RemovedFromServer($event->server)); $event->user->notify(new RemovedFromServer($event->server));

View File

@ -9,12 +9,16 @@ use App\Livewire\Installer\Steps\QueueStep;
use App\Livewire\Installer\Steps\RequirementsStep; use App\Livewire\Installer\Steps\RequirementsStep;
use App\Livewire\Installer\Steps\SessionStep; use App\Livewire\Installer\Steps\SessionStep;
use App\Models\User; use App\Models\User;
use App\Services\Helpers\LanguageService;
use App\Services\Users\UserCreationService; use App\Services\Users\UserCreationService;
use App\Traits\CheckMigrationsTrait; use App\Traits\CheckMigrationsTrait;
use App\Traits\EnvironmentWriterTrait; use App\Traits\EnvironmentWriterTrait;
use Exception; use Exception;
use Filament\Facades\Filament; use Filament\Facades\Filament;
use Filament\Forms\Components\Actions\Action; use Filament\Forms\Components\Actions\Action;
use Filament\Forms\Components\Component;
use Filament\Forms\Components\Grid;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Wizard; use Filament\Forms\Components\Wizard;
use Filament\Forms\Concerns\InteractsWithForms; use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms; use Filament\Forms\Contracts\HasForms;
@ -23,6 +27,7 @@ use Filament\Notifications\Notification;
use Filament\Pages\SimplePage; use Filament\Pages\SimplePage;
use Filament\Support\Enums\MaxWidth; use Filament\Support\Enums\MaxWidth;
use Filament\Support\Exceptions\Halt; use Filament\Support\Exceptions\Halt;
use Illuminate\Foundation\Application;
use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Blade; use Illuminate\Support\Facades\Blade;
use Illuminate\Support\HtmlString; use Illuminate\Support\HtmlString;
@ -61,6 +66,10 @@ class PanelInstaller extends SimplePage implements HasForms
protected function getFormSchema(): array protected function getFormSchema(): array
{ {
return [ return [
Grid::make()
->schema([
$this->getLanguageComponent(),
]),
Wizard::make([ Wizard::make([
RequirementsStep::make(), RequirementsStep::make(),
EnvironmentStep::make($this), EnvironmentStep::make($this),
@ -77,13 +86,29 @@ class PanelInstaller extends SimplePage implements HasForms
size="sm" size="sm"
wire:loading.attr="disabled" wire:loading.attr="disabled"
> >
Finish trans('installer.finish')
<span wire:loading><x-filament::loading-indicator class="h-4 w-4" /></span> <span wire:loading><x-filament::loading-indicator class="h-4 w-4" /></span>
</x-filament::button> </x-filament::button>
BLADE))), BLADE))),
]; ];
} }
protected function getLanguageComponent(): Component
{
return Select::make('language')
->hiddenLabel()
->prefix(trans('profile.language'))
->prefixIcon('tabler-flag')
->required()
->live()
->default('en')
->selectablePlaceholder(false)
->options(fn (LanguageService $languageService) => $languageService->getAvailableLanguages())
->afterStateUpdated(fn ($state, Application $app) => $app->setLocale($state ?? config('app.locale')))
->native(false)
->columnStart(4);
}
protected function getFormStatePath(): ?string protected function getFormStatePath(): ?string
{ {
return 'data'; return 'data';
@ -121,13 +146,13 @@ class PanelInstaller extends SimplePage implements HasForms
report($exception); report($exception);
Notification::make() Notification::make()
->title('Could not write to .env file') ->title(trans('installer.exceptions.write_env'))
->body($exception->getMessage()) ->body($exception->getMessage())
->danger() ->danger()
->persistent() ->persistent()
->send(); ->send();
throw new Halt('Error while writing .env file'); throw new Halt(trans('installer.exceptions.write_env'));
} }
Artisan::call('config:clear'); Artisan::call('config:clear');
@ -144,23 +169,23 @@ class PanelInstaller extends SimplePage implements HasForms
report($exception); report($exception);
Notification::make() Notification::make()
->title('Migrations failed') ->title(trans('installer.database.exceptions.migration'))
->body($exception->getMessage()) ->body($exception->getMessage())
->danger() ->danger()
->persistent() ->persistent()
->send(); ->send();
throw new Halt('Error while running migrations'); throw new Halt(trans('installer.exceptions.migration'));
} }
if (!$this->hasCompletedMigrations()) { if (!$this->hasCompletedMigrations()) {
Notification::make() Notification::make()
->title('Migrations failed') ->title(trans('installer.database.exceptions.migration'))
->danger() ->danger()
->persistent() ->persistent()
->send(); ->send();
throw new Halt('Migrations failed'); throw new Halt(trans('installer.database.exceptions.migration'));
} }
} }
@ -175,13 +200,13 @@ class PanelInstaller extends SimplePage implements HasForms
report($exception); report($exception);
Notification::make() Notification::make()
->title('Could not create admin user') ->title(trans('installer.exceptions.create_user'))
->body($exception->getMessage()) ->body($exception->getMessage())
->danger() ->danger()
->persistent() ->persistent()
->send(); ->send();
throw new Halt('Error while creating admin user'); throw new Halt(trans('installer.exceptions.create_user'));
} }
} }
} }

View File

@ -24,13 +24,13 @@ class CacheStep
public static function make(PanelInstaller $installer): Step public static function make(PanelInstaller $installer): Step
{ {
return Step::make('cache') return Step::make('cache')
->label('Cache') ->label(trans('installer.cache.title'))
->columns() ->columns()
->schema([ ->schema([
ToggleButtons::make('env_cache.CACHE_STORE') ToggleButtons::make('env_cache.CACHE_STORE')
->label('Cache Driver') ->label(trans('installer.cache.driver'))
->hintIcon('tabler-question-mark') ->hintIcon('tabler-question-mark')
->hintIconTooltip('The driver used for caching. We recommend "Filesystem".') ->hintIconTooltip(trans('installer.cache.driver_help'))
->required() ->required()
->inline() ->inline()
->options(self::CACHE_DRIVERS) ->options(self::CACHE_DRIVERS)
@ -50,31 +50,31 @@ class CacheStep
} }
}), }),
TextInput::make('env_cache.REDIS_HOST') TextInput::make('env_cache.REDIS_HOST')
->label('Redis Host') ->label(trans('installer.cache.fields.host'))
->placeholder('127.0.0.1') ->placeholder('127.0.0.1')
->hintIcon('tabler-question-mark') ->hintIcon('tabler-question-mark')
->hintIconTooltip('The host of your redis server. Make sure it is reachable.') ->hintIconTooltip(trans('installer.cache.fields.host_help'))
->required(fn (Get $get) => $get('env_cache.CACHE_STORE') === 'redis') ->required(fn (Get $get) => $get('env_cache.CACHE_STORE') === 'redis')
->default(fn (Get $get) => $get('env_cache.CACHE_STORE') === 'redis' ? config('database.redis.default.host') : null) ->default(fn (Get $get) => $get('env_cache.CACHE_STORE') === 'redis' ? config('database.redis.default.host') : null)
->visible(fn (Get $get) => $get('env_cache.CACHE_STORE') === 'redis'), ->visible(fn (Get $get) => $get('env_cache.CACHE_STORE') === 'redis'),
TextInput::make('env_cache.REDIS_PORT') TextInput::make('env_cache.REDIS_PORT')
->label('Redis Port') ->label(trans('installer.cache.fields.port'))
->placeholder('6379') ->placeholder('6379')
->hintIcon('tabler-question-mark') ->hintIcon('tabler-question-mark')
->hintIconTooltip('The port of your redis server.') ->hintIconTooltip(trans('installer.cache.fields.port_help'))
->required(fn (Get $get) => $get('env_cache.CACHE_STORE') === 'redis') ->required(fn (Get $get) => $get('env_cache.CACHE_STORE') === 'redis')
->default(fn (Get $get) => $get('env_cache.CACHE_STORE') === 'redis' ? config('database.redis.default.port') : null) ->default(fn (Get $get) => $get('env_cache.CACHE_STORE') === 'redis' ? config('database.redis.default.port') : null)
->visible(fn (Get $get) => $get('env_cache.CACHE_STORE') === 'redis'), ->visible(fn (Get $get) => $get('env_cache.CACHE_STORE') === 'redis'),
TextInput::make('env_cache.REDIS_USERNAME') TextInput::make('env_cache.REDIS_USERNAME')
->label('Redis Username') ->label(trans('installer.cache.fields.username'))
->hintIcon('tabler-question-mark') ->hintIcon('tabler-question-mark')
->hintIconTooltip('The name of your redis user. Can be empty') ->hintIconTooltip(trans('installer.cache.fields.username_help'))
->default(fn (Get $get) => $get('env_cache.CACHE_STORE') === 'redis' ? config('database.redis.default.username') : null) ->default(fn (Get $get) => $get('env_cache.CACHE_STORE') === 'redis' ? config('database.redis.default.username') : null)
->visible(fn (Get $get) => $get('env_cache.CACHE_STORE') === 'redis'), ->visible(fn (Get $get) => $get('env_cache.CACHE_STORE') === 'redis'),
TextInput::make('env_cache.REDIS_PASSWORD') TextInput::make('env_cache.REDIS_PASSWORD')
->label('Redis Password') ->label(trans('installer.cache.fields.password'))
->hintIcon('tabler-question-mark') ->hintIcon('tabler-question-mark')
->hintIconTooltip('The password for your redis user. Can be empty.') ->hintIconTooltip(trans('installer.cache.fields.password_help'))
->password() ->password()
->revealable() ->revealable()
->default(fn (Get $get) => $get('env_cache.CACHE_STORE') === 'redis' ? config('database.redis.default.password') : null) ->default(fn (Get $get) => $get('env_cache.CACHE_STORE') === 'redis' ? config('database.redis.default.password') : null)
@ -110,7 +110,7 @@ class CacheStep
$redis->connection()->command('ping'); $redis->connection()->command('ping');
} catch (Exception $exception) { } catch (Exception $exception) {
Notification::make() Notification::make()
->title('Redis connection failed') ->title(trans('installer.cache.exception'))
->body($exception->getMessage()) ->body($exception->getMessage())
->danger() ->danger()
->send(); ->send();

View File

@ -25,13 +25,13 @@ class DatabaseStep
public static function make(PanelInstaller $installer): Step public static function make(PanelInstaller $installer): Step
{ {
return Step::make('database') return Step::make('database')
->label('Database') ->label(trans('installer.database.title'))
->columns() ->columns()
->schema([ ->schema([
ToggleButtons::make('env_database.DB_CONNECTION') ToggleButtons::make('env_database.DB_CONNECTION')
->label('Database Driver') ->label(trans('installer.database.driver'))
->hintIcon('tabler-question-mark') ->hintIcon('tabler-question-mark')
->hintIconTooltip('The driver used for the panel database. We recommend "SQLite".') ->hintIconTooltip(trans('installer.database.driver_help'))
->required() ->required()
->inline() ->inline()
->options(self::DATABASE_DRIVERS) ->options(self::DATABASE_DRIVERS)
@ -61,40 +61,40 @@ class DatabaseStep
} }
}), }),
TextInput::make('env_database.DB_DATABASE') TextInput::make('env_database.DB_DATABASE')
->label(fn (Get $get) => $get('env_database.DB_CONNECTION') === 'sqlite' ? 'Database Path' : 'Database Name') ->label(fn (Get $get) => $get('env_database.DB_CONNECTION') === 'sqlite' ? trans('installer.database.fields.path') : trans('installer.database.fields.name'))
->placeholder(fn (Get $get) => $get('env_database.DB_CONNECTION') === 'sqlite' ? 'database.sqlite' : 'panel') ->placeholder(fn (Get $get) => $get('env_database.DB_CONNECTION') === 'sqlite' ? 'database.sqlite' : 'panel')
->hintIcon('tabler-question-mark') ->hintIcon('tabler-question-mark')
->hintIconTooltip(fn (Get $get) => $get('env_database.DB_CONNECTION') === 'sqlite' ? 'The path of your .sqlite file relative to the database folder.' : 'The name of the panel database.') ->hintIconTooltip(fn (Get $get) => $get('env_database.DB_CONNECTION') === 'sqlite' ? trans('installer.database.fields.path_help') : trans('installer.database.fields.name_help'))
->required() ->required()
->default('database.sqlite'), ->default('database.sqlite'),
TextInput::make('env_database.DB_HOST') TextInput::make('env_database.DB_HOST')
->label('Database Host') ->label(trans('installer.database.fields.host'))
->placeholder('127.0.0.1') ->placeholder('127.0.0.1')
->hintIcon('tabler-question-mark') ->hintIcon('tabler-question-mark')
->hintIconTooltip('The host of your database. Make sure it is reachable.') ->hintIconTooltip(trans('installer.database.fields.host_help'))
->required(fn (Get $get) => $get('env_database.DB_CONNECTION') !== 'sqlite') ->required(fn (Get $get) => $get('env_database.DB_CONNECTION') !== 'sqlite')
->hidden(fn (Get $get) => $get('env_database.DB_CONNECTION') === 'sqlite'), ->hidden(fn (Get $get) => $get('env_database.DB_CONNECTION') === 'sqlite'),
TextInput::make('env_database.DB_PORT') TextInput::make('env_database.DB_PORT')
->label('Database Port') ->label(trans('installer.database.fields.port'))
->placeholder('3306') ->placeholder('3306')
->hintIcon('tabler-question-mark') ->hintIcon('tabler-question-mark')
->hintIconTooltip('The port of your database.') ->hintIconTooltip(trans('installer.database.fields.port_help'))
->numeric() ->numeric()
->minValue(1) ->minValue(1)
->maxValue(65535) ->maxValue(65535)
->required(fn (Get $get) => $get('env_database.DB_CONNECTION') !== 'sqlite') ->required(fn (Get $get) => $get('env_database.DB_CONNECTION') !== 'sqlite')
->hidden(fn (Get $get) => $get('env_database.DB_CONNECTION') === 'sqlite'), ->hidden(fn (Get $get) => $get('env_database.DB_CONNECTION') === 'sqlite'),
TextInput::make('env_database.DB_USERNAME') TextInput::make('env_database.DB_USERNAME')
->label('Database Username') ->label(trans('installer.database.fields.username'))
->placeholder('pelican') ->placeholder('pelican')
->hintIcon('tabler-question-mark') ->hintIcon('tabler-question-mark')
->hintIconTooltip('The name of your database user.') ->hintIconTooltip(trans('installer.database.fields.username_help'))
->required(fn (Get $get) => $get('env_database.DB_CONNECTION') !== 'sqlite') ->required(fn (Get $get) => $get('env_database.DB_CONNECTION') !== 'sqlite')
->hidden(fn (Get $get) => $get('env_database.DB_CONNECTION') === 'sqlite'), ->hidden(fn (Get $get) => $get('env_database.DB_CONNECTION') === 'sqlite'),
TextInput::make('env_database.DB_PASSWORD') TextInput::make('env_database.DB_PASSWORD')
->label('Database Password') ->label(trans('installer.database.fields.password'))
->hintIcon('tabler-question-mark') ->hintIcon('tabler-question-mark')
->hintIconTooltip('The password of your database user. Can be empty.') ->hintIconTooltip(trans('installer.database.fields.password_help'))
->password() ->password()
->revealable() ->revealable()
->hidden(fn (Get $get) => $get('env_database.DB_CONNECTION') === 'sqlite'), ->hidden(fn (Get $get) => $get('env_database.DB_CONNECTION') === 'sqlite'),
@ -103,7 +103,7 @@ class DatabaseStep
$driver = $get('env_database.DB_CONNECTION'); $driver = $get('env_database.DB_CONNECTION');
if (!self::testConnection($driver, $get('env_database.DB_HOST'), $get('env_database.DB_PORT'), $get('env_database.DB_DATABASE'), $get('env_database.DB_USERNAME'), $get('env_database.DB_PASSWORD'))) { if (!self::testConnection($driver, $get('env_database.DB_HOST'), $get('env_database.DB_PORT'), $get('env_database.DB_DATABASE'), $get('env_database.DB_USERNAME'), $get('env_database.DB_PASSWORD'))) {
throw new Halt('Database connection failed'); throw new Halt(trans('installer.database.exceptions.connection'));
} }
$installer->writeToEnv('env_database'); $installer->writeToEnv('env_database');
@ -133,7 +133,7 @@ class DatabaseStep
DB::disconnect('_panel_install_test'); DB::disconnect('_panel_install_test');
Notification::make() Notification::make()
->title('Database connection failed') ->title(trans('installer.database.exceptions.connection'))
->body($exception->getMessage()) ->body($exception->getMessage())
->danger() ->danger()
->send(); ->send();

View File

@ -12,36 +12,36 @@ class EnvironmentStep
public static function make(PanelInstaller $installer): Step public static function make(PanelInstaller $installer): Step
{ {
return Step::make('environment') return Step::make('environment')
->label('Environment') ->label(trans('installer.environment.title'))
->columns() ->columns()
->schema([ ->schema([
TextInput::make('env_general.APP_NAME') TextInput::make('env_general.APP_NAME')
->label('App Name') ->label(trans('installer.environment.fields.app_name'))
->hintIcon('tabler-question-mark') ->hintIcon('tabler-question-mark')
->hintIconTooltip('This will be the Name of your Panel.') ->hintIconTooltip(trans('installer.environment.fields.app_name_help'))
->required() ->required()
->default(config('app.name')), ->default(config('app.name')),
TextInput::make('env_general.APP_URL') TextInput::make('env_general.APP_URL')
->label('App URL') ->label(trans('installer.environment.fields.app_url'))
->hintIcon('tabler-question-mark') ->hintIcon('tabler-question-mark')
->hintIconTooltip('This will be the URL you access your Panel from.') ->hintIconTooltip(trans('installer.environment.fields.app_url_help'))
->required() ->required()
->default(url('')), ->default(url('')),
Fieldset::make('adminuser') Fieldset::make('admin_user')
->label('Admin User') ->label(trans('installer.environment.fields.account.section'))
->columns(3) ->columns(3)
->schema([ ->schema([
TextInput::make('user.email') TextInput::make('user.email')
->label('E-Mail') ->label(trans('installer.environment.fields.account.email'))
->required() ->required()
->email() ->email()
->placeholder('admin@example.com'), ->placeholder('admin@example.com'),
TextInput::make('user.username') TextInput::make('user.username')
->label('Username') ->label(trans('installer.environment.fields.account.username'))
->required() ->required()
->placeholder('admin'), ->placeholder('admin'),
TextInput::make('user.password') TextInput::make('user.password')
->label('Password') ->label(trans('installer.environment.fields.account.password'))
->required() ->required()
->password() ->password()
->revealable(), ->revealable(),

View File

@ -22,35 +22,35 @@ class QueueStep
public static function make(PanelInstaller $installer): Step public static function make(PanelInstaller $installer): Step
{ {
return Step::make('queue') return Step::make('queue')
->label('Queue') ->label(trans('installer.queue.title'))
->columns() ->columns()
->schema([ ->schema([
ToggleButtons::make('env_queue.QUEUE_CONNECTION') ToggleButtons::make('env_queue.QUEUE_CONNECTION')
->label('Queue Driver') ->label(trans('installer.queue.driver'))
->hintIcon('tabler-question-mark') ->hintIcon('tabler-question-mark')
->hintIconTooltip('The driver used for handling queues. We recommend "Database".') ->hintIconTooltip(trans('installer.queue.driver_help'))
->required() ->required()
->inline() ->inline()
->options(self::QUEUE_DRIVERS) ->options(self::QUEUE_DRIVERS)
->disableOptionWhen(fn ($value, Get $get) => $value === 'redis' && $get('env_cache.CACHE_STORE') !== 'redis') ->disableOptionWhen(fn ($value, Get $get) => $value === 'redis' && $get('env_cache.CACHE_STORE') !== 'redis')
->default(config('queue.default')), ->default(config('queue.default')),
Toggle::make('done') Toggle::make('done')
->label('I have done both steps below.') ->label(trans('installer.queue.fields.done'))
->accepted(fn () => !@file_exists('/.dockerenv')) ->accepted(fn () => !@file_exists('/.dockerenv'))
->inline(false) ->inline(false)
->validationMessages([ ->validationMessages([
'accepted' => 'You need to do both steps before continuing!', 'accepted' => trans('installer.queue.fields.done_validation'),
]) ])
->hidden(fn () => @file_exists('/.dockerenv')), ->hidden(fn () => @file_exists('/.dockerenv')),
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(trans('installer.queue.fields.crontab')))
->disabled() ->disabled()
->hintAction(fn () => request()->isSecure() ? CopyAction::make() : null) ->hintAction(fn () => request()->isSecure() ? CopyAction::make() : null)
->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(trans('installer.queue.fields.service')))
->disabled() ->disabled()
->hintAction(fn () => request()->isSecure() ? CopyAction::make() : null) ->hintAction(fn () => request()->isSecure() ? CopyAction::make() : null)
->default('sudo php ' . base_path() . '/artisan p:environment:queue-service') ->default('sudo php ' . base_path() . '/artisan p:environment:queue-service')

View File

@ -18,13 +18,13 @@ class RequirementsStep
$correctPhpVersion = $compare >= 0; $correctPhpVersion = $compare >= 0;
$fields = [ $fields = [
Section::make('PHP Version') Section::make(trans('installer.requirements.sections.version.title'))
->description(self::MIN_PHP_VERSION . ' or newer') ->description(trans('installer.requirements.sections.version.or_newer', ['version' => self::MIN_PHP_VERSION]))
->icon($correctPhpVersion ? 'tabler-check' : 'tabler-x') ->icon($correctPhpVersion ? 'tabler-check' : 'tabler-x')
->iconColor($correctPhpVersion ? 'success' : 'danger') ->iconColor($correctPhpVersion ? 'success' : 'danger')
->schema([ ->schema([
Placeholder::make('') Placeholder::make('')
->content('Your PHP Version is ' . PHP_VERSION . '.'), ->content(trans('installer.requirements.sections.version.content', ['version' => PHP_VERSION])),
]), ]),
]; ];
@ -41,16 +41,16 @@ class RequirementsStep
]; ];
$allExtensionsInstalled = !in_array(false, $phpExtensions); $allExtensionsInstalled = !in_array(false, $phpExtensions);
$fields[] = Section::make('PHP Extensions') $fields[] = Section::make(trans('installer.requirements.sections.extensions.title'))
->description(implode(', ', array_keys($phpExtensions))) ->description(implode(', ', array_keys($phpExtensions)))
->icon($allExtensionsInstalled ? 'tabler-check' : 'tabler-x') ->icon($allExtensionsInstalled ? 'tabler-check' : 'tabler-x')
->iconColor($allExtensionsInstalled ? 'success' : 'danger') ->iconColor($allExtensionsInstalled ? 'success' : 'danger')
->schema([ ->schema([
Placeholder::make('') Placeholder::make('')
->content('All needed PHP Extensions are installed.') ->content(trans('installer.requirements.sections.extensions.good'))
->visible($allExtensionsInstalled), ->visible($allExtensionsInstalled),
Placeholder::make('') Placeholder::make('')
->content('The following PHP Extensions are missing: ' . implode(', ', array_keys($phpExtensions, false))) ->content(trans('installer.requirements.sections.extensions.bad', ['extensions' => implode(', ', array_keys($phpExtensions, false))]))
->visible(!$allExtensionsInstalled), ->visible(!$allExtensionsInstalled),
]); ]);
@ -60,30 +60,30 @@ class RequirementsStep
]; ];
$correctFolderPermissions = !in_array(false, $folderPermissions); $correctFolderPermissions = !in_array(false, $folderPermissions);
$fields[] = Section::make('Folder Permissions') $fields[] = Section::make(trans('installer.requirements.sections.permissions.title'))
->description(implode(', ', array_keys($folderPermissions))) ->description(implode(', ', array_keys($folderPermissions)))
->icon($correctFolderPermissions ? 'tabler-check' : 'tabler-x') ->icon($correctFolderPermissions ? 'tabler-check' : 'tabler-x')
->iconColor($correctFolderPermissions ? 'success' : 'danger') ->iconColor($correctFolderPermissions ? 'success' : 'danger')
->schema([ ->schema([
Placeholder::make('') Placeholder::make('')
->content('All Folders have the correct permissions.') ->content(trans('installer.requirements.sections.permissions.good'))
->visible($correctFolderPermissions), ->visible($correctFolderPermissions),
Placeholder::make('') Placeholder::make('')
->content('The following Folders have wrong permissions: ' . implode(', ', array_keys($folderPermissions, false))) ->content(trans('installer.requirements.sections.permissions.bad', ['folders' => implode(', ', array_keys($folderPermissions, false))]))
->visible(!$correctFolderPermissions), ->visible(!$correctFolderPermissions),
]); ]);
return Step::make('requirements') return Step::make('requirements')
->label('Server Requirements') ->label(trans('installer.requirements.title'))
->schema($fields) ->schema($fields)
->afterValidation(function () use ($correctPhpVersion, $allExtensionsInstalled, $correctFolderPermissions) { ->afterValidation(function () use ($correctPhpVersion, $allExtensionsInstalled, $correctFolderPermissions) {
if (!$correctPhpVersion || !$allExtensionsInstalled || !$correctFolderPermissions) { if (!$correctPhpVersion || !$allExtensionsInstalled || !$correctFolderPermissions) {
Notification::make() Notification::make()
->title('Some requirements are missing!') ->title(trans('installer.requirements.exception'))
->danger() ->danger()
->send(); ->send();
throw new Halt('Some requirements are missing'); throw new Halt(trans('installer.requirements.title'));
} }
}); });
} }

View File

@ -19,12 +19,12 @@ class SessionStep
public static function make(): Step public static function make(): Step
{ {
return Step::make('session') return Step::make('session')
->label('Session') ->label(trans('installer.session.title'))
->schema([ ->schema([
ToggleButtons::make('env_session.SESSION_DRIVER') ToggleButtons::make('env_session.SESSION_DRIVER')
->label('Session Driver') ->label(trans('installer.session.driver'))
->hintIcon('tabler-question-mark') ->hintIcon('tabler-question-mark')
->hintIconTooltip('The driver used for storing sessions. We recommend "Filesystem" or "Database".') ->hintIconTooltip(trans('installer.session.driver_help'))
->required() ->required()
->inline() ->inline()
->options(self::SESSION_DRIVERS) ->options(self::SESSION_DRIVERS)

View File

@ -195,7 +195,7 @@ class File extends Model
} }
AlertBanner::make('files_node_error') AlertBanner::make('files_node_error')
->title('Could not load files!') ->title(trans('server/file.alerts.files_node_error.title'))
->body($message->toString()) ->body($message->toString())
->danger() ->danger()
->send(); ->send();

View File

@ -26,7 +26,7 @@ class ServerPanelProvider extends PanelProvider
->label(fn () => trans('filament-panels::pages/auth/edit-profile.label')) ->label(fn () => trans('filament-panels::pages/auth/edit-profile.label'))
->url(fn () => EditProfile::getUrl(panel: 'app')), ->url(fn () => EditProfile::getUrl(panel: 'app')),
MenuItem::make() MenuItem::make()
->label('Server List') ->label(trans('server/dashboard.list'))
->icon('tabler-brand-docker') ->icon('tabler-brand-docker')
->url(fn () => ListServers::getUrl(panel: 'app')) ->url(fn () => ListServers::getUrl(panel: 'app'))
->sort(6), ->sort(6),

View File

@ -31,8 +31,8 @@ class DaemonServerRepository extends DaemonRepository
if ($requestBadGateway && $requestFromCloudflare && !$requestCachedFromCloudflare) { if ($requestBadGateway && $requestFromCloudflare && !$requestCachedFromCloudflare) {
Notification::make() Notification::make()
->title('Cloudflare Issue') ->title(trans('admin/node.cloudflare_issue.title'))
->body('Your Node is not accessible by Cloudflare') ->body(trans('admin/node.cloudflare_issue.body'))
->danger() ->danger()
->send(); ->send();
} }

View File

@ -46,7 +46,7 @@ class VariableUpdateService
{ {
if (!is_null(array_get($data, 'env_variable'))) { if (!is_null(array_get($data, 'env_variable'))) {
if (in_array(strtoupper(array_get($data, 'env_variable')), EggVariable::RESERVED_ENV_NAMES)) { if (in_array(strtoupper(array_get($data, 'env_variable')), EggVariable::RESERVED_ENV_NAMES)) {
throw new ReservedVariableNameException(trans('exceptions.service.variables.reserved_name', ['name' => array_get($data, 'env_variable')])); throw new ReservedVariableNameException(trans('exceptions.variables.reserved_name', ['name' => array_get($data, 'env_variable')]));
} }
$search = EggVariable::query() $search = EggVariable::query()
@ -56,7 +56,7 @@ class VariableUpdateService
->count(); ->count();
if ($search > 0) { if ($search > 0) {
throw new DisplayException(trans('exceptions.service.variables.env_not_unique', ['name' => array_get($data, 'env_variable')])); throw new DisplayException(trans('exceptions.variables.env_not_unique', ['name' => array_get($data, 'env_variable')]));
} }
} }

View File

@ -30,14 +30,14 @@ class SuspensionService
// suspended in the database. Additionally, nothing needs to happen if the server // suspended in the database. Additionally, nothing needs to happen if the server
// is not suspended, and we try to un-suspend the instance. // is not suspended, and we try to un-suspend the instance.
if ($isSuspending === $server->isSuspended()) { if ($isSuspending === $server->isSuspended()) {
Notification::make()->danger()->title('Failed!')->body('Server is already suspended!')->send(); Notification::make()->danger()->title(trans('notifications.failed'))->body(trans('admin/server.notifications.server_already_suspended'))->send();
return; return;
} }
// Check if the server is currently being transferred. // Check if the server is currently being transferred.
if (!is_null($server->transfer)) { if (!is_null($server->transfer)) {
Notification::make()->danger()->title('Failed!')->body('Server is currently being transferred.')->send(); Notification::make()->danger()->title(trans('notifications.failed'))->body(trans('admin/server.notifications.already_transfering'))->send();
throw new ConflictHttpException('Cannot toggle suspension status on a server that is currently being transferred.'); throw new ConflictHttpException('Cannot toggle suspension status on a server that is currently being transferred.');
} }

View File

@ -2,7 +2,7 @@
return [ return [
'title' => 'Application API Keys', 'title' => 'Application API Keys',
'empty_table' => 'No API keys', 'empty' => 'No API keys',
'whitelist' => 'Whitelisted IPv4 Addresses', 'whitelist' => 'Whitelisted IPv4 Addresses',
'whitelist_help' => 'API keys can be restricted to only work from specific IPv4 addresses. Enter each address on a new line.', 'whitelist_help' => 'API keys can be restricted to only work from specific IPv4 addresses. Enter each address on a new line.',
'whitelist_placeholder' => 'Example: 127.0.0.1 or 192.168.1.1', 'whitelist_placeholder' => 'Example: 127.0.0.1 or 192.168.1.1',

View File

@ -23,7 +23,7 @@ return [
], ],
'export' => [ 'export' => [
'modal' => 'How would you like to export :egg ?', 'modal' => 'How would you like to export :egg ?',
'as' => 'As', 'as' => 'As .:format',
], ],
'in_use' => 'In Use', 'in_use' => 'In Use',
'servers' => 'Servers', 'servers' => 'Servers',

View File

@ -55,6 +55,6 @@ return [
], ],
'checks' => [ 'checks' => [
'successful' => 'Successful', 'successful' => 'Successful',
'failed' => 'Failed', 'failed' => 'Failed :checks',
], ],
]; ];

View File

@ -29,7 +29,7 @@ return [
'architecture' => 'Architecture', 'architecture' => 'Architecture',
'kernel' => 'Kernel', 'kernel' => 'Kernel',
'unknown' => 'Unknown', 'unknown' => 'Unknown',
'latest' => 'Latest', 'latest' => '(Latest: :version)',
'node_uuid' => 'Node UUID', 'node_uuid' => 'Node UUID',
'node_id' => 'Node ID', 'node_id' => 'Node ID',
@ -88,6 +88,7 @@ return [
'auto_deploy' => 'Auto Deploy Command', 'auto_deploy' => 'Auto Deploy Command',
'auto_question' => 'Choose between Standalone and Docker install.', 'auto_question' => 'Choose between Standalone and Docker install.',
'auto_label' => 'Type',
'standalone' => 'Standalone', 'standalone' => 'Standalone',
'docker' => 'Docker', 'docker' => 'Docker',
'auto_command' => 'To auto-configure your node run the following command:', 'auto_command' => 'To auto-configure your node run the following command:',
@ -112,4 +113,9 @@ return [
'error_connecting' => 'Error connecting to :node', 'error_connecting' => 'Error connecting to :node',
'error_connecting_description' => 'The configuration could not be automatically updated on Wings, you will need to manually update the configuration file.', 'error_connecting_description' => 'The configuration could not be automatically updated on Wings, you will need to manually update the configuration file.',
'allocation' => 'Allocation', 'allocation' => 'Allocation',
'cloudflare_issue' => [
'title' => 'Cloudflare Issue',
'body' => 'Your Node is not accessible by Cloudflare',
],
]; ];

View File

@ -111,6 +111,7 @@ return [
'notifications' => [ 'notifications' => [
'server_suspension' => 'Server Suspension', 'server_suspension' => 'Server Suspension',
'server_suspended' => 'Server has been suspended', 'server_suspended' => 'Server has been suspended',
'server_already_suspended' => 'Server is already suspended!',
'server_suspend_help' => 'This will suspend the Server, stop any running processes, and immediately block the user from being able to access their files or otherwise manage the Server through the panel or API.', 'server_suspend_help' => 'This will suspend the Server, stop any running processes, and immediately block the user from being able to access their files or otherwise manage the Server through the panel or API.',
'server_unsuspend_help' => 'This will unsuspend the Server and restore normal user access.', 'server_unsuspend_help' => 'This will unsuspend the Server and restore normal user access.',
'server_unsuspended' => 'Server has been unsuspended', 'server_unsuspended' => 'Server has been unsuspended',
@ -132,6 +133,9 @@ return [
'reinstall_started' => 'Reinstall started', 'reinstall_started' => 'Reinstall started',
'reinstall_failed' => 'Could not start reinstall', 'reinstall_failed' => 'Could not start reinstall',
'log_failed' => 'Could not connect to Wings to retrieve server install log.', 'log_failed' => 'Could not connect to Wings to retrieve server install log.',
'transfer_started' => 'Transfer started',
'transfer_failed' => 'Transfer failed',
'already_transfering' => 'Server is currently being transferred.',
], ],
'notes' => 'Notes', 'notes' => 'Notes',
'no_notes' => 'No Notes', 'no_notes' => 'No Notes',

View File

@ -89,6 +89,7 @@ return [
], ],
'oauth' => [ 'oauth' => [
'enable' => 'Enable', 'enable' => 'Enable',
'enable_schema' => 'Enable :schema',
'disable' => 'Disable', 'disable' => 'Disable',
'client_id' => 'Client ID', 'client_id' => 'Client ID',
'client_secret' => 'Client Secret', 'client_secret' => 'Client Secret',

View File

@ -14,10 +14,7 @@ return [
'ask_password' => 'Password', 'ask_password' => 'Password',
'ask_password_tip' => 'If you would like to create an account with a random password emailed to the user, re-run this command (CTRL+C) and pass the `--no-password` flag.', 'ask_password_tip' => 'If you would like to create an account with a random password emailed to the user, re-run this command (CTRL+C) and pass the `--no-password` flag.',
'ask_password_help' => 'Passwords must be at least 8 characters in length and contain at least one capital letter and number.', 'ask_password_help' => 'Passwords must be at least 8 characters in length and contain at least one capital letter and number.',
'2fa_help_text' => [ '2fa_help_text' => 'This command will disable 2-factor authentication for a user\'s account if it is enabled. This should only be used as an account recovery command if the user is locked out of their account. If this is not what you wanted to do, press CTRL+C to exit this process.',
'This command will disable 2-factor authentication for a user\'s account if it is enabled. This should only be used as an account recovery command if the user is locked out of their account.',
'If this is not what you wanted to do, press CTRL+C to exit this process.',
],
'2fa_disabled' => '2-Factor authentication has been disabled for :email.', '2fa_disabled' => '2-Factor authentication has been disabled for :email.',
], ],
'schedule' => [ 'schedule' => [

View File

@ -54,13 +54,13 @@ return [
'schedule' => [ 'schedule' => [
'process' => [ 'process' => [
'no_tasks' => 'There are no scheduled tasks for servers that need to be run.', 'no_tasks' => 'There are no scheduled tasks for servers that need to be run.',
'error_message' => 'An error was encountered while processing Schedule: ', 'error_message' => 'An error was encountered while processing Schedule: :schedules',
], ],
], ],
'upgrade' => [ 'upgrade' => [
'integrity' => 'This command does not verify the integrity of downloaded assets. Please ensure that you trust the download source before continuing. If you do not wish to download an archive, please indicate that using the --skip-download flag, or answering "no" to the question below.', 'integrity' => 'This command does not verify the integrity of downloaded assets. Please ensure that you trust the download source before continuing. If you do not wish to download an archive, please indicate that using the --skip-download flag, or answering "no" to the question below.',
'source_url' => 'Download Source (set with --url=):', 'source_url' => 'Download Source (set with --url=):',
'php_version' => 'Cannot execute self-upgrade process. The minimum required PHP version required is 7.4.0, you have', 'php_version' => 'Cannot execute self-upgrade process. The minimum required PHP version required is 7.4.0, you have :current',
'skipDownload' => 'Would you like to download and unpack the archive files for the latest version?', 'skipDownload' => 'Would you like to download and unpack the archive files for the latest version?',
'webserver_user' => 'Your webserver user has been detected as <fg=blue>[{:user}]:</> is this correct?', 'webserver_user' => 'Your webserver user has been detected as <fg=blue>[{:user}]:</> is this correct?',
'name_webserver' => 'Please enter the name of the user running your webserver process. This varies from system to system, but is generally "www-data", "nginx", or "apache".', 'name_webserver' => 'Please enter the name of the user running your webserver process. This varies from system to system, but is generally "www-data", "nginx", or "apache".',

101
lang/en/installer.php Normal file
View File

@ -0,0 +1,101 @@
<?php
return [
'requirements' => [
'title' => 'Server Requirements',
'sections' => [
'version' => [
'title' => 'PHP Version',
'or_newer' => ':version or newer',
'content' => 'Your PHP Version is :version.',
],
'extensions' => [
'title' => 'PHP Extensions',
'good' => 'All needed PHP Extensions are installed.',
'bad' => 'The following PHP Extensions are missing: :extensions',
],
'permissions' => [
'title' => 'Folder Permissions',
'good' => 'All Folders have the correct permissions.',
'bad' => 'The following Folders have wrong permissions: :folders',
],
],
'exception' => 'Some requirements are missing',
],
'environment' => [
'title' => 'Environment',
'fields' => [
'app_name' => 'App Name',
'app_name_help' => 'This will be the Name of your Panel.',
'app_url' => 'App URL',
'app_url_help' => 'This will be the URL you access your Panel from.',
'account' => [
'section' => 'Admin User',
'email' => 'E-Mail',
'username' => 'Username',
'password' => 'Password',
],
],
],
'database' => [
'title' => 'Database',
'driver' => 'Database Driver',
'driver_help' => 'The driver used for the panel database. We recommend "SQLite".',
'fields' => [
'host' => 'Database Host',
'host_help' => 'The host of your database. Make sure it is reachable.',
'port' => 'Database Port',
'port_help' => 'The port of your database.',
'path' => 'Database Path',
'path_help' => 'The path of your .sqlite file relative to the database folder.',
'name' => 'Database Name',
'name_help' => 'The name of the panel database.',
'username' => 'Database Username',
'username_help' => 'The name of your database user.',
'password' => 'Database Password',
'password_help' => 'The password of your database user. Can be empty.',
],
'exceptions' => [
'connection' => 'Database connection failed',
'migration' => 'Migrations failed',
],
],
'session' => [
'title' => 'Session',
'driver' => 'Session Driver',
'driver_help' => 'The driver used for storing sessions. We recommend "Filesystem" or "Database".',
],
'cache' => [
'title' => 'Cache',
'driver' => 'Cache Driver',
'driver_help' => 'The driver used for caching. We recommend "Filesystem".',
'fields' => [
'host' => 'Redis Host',
'host_help' => 'The host of your redis server. Make sure it is reachable.',
'port' => 'Redis Port',
'port_help' => 'The port of your redis server.',
'username' => 'Redis Username',
'username_help' => 'The name of your redis user. Can be empty',
'password' => 'Redis Password',
'password_help' => 'The password for your redis user. Can be empty.',
],
'exception' => 'Redis connection failed',
],
'queue' => [
'title' => 'Queue',
'driver' => 'Queue Driver',
'driver_help' => 'The driver used for handling queues. We recommend "Database".',
'fields' => [
'done' => 'I have done both steps below.',
'done_validation' => 'You need to do both steps before continuing!',
'crontab' => '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!',
'service' => 'To setup the queue worker service you simply have to run the following command.',
],
],
'exceptions' => [
'write_env' => 'Could not write to .env file',
'migration' => 'Could not run migrations',
'create_user' => 'Could not create admin user',
],
'finish' => 'Finish',
];

18
lang/en/notifications.php Normal file
View File

@ -0,0 +1,18 @@
<?php
return [
'open_server' => 'Open Server',
'installation_completed' => 'Server Installation Completed',
'installation_failed' => 'Server Installation Failed',
'reinstallation_completed' => 'Server Reinstallation Completed',
'reinstallation_failed' => 'Server Reinstallation Failed',
'failed' => 'Failed',
'user_added' => [
'title' => 'Added to Server',
'body' => 'You have been added as a subuser to :server.',
],
'user_removed' => [
'title' => 'Removed from Server',
'body' => 'You have been removed as a subuser from :server.',
],
];

View File

@ -26,7 +26,7 @@ return [
'unlinked' => ':name unlinked', 'unlinked' => ':name unlinked',
'scan_qr' => 'Scan QR Code', 'scan_qr' => 'Scan QR Code',
'code' => 'Code', 'code' => 'Code',
'setup_key' => 'Setup Key', 'setup_key' => 'Setup Key: :secret',
'invalid_code' => 'Invalid 2FA Code', 'invalid_code' => 'Invalid 2FA Code',
'code_help' => 'Scan the QR code above using your two-step authentication app, then enter the code generated.', 'code_help' => 'Scan the QR code above using your two-step authentication app, then enter the code generated.',
'2fa_enabled' => 'Two Factor Authentication is currently enabled!', '2fa_enabled' => 'Two Factor Authentication is currently enabled!',

View File

@ -29,6 +29,11 @@ return [
'unlock' => 'Unlock', 'unlock' => 'Unlock',
], ],
'download' => 'Download', 'download' => 'Download',
'rename' => [
'title' => 'Rename',
'new_name' => 'Backup Name',
'notification_success' => 'Backup Renamed Successfully',
],
'restore' => [ 'restore' => [
'title' => 'Restore', 'title' => 'Restore',
'helper' => 'Your server will be stopped. You will not be able to control the power state, access the file manager, or create additional backups until this process is completed.', 'helper' => 'Your server will be stopped. You will not be able to control the power state, access the file manager, or create additional backups until this process is completed.',

View File

@ -36,4 +36,8 @@ return [
'offline' => 'Offline', 'offline' => 'Offline',
'missing' => 'Missing', 'missing' => 'Missing',
], ],
'websocket_error' => [
'title' => 'Could not connect to websocket!',
'body' => 'Check your browser console for more details.',
],
]; ];

View File

@ -3,9 +3,11 @@
return [ return [
'title' => 'Servers', 'title' => 'Servers',
'list' => 'Server List', 'list' => 'Server List',
'my_servers' => 'My Servers', 'tabs' => [
'other_servers' => 'Others\' Servers', 'my' => 'My Servers',
'all_servers' => 'All Servers', 'other' => 'Others\' Servers',
'all' => 'All Servers',
],
'empty_own' => 'You don\'t own any servers!', 'empty_own' => 'You don\'t own any servers!',
'empty_other' => 'You don\'t have access to any servers!', 'empty_other' => 'You don\'t have access to any servers!',
@ -22,4 +24,7 @@ return [
'loading' => 'Loading...', 'loading' => 'Loading...',
'power_actions' => 'Power Actions', 'power_actions' => 'Power Actions',
'power_action_sent' => ':action sent to :name',
'copied' => 'Copied to clipboard',
]; ];

View File

@ -2,6 +2,7 @@
return [ return [
'title' => 'Databases', 'title' => 'Databases',
'empty' => 'No Databases',
'create_database' => 'Create Database', 'create_database' => 'Create Database',
'limit' => 'Database limit reached', 'limit' => 'Database limit reached',
'viewing' => 'Viewing: :database', 'viewing' => 'Viewing: :database',

View File

@ -66,6 +66,7 @@ return [
'search_term' => 'Search term', 'search_term' => 'Search term',
'search_term_placeholder' => 'Enter a search term, ex. *.txt', 'search_term_placeholder' => 'Enter a search term, ex. *.txt',
'search' => 'Search', 'search' => 'Search',
'search_for_term' => 'Search :term',
], ],
'delete' => [ 'delete' => [
'notification' => 'File Deleted', 'notification' => 'File Deleted',
@ -79,4 +80,26 @@ return [
'notification' => 'File Saved', 'notification' => 'File Saved',
], ],
], ],
'alerts' => [
'file_too_large' => [
'title' => '<code>:name</code> is too large!',
'body' => 'Max is :max',
],
'file_not_found' => [
'title' => '<code>:name</code> not found!',
],
'file_not_editable' => [
'title' => '<code>:name</code> is a directory',
],
'file_already_exists' => [
'title' => '<code>:name</code> already exists!',
],
'files_node_error' => [
'title' => 'Could not load files!',
],
'pelicanignore' => [
'title' => 'You are editing a <code>.pelicanignore</code> file!',
'body' => 'Any files or directories listed in here will be excluded from backups. Wildcards are supported by using an asterisk (<code>*</code>).<br>You can negate a prior rule by prepending an exclamation point (<code>!</code>).',
],
],
]; ];

View File

@ -6,6 +6,7 @@ return [
'title' => 'Server Information', 'title' => 'Server Information',
'information' => 'Information', 'information' => 'Information',
'name' => 'Server Name', 'name' => 'Server Name',
'server_name' => 'Server Name: :name',
'notification_name' => 'Updated Server Name', 'notification_name' => 'Updated Server Name',
'description' => 'Server Description', 'description' => 'Server Description',
'notification_description' => 'Updated Server Description', 'notification_description' => 'Updated Server Description',
@ -15,7 +16,7 @@ return [
'limits' => [ 'limits' => [
'title' => 'Limits', 'title' => 'Limits',
'unlimited' => 'Unlimited', 'unlimited' => 'Unlimited',
'of' => 'of', 'of' => 'of :max',
'cpu' => 'CPU', 'cpu' => 'CPU',
'memory' => 'Memory', 'memory' => 'Memory',
'disk' => 'Disk Space', 'disk' => 'Disk Space',

View File

@ -34,7 +34,7 @@ return [
'settings_rename' => 'Allows a user to rename this server.', 'settings_rename' => 'Allows a user to rename this server.',
'settings_description' => 'Allows a user to change the description of this server.', 'settings_description' => 'Allows a user to change the description of this server.',
'activity_read' => 'Allows a user to view the activity logs for the server.', 'activity_read' => 'Allows a user to view the activity logs for the server.',
'websocket_*' => 'Allows a user access to the websocket for this server.', 'websocket_connect' => 'Allows a user access to the websocket for this server.',
'control_console' => 'Allows a user to send data to the server console.', 'control_console' => 'Allows a user to send data to the server console.',
'control_start' => 'Allows a user to start the server instance.', 'control_start' => 'Allows a user to start the server instance.',
'control_stop' => 'Allows a user to stop the server instance.', 'control_stop' => 'Allows a user to stop the server instance.',