mirror of
https://github.com/pelican-dev/panel.git
synced 2025-05-19 18:44:46 +02:00
Admin Area Translations (#965)
* Init * Health Page * Admin API Keys * Update API Keys * Database Hosts * Mounts * remove `s` * Users * Webhooks * Server never again... * Fix Server * Settings * Update Mounts * Update Databasehost * Update Server * Oops, Update Server * Nodes * Update User * Dashboard * Update Server * Profile * Egg * Role & Update Egg * Add base Laravel lang files * update apikey * remove html back to settings, remove comment * add `:resource` to create_action * Update Egg * Update Egg v2 * Update 1 * trans cf info label * Update charts * more trans * Update Webhook * update Health * Update Server * Update Role * Fixes * Bulk Update * AnotherOne * Fix relation button label * rename `admin1` to `admin` Leftover from testing... oops * More Translations * Updates * `pint` + Relation Manager Titles
This commit is contained in:
parent
513117cc42
commit
f8ad720f52
58
app/Checks/CacheCheck.php
Normal file
58
app/Checks/CacheCheck.php
Normal file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace App\Checks;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Str;
|
||||
use Spatie\Health\Checks\Check;
|
||||
use Spatie\Health\Checks\Result;
|
||||
|
||||
class CacheCheck extends Check
|
||||
{
|
||||
protected ?string $driver = null;
|
||||
|
||||
public function driver(string $driver): self
|
||||
{
|
||||
$this->driver = $driver;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function run(): Result
|
||||
{
|
||||
$driver = $this->driver ?? $this->defaultDriver();
|
||||
|
||||
$result = Result::make()->meta([
|
||||
'driver' => $driver,
|
||||
]);
|
||||
|
||||
try {
|
||||
return $this->canWriteValuesToCache($driver)
|
||||
? $result->ok(trans('admin/health.results.cache.ok'))
|
||||
: $result->failed(trans('admin/health.results.cache.failed_retrieve'));
|
||||
} catch (Exception $exception) {
|
||||
return $result->failed(trans('admin/health.results.cache.failed', ['error' => $exception->getMessage()]));
|
||||
}
|
||||
}
|
||||
|
||||
protected function defaultDriver(): ?string
|
||||
{
|
||||
return config('cache.default', 'file');
|
||||
}
|
||||
|
||||
protected function canWriteValuesToCache(?string $driver): bool
|
||||
{
|
||||
$expectedValue = Str::random(5);
|
||||
|
||||
$cacheName = "laravel-health:check-{$expectedValue}";
|
||||
|
||||
Cache::driver($driver)->put($cacheName, $expectedValue, 10);
|
||||
|
||||
$actualValue = Cache::driver($driver)->get($cacheName);
|
||||
|
||||
Cache::driver($driver)->forget($cacheName);
|
||||
|
||||
return $actualValue === $expectedValue;
|
||||
}
|
||||
}
|
42
app/Checks/DatabaseCheck.php
Normal file
42
app/Checks/DatabaseCheck.php
Normal file
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\Checks;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Spatie\Health\Checks\Check;
|
||||
use Spatie\Health\Checks\Result;
|
||||
|
||||
class DatabaseCheck extends Check
|
||||
{
|
||||
protected ?string $connectionName = null;
|
||||
|
||||
public function connectionName(string $connectionName): self
|
||||
{
|
||||
$this->connectionName = $connectionName;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function run(): Result
|
||||
{
|
||||
$connectionName = $this->connectionName ?? $this->getDefaultConnectionName();
|
||||
|
||||
$result = Result::make()->meta([
|
||||
'connection_name' => $connectionName,
|
||||
]);
|
||||
|
||||
try {
|
||||
DB::connection($connectionName)->getPdo();
|
||||
|
||||
return $result->ok(trans('admin/health.results.database.ok'));
|
||||
} catch (Exception $exception) {
|
||||
return $result->failed(trans('admin/health.results.database.failed', ['error' => $exception->getMessage()]));
|
||||
}
|
||||
}
|
||||
|
||||
protected function getDefaultConnectionName(): string
|
||||
{
|
||||
return config('database.default');
|
||||
}
|
||||
}
|
44
app/Checks/DebugModeCheck.php
Normal file
44
app/Checks/DebugModeCheck.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Checks;
|
||||
|
||||
use Spatie\Health\Checks\Check;
|
||||
use Spatie\Health\Checks\Result;
|
||||
|
||||
use function config;
|
||||
|
||||
class DebugModeCheck extends Check
|
||||
{
|
||||
protected bool $expected = false;
|
||||
|
||||
public function expectedToBe(bool $bool): self
|
||||
{
|
||||
$this->expected = $bool;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function run(): Result
|
||||
{
|
||||
$actual = config('app.debug');
|
||||
|
||||
$result = Result::make()
|
||||
->meta([
|
||||
'actual' => $actual,
|
||||
'expected' => $this->expected,
|
||||
])
|
||||
->shortSummary($this->convertToWord($actual));
|
||||
|
||||
return $this->expected === $actual
|
||||
? $result->ok()
|
||||
: $result->failed(trans('admin/health.results.debugmode.failed', [
|
||||
'actual' => $this->convertToWord($actual),
|
||||
'expected' => $this->convertToWord($this->expected),
|
||||
]));
|
||||
}
|
||||
|
||||
protected function convertToWord(bool $boolean): string
|
||||
{
|
||||
return $boolean ? 'true' : 'false';
|
||||
}
|
||||
}
|
38
app/Checks/EnvironmentCheck.php
Normal file
38
app/Checks/EnvironmentCheck.php
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace App\Checks;
|
||||
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Spatie\Health\Checks\Check;
|
||||
use Spatie\Health\Checks\Result;
|
||||
|
||||
class EnvironmentCheck extends Check
|
||||
{
|
||||
protected string $expectedEnvironment = 'production';
|
||||
|
||||
public function expectEnvironment(string $expectedEnvironment): self
|
||||
{
|
||||
$this->expectedEnvironment = $expectedEnvironment;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function run(): Result
|
||||
{
|
||||
$actualEnvironment = (string) App::environment();
|
||||
|
||||
$result = Result::make()
|
||||
->meta([
|
||||
'actual' => $actualEnvironment,
|
||||
'expected' => $this->expectedEnvironment,
|
||||
])
|
||||
->shortSummary($actualEnvironment);
|
||||
|
||||
return $this->expectedEnvironment === $actualEnvironment
|
||||
? $result->ok(trans('admin/health.results.environment.ok'))
|
||||
: $result->failed(trans('admin/health.results.environment.failed', [
|
||||
'actual' => $actualEnvironment,
|
||||
'expected' => $this->expectedEnvironment,
|
||||
]));
|
||||
}
|
||||
}
|
@ -17,7 +17,9 @@ class NodeVersionsCheck extends Check
|
||||
$all = Node::query()->count();
|
||||
|
||||
if ($all === 0) {
|
||||
$result = Result::make()->notificationMessage('No Nodes created')->shortSummary('No Nodes');
|
||||
$result = Result::make()
|
||||
->notificationMessage(trans('admin/health.results.nodeversions.no_nodes_created'))
|
||||
->shortSummary(trans('admin/health.results.node_version.no_nodes'));
|
||||
$result->status = Status::skipped();
|
||||
|
||||
return $result;
|
||||
@ -34,10 +36,10 @@ class NodeVersionsCheck extends Check
|
||||
'all' => $all,
|
||||
'outdated' => $outdated,
|
||||
])
|
||||
->shortSummary($outdated === 0 ? 'All up-to-date' : "{$outdated}/{$all} outdated");
|
||||
->shortSummary($outdated === 0 ? trans('admin/health.results.nodeversions.all_up_to_date') : trans('admin/health.results.nodeversions.outdated', ['outdated' => $outdated, 'all' => $all]));
|
||||
|
||||
return $outdated === 0
|
||||
? $result->ok('All Nodes are up-to-date.')
|
||||
: $result->failed(':outdated/:all Nodes are outdated.');
|
||||
? $result->ok(trans('admin/health.results.nodeversions.ok'))
|
||||
: $result->failed(trans('admin/health.results.nodeversions.failed', ['outdated' => $outdated, 'all' => $all]));
|
||||
}
|
||||
}
|
||||
|
@ -22,10 +22,13 @@ class PanelVersionCheck extends Check
|
||||
'currentVersion' => $currentVersion,
|
||||
'latestVersion' => $latestVersion,
|
||||
])
|
||||
->shortSummary($isLatest ? 'up-to-date' : 'outdated');
|
||||
->shortSummary($isLatest ? trans('admin/health.results.panelversion.up_to_date') : trans('admin/health.results.panelversion.outdated'));
|
||||
|
||||
return $isLatest
|
||||
? $result->ok('Panel is up-to-date.')
|
||||
: $result->failed('Installed version is `:currentVersion` but latest is `:latestVersion`.');
|
||||
? $result->ok(trans('admin/health.results.panelversion.ok'))
|
||||
: $result->failed(trans('admin/health.results.panelversion.failed', [
|
||||
'currentVersion' => $currentVersion,
|
||||
'latestVersion' => $latestVersion,
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
78
app/Checks/ScheduleCheck.php
Normal file
78
app/Checks/ScheduleCheck.php
Normal file
@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace App\Checks;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Composer\InstalledVersions;
|
||||
use Spatie\Health\Checks\Check;
|
||||
use Spatie\Health\Checks\Result;
|
||||
|
||||
class ScheduleCheck extends Check
|
||||
{
|
||||
protected string $cacheKey = 'health:checks:schedule:latestHeartbeatAt';
|
||||
|
||||
protected ?string $cacheStoreName = null;
|
||||
|
||||
protected int $heartbeatMaxAgeInMinutes = 1;
|
||||
|
||||
public function useCacheStore(string $cacheStoreName): self
|
||||
{
|
||||
$this->cacheStoreName = $cacheStoreName;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCacheStoreName(): string
|
||||
{
|
||||
return $this->cacheStoreName ?? config('cache.default');
|
||||
}
|
||||
|
||||
public function cacheKey(string $cacheKey): self
|
||||
{
|
||||
$this->cacheKey = $cacheKey;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function heartbeatMaxAgeInMinutes(int $heartbeatMaxAgeInMinutes): self
|
||||
{
|
||||
$this->heartbeatMaxAgeInMinutes = $heartbeatMaxAgeInMinutes;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCacheKey(): string
|
||||
{
|
||||
return $this->cacheKey;
|
||||
}
|
||||
|
||||
public function run(): Result
|
||||
{
|
||||
$result = Result::make()->ok(trans('admin/health.results.schedule.ok'));
|
||||
|
||||
$lastHeartbeatTimestamp = cache()->store($this->cacheStoreName)->get($this->cacheKey);
|
||||
|
||||
if (!$lastHeartbeatTimestamp) {
|
||||
return $result->failed(trans('admin/health.results.schedule.failed_not_ran'));
|
||||
}
|
||||
|
||||
$latestHeartbeatAt = Carbon::createFromTimestamp($lastHeartbeatTimestamp);
|
||||
|
||||
$carbonVersion = InstalledVersions::getVersion('nesbot/carbon');
|
||||
|
||||
$minutesAgo = $latestHeartbeatAt->diffInMinutes();
|
||||
|
||||
if (version_compare($carbonVersion,
|
||||
'3.0.0', '<')) {
|
||||
$minutesAgo += 1;
|
||||
}
|
||||
|
||||
if ($minutesAgo > $this->heartbeatMaxAgeInMinutes) {
|
||||
return $result->failed(trans('admin/health.results.schedule.failed_last_ran', [
|
||||
'time' => $minutesAgo,
|
||||
]));
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
@ -22,13 +22,16 @@ class Dashboard extends Page
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return trans('strings.dashboard');
|
||||
return trans('admin/dashboard.title');
|
||||
}
|
||||
|
||||
public static function getNavigationLabel(): string
|
||||
{
|
||||
return trans('admin/dashboard.title');
|
||||
}
|
||||
|
||||
protected static ?string $slug = '/';
|
||||
|
||||
public string $activeTab = 'nodes';
|
||||
|
||||
private SoftwareVersionService $softwareVersionService;
|
||||
|
||||
public function mount(SoftwareVersionService $softwareVersionService): void
|
||||
@ -51,33 +54,33 @@ class Dashboard extends Page
|
||||
|
||||
'devActions' => [
|
||||
CreateAction::make()
|
||||
->label('Bugs & Features')
|
||||
->label(trans('admin/dashboard.sections.intro-developers.button_issues'))
|
||||
->icon('tabler-brand-github')
|
||||
->url('https://github.com/pelican-dev/panel/discussions', true),
|
||||
->url('https://github.com/pelican-dev/panel/issues', true),
|
||||
],
|
||||
'updateActions' => [
|
||||
CreateAction::make()
|
||||
->label('Read Documentation')
|
||||
->label(trans('admin/dashboard.sections.intro-update-available.heading'))
|
||||
->icon('tabler-clipboard-text')
|
||||
->url('https://pelican.dev/docs/panel/update', true)
|
||||
->color('warning'),
|
||||
],
|
||||
'nodeActions' => [
|
||||
CreateAction::make()
|
||||
->label(trans('dashboard/index.sections.intro-first-node.button_label'))
|
||||
->label(trans('admin/dashboard.sections.intro-first-node.button_label'))
|
||||
->icon('tabler-server-2')
|
||||
->url(CreateNode::getUrl()),
|
||||
],
|
||||
'supportActions' => [
|
||||
CreateAction::make()
|
||||
->label(trans('dashboard/index.sections.intro-support.button_donate'))
|
||||
->label(trans('admin/dashboard.sections.intro-support.button_donate'))
|
||||
->icon('tabler-cash')
|
||||
->url('https://pelican.dev/donate', true)
|
||||
->color('success'),
|
||||
],
|
||||
'helpActions' => [
|
||||
CreateAction::make()
|
||||
->label(trans('dashboard/index.sections.intro-help.button_docs'))
|
||||
->label(trans('admin/dashboard.sections.intro-help.button_docs'))
|
||||
->icon('tabler-speedboat')
|
||||
->url('https://pelican.dev/docs', true),
|
||||
],
|
||||
|
@ -15,8 +15,6 @@ class Health extends Page
|
||||
{
|
||||
protected static ?string $navigationIcon = 'tabler-heart';
|
||||
|
||||
protected static ?string $navigationGroup = 'Advanced';
|
||||
|
||||
protected static string $view = 'filament.pages.health';
|
||||
|
||||
// @phpstan-ignore-next-line
|
||||
@ -24,6 +22,21 @@ class Health extends Page
|
||||
'refresh-component' => '$refresh',
|
||||
];
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return trans('admin/health.title');
|
||||
}
|
||||
|
||||
public static function getNavigationLabel(): string
|
||||
{
|
||||
return trans('admin/health.title');
|
||||
}
|
||||
|
||||
public static function getNavigationGroup(): ?string
|
||||
{
|
||||
return trans('admin/dashboard.advanced');
|
||||
}
|
||||
|
||||
public static function canAccess(): bool
|
||||
{
|
||||
return auth()->user()->can('view health');
|
||||
@ -33,6 +46,7 @@ class Health extends Page
|
||||
{
|
||||
return [
|
||||
Action::make('refresh')
|
||||
->label(trans('admin/health.refresh'))
|
||||
->button()
|
||||
->action('refresh'),
|
||||
];
|
||||
@ -62,7 +76,7 @@ class Health extends Page
|
||||
$this->dispatch('refresh-component');
|
||||
|
||||
Notification::make()
|
||||
->title('Health check results refreshed')
|
||||
->title(trans('admin/health.results_refreshed'))
|
||||
->success()
|
||||
->send();
|
||||
}
|
||||
@ -109,7 +123,7 @@ class Health extends Page
|
||||
return $carry;
|
||||
}, []);
|
||||
|
||||
return 'Failed: ' . implode(', ', $failedNames);
|
||||
return trans('admin/health.checks.failed') . implode(', ', $failedNames);
|
||||
}
|
||||
|
||||
public static function getNavigationIcon(): string
|
||||
|
@ -61,6 +61,16 @@ class Settings extends Page implements HasForms
|
||||
return auth()->user()->can('view settings');
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return trans('admin/setting.title');
|
||||
}
|
||||
|
||||
public static function getNavigationLabel(): string
|
||||
{
|
||||
return trans('admin/setting.title');
|
||||
}
|
||||
|
||||
protected function getFormSchema(): array
|
||||
{
|
||||
return [
|
||||
@ -70,28 +80,28 @@ class Settings extends Page implements HasForms
|
||||
->disabled(fn () => !auth()->user()->can('update settings'))
|
||||
->tabs([
|
||||
Tab::make('general')
|
||||
->label('General')
|
||||
->label(trans('admin/setting.navigation.general'))
|
||||
->icon('tabler-home')
|
||||
->schema($this->generalSettings()),
|
||||
Tab::make('captcha')
|
||||
->label('Captcha')
|
||||
->label(trans('admin/setting.navigation.captcha'))
|
||||
->icon('tabler-shield')
|
||||
->schema($this->captchaSettings())
|
||||
->columns(3),
|
||||
Tab::make('mail')
|
||||
->label('Mail')
|
||||
->label(trans('admin/setting.navigation.mail'))
|
||||
->icon('tabler-mail')
|
||||
->schema($this->mailSettings()),
|
||||
Tab::make('backup')
|
||||
->label('Backup')
|
||||
->label(trans('admin/setting.navigation.backup'))
|
||||
->icon('tabler-box')
|
||||
->schema($this->backupSettings()),
|
||||
Tab::make('OAuth')
|
||||
->label('OAuth')
|
||||
->label(trans('admin/setting.navigation.oauth'))
|
||||
->icon('tabler-brand-oauth')
|
||||
->schema($this->oauthSettings()),
|
||||
Tab::make('misc')
|
||||
->label('Misc')
|
||||
->label(trans('admin/setting.navigation.misc'))
|
||||
->icon('tabler-tool')
|
||||
->schema($this->miscSettings()),
|
||||
]),
|
||||
@ -102,17 +112,17 @@ class Settings extends Page implements HasForms
|
||||
{
|
||||
return [
|
||||
TextInput::make('APP_NAME')
|
||||
->label('App Name')
|
||||
->label(trans('admin/setting.general.app_name'))
|
||||
->required()
|
||||
->default(env('APP_NAME', 'Pelican')),
|
||||
TextInput::make('APP_FAVICON')
|
||||
->label('App Favicon')
|
||||
->label(trans('admin/setting.general.app_favicon'))
|
||||
->hintIcon('tabler-question-mark')
|
||||
->hintIconTooltip('Favicons should be placed in the public folder, located in the root panel directory.')
|
||||
->hintIconTooltip(trans('admin/setting.general.app_favicon_help'))
|
||||
->required()
|
||||
->default(env('APP_FAVICON', '/pelican.ico')),
|
||||
Toggle::make('APP_DEBUG')
|
||||
->label('Enable Debug Mode?')
|
||||
->label(trans('admin/setting.general.debug_mode'))
|
||||
->inline(false)
|
||||
->onIcon('tabler-check')
|
||||
->offIcon('tabler-x')
|
||||
@ -122,52 +132,52 @@ class Settings extends Page implements HasForms
|
||||
->afterStateUpdated(fn ($state, Set $set) => $set('APP_DEBUG', (bool) $state))
|
||||
->default(env('APP_DEBUG', config('app.debug'))),
|
||||
ToggleButtons::make('FILAMENT_TOP_NAVIGATION')
|
||||
->label('Navigation')
|
||||
->label(trans('admin/setting.general.navigation'))
|
||||
->inline()
|
||||
->options([
|
||||
false => 'Sidebar',
|
||||
true => 'Topbar',
|
||||
false => trans('admin/setting.general.sidebar'),
|
||||
true => trans('admin/setting.general.topbar'),
|
||||
])
|
||||
->formatStateUsing(fn ($state): bool => (bool) $state)
|
||||
->afterStateUpdated(fn ($state, Set $set) => $set('FILAMENT_TOP_NAVIGATION', (bool) $state))
|
||||
->default(env('FILAMENT_TOP_NAVIGATION', config('panel.filament.top-navigation'))),
|
||||
ToggleButtons::make('PANEL_USE_BINARY_PREFIX')
|
||||
->label('Unit prefix')
|
||||
->label(trans('admin/setting.general.unit_prefix'))
|
||||
->inline()
|
||||
->options([
|
||||
false => 'Decimal Prefix (MB/ GB)',
|
||||
true => 'Binary Prefix (MiB/ GiB)',
|
||||
false => trans('admin/setting.general.decimal_prefix'),
|
||||
true => trans('admin/setting.general.binary_prefix'),
|
||||
])
|
||||
->formatStateUsing(fn ($state): bool => (bool) $state)
|
||||
->afterStateUpdated(fn ($state, Set $set) => $set('PANEL_USE_BINARY_PREFIX', (bool) $state))
|
||||
->default(env('PANEL_USE_BINARY_PREFIX', config('panel.use_binary_prefix'))),
|
||||
ToggleButtons::make('APP_2FA_REQUIRED')
|
||||
->label('2FA Requirement')
|
||||
->label(trans('admin/setting.general.2fa_requirement'))
|
||||
->inline()
|
||||
->options([
|
||||
0 => 'Not required',
|
||||
1 => 'Required for only Admins',
|
||||
2 => 'Required for all Users',
|
||||
0 => trans('admin/setting.general.not_required'),
|
||||
1 => trans('admin/setting.general.admins_only'),
|
||||
2 => trans('admin/setting.general.all_users'),
|
||||
])
|
||||
->formatStateUsing(fn ($state): int => (int) $state)
|
||||
->afterStateUpdated(fn ($state, Set $set) => $set('APP_2FA_REQUIRED', (int) $state))
|
||||
->default(env('APP_2FA_REQUIRED', config('panel.auth.2fa_required'))),
|
||||
TagsInput::make('TRUSTED_PROXIES')
|
||||
->label('Trusted Proxies')
|
||||
->label(trans('admin/setting.general.trusted_proxies'))
|
||||
->separator()
|
||||
->splitKeys(['Tab', ' '])
|
||||
->placeholder('New IP or IP Range')
|
||||
->placeholder(trans('admin/setting.general.trusted_proxies_help'))
|
||||
->default(env('TRUSTED_PROXIES', implode(',', config('trustedproxy.proxies'))))
|
||||
->hintActions([
|
||||
FormAction::make('clear')
|
||||
->label('Clear')
|
||||
->label(trans('admin/setting.general.clear'))
|
||||
->color('danger')
|
||||
->icon('tabler-trash')
|
||||
->requiresConfirmation()
|
||||
->authorize(fn () => auth()->user()->can('update settings'))
|
||||
->action(fn (Set $set) => $set('TRUSTED_PROXIES', [])),
|
||||
FormAction::make('cloudflare')
|
||||
->label('Set to Cloudflare IPs')
|
||||
->label(trans('admin/setting.general.set_to_cf'))
|
||||
->icon('tabler-brand-cloudflare')
|
||||
->authorize(fn () => auth()->user()->can('update settings'))
|
||||
->action(function (Factory $client, Set $set) {
|
||||
@ -193,7 +203,7 @@ class Settings extends Page implements HasForms
|
||||
}),
|
||||
]),
|
||||
Select::make('FILAMENT_WIDTH')
|
||||
->label('Display Width')
|
||||
->label(trans('admin/setting.general.display_width'))
|
||||
->native(false)
|
||||
->options(MaxWidth::class)
|
||||
->default(env('FILAMENT_WIDTH', config('panel.filament.display-width'))),
|
||||
@ -204,7 +214,7 @@ class Settings extends Page implements HasForms
|
||||
{
|
||||
return [
|
||||
Toggle::make('TURNSTILE_ENABLED')
|
||||
->label('Enable Turnstile Captcha?')
|
||||
->label(trans('admin/setting.captcha.enable'))
|
||||
->inline(false)
|
||||
->columnSpan(1)
|
||||
->onIcon('tabler-check')
|
||||
@ -216,22 +226,23 @@ class Settings extends Page implements HasForms
|
||||
->afterStateUpdated(fn ($state, Set $set) => $set('TURNSTILE_ENABLED', (bool) $state))
|
||||
->default(env('TURNSTILE_ENABLED', config('turnstile.turnstile_enabled'))),
|
||||
Placeholder::make('info')
|
||||
->label(trans('admin/setting.captcha.info_label'))
|
||||
->columnSpan(2)
|
||||
->content(new HtmlString('<p>You can generate the keys on your <u><a href="https://developers.cloudflare.com/turnstile/get-started/#get-a-sitekey-and-secret-key" target="_blank">Cloudflare Dashboard</a></u>. A Cloudflare account is required.</p>')),
|
||||
->content(new HtmlString('<u><a href="https://developers.cloudflare.com/turnstile/get-started/#get-a-sitekey-and-secret-key" target="_blank">Link to Cloudflare Dashboard</a></u><br> ' . trans('admin/setting.captcha.info'))),
|
||||
TextInput::make('TURNSTILE_SITE_KEY')
|
||||
->label('Site Key')
|
||||
->label(trans('admin/setting.captcha.site_key'))
|
||||
->required()
|
||||
->visible(fn (Get $get) => $get('TURNSTILE_ENABLED'))
|
||||
->default(env('TURNSTILE_SITE_KEY', config('turnstile.turnstile_site_key')))
|
||||
->placeholder('1x00000000000000000000AA'),
|
||||
TextInput::make('TURNSTILE_SECRET_KEY')
|
||||
->label('Secret Key')
|
||||
->label(trans('admin/setting.captcha.secret_key'))
|
||||
->required()
|
||||
->visible(fn (Get $get) => $get('TURNSTILE_ENABLED'))
|
||||
->default(env('TURNSTILE_SECRET_KEY', config('turnstile.secret_key')))
|
||||
->placeholder('1x0000000000000000000000000000000AA'),
|
||||
Toggle::make('TURNSTILE_VERIFY_DOMAIN')
|
||||
->label('Verify domain?')
|
||||
->label(trans('admin/setting.captcha.verify'))
|
||||
->inline(false)
|
||||
->onIcon('tabler-check')
|
||||
->offIcon('tabler-x')
|
||||
@ -248,7 +259,7 @@ class Settings extends Page implements HasForms
|
||||
{
|
||||
return [
|
||||
ToggleButtons::make('MAIL_MAILER')
|
||||
->label('Mail Driver')
|
||||
->label(trans('admin/setting.mail.mail_driver'))
|
||||
->columnSpanFull()
|
||||
->inline()
|
||||
->options([
|
||||
@ -263,7 +274,7 @@ class Settings extends Page implements HasForms
|
||||
->default(env('MAIL_MAILER', config('mail.default')))
|
||||
->hintAction(
|
||||
FormAction::make('test')
|
||||
->label('Send Test Mail')
|
||||
->label(trans('admin/setting.mail.test_mail'))
|
||||
->icon('tabler-send')
|
||||
->hidden(fn (Get $get) => $get('MAIL_MAILER') === 'log')
|
||||
->authorize(fn () => auth()->user()->can('update settings'))
|
||||
@ -303,12 +314,12 @@ class Settings extends Page implements HasForms
|
||||
->notify(new MailTested(auth()->user()));
|
||||
|
||||
Notification::make()
|
||||
->title('Test Mail sent')
|
||||
->title(trans('admin/setting.mail.test_mail_sent'))
|
||||
->success()
|
||||
->send();
|
||||
} catch (Exception $exception) {
|
||||
Notification::make()
|
||||
->title('Test Mail failed')
|
||||
->title(trans('admin/setting.mail.test_mail_failed'))
|
||||
->body($exception->getMessage())
|
||||
->danger()
|
||||
->send();
|
||||
@ -317,50 +328,50 @@ class Settings extends Page implements HasForms
|
||||
}
|
||||
})
|
||||
),
|
||||
Section::make('"From" Settings')
|
||||
->description('Set the Address and Name used as "From" in mails.')
|
||||
Section::make(trans('admin/setting.mail.from_settings'))
|
||||
->description(trans('admin/setting.mail.from_settings_help'))
|
||||
->columns()
|
||||
->schema([
|
||||
TextInput::make('MAIL_FROM_ADDRESS')
|
||||
->label('From Address')
|
||||
->label(trans('admin/setting.mail.from_address'))
|
||||
->required()
|
||||
->email()
|
||||
->default(env('MAIL_FROM_ADDRESS', config('mail.from.address'))),
|
||||
TextInput::make('MAIL_FROM_NAME')
|
||||
->label('From Name')
|
||||
->label(trans('admin/setting.mail.from_name'))
|
||||
->required()
|
||||
->default(env('MAIL_FROM_NAME', config('mail.from.name'))),
|
||||
]),
|
||||
Section::make('SMTP Configuration')
|
||||
Section::make(trans('admin/setting.mail.smtp.smtp_title'))
|
||||
->columns()
|
||||
->visible(fn (Get $get) => $get('MAIL_MAILER') === 'smtp')
|
||||
->schema([
|
||||
TextInput::make('MAIL_HOST')
|
||||
->label('Host')
|
||||
->label(trans('admin/setting.mail.smtp.host'))
|
||||
->required()
|
||||
->default(env('MAIL_HOST', config('mail.mailers.smtp.host'))),
|
||||
TextInput::make('MAIL_PORT')
|
||||
->label('Port')
|
||||
->label(trans('admin/setting.mail.smtp.port'))
|
||||
->required()
|
||||
->numeric()
|
||||
->minValue(1)
|
||||
->maxValue(65535)
|
||||
->default(env('MAIL_PORT', config('mail.mailers.smtp.port'))),
|
||||
TextInput::make('MAIL_USERNAME')
|
||||
->label('Username')
|
||||
->label(trans('admin/setting.mail.smtp.username'))
|
||||
->default(env('MAIL_USERNAME', config('mail.mailers.smtp.username'))),
|
||||
TextInput::make('MAIL_PASSWORD')
|
||||
->label('Password')
|
||||
->label(trans('admin/setting.mail.smtp.password'))
|
||||
->password()
|
||||
->revealable()
|
||||
->default(env('MAIL_PASSWORD')),
|
||||
ToggleButtons::make('MAIL_ENCRYPTION')
|
||||
->label('Encryption')
|
||||
->label(trans('admin/setting.mail.smtp.encryption'))
|
||||
->inline()
|
||||
->options([
|
||||
'tls' => 'TLS',
|
||||
'ssl' => 'SSL',
|
||||
'' => 'None',
|
||||
'tls' => trans('admin/setting.mail.smtp.tls'),
|
||||
'ssl' => trans('admin/setting.mail.smtp.ssl'),
|
||||
'' => trans('admin/setting.mail.smtp.none'),
|
||||
])
|
||||
->default(env('MAIL_ENCRYPTION', config('mail.mailers.smtp.encryption', 'tls')))
|
||||
->live()
|
||||
@ -373,20 +384,20 @@ class Settings extends Page implements HasForms
|
||||
$set('MAIL_PORT', $port);
|
||||
}),
|
||||
]),
|
||||
Section::make('Mailgun Configuration')
|
||||
Section::make(trans('admin/setting.mail.mailgun.mailgun_title'))
|
||||
->columns()
|
||||
->visible(fn (Get $get) => $get('MAIL_MAILER') === 'mailgun')
|
||||
->schema([
|
||||
TextInput::make('MAILGUN_DOMAIN')
|
||||
->label('Domain')
|
||||
->label(trans('admin/setting.mail.mailgun.domain'))
|
||||
->required()
|
||||
->default(env('MAILGUN_DOMAIN', config('services.mailgun.domain'))),
|
||||
TextInput::make('MAILGUN_SECRET')
|
||||
->label('Secret')
|
||||
->label(trans('admin/setting.mail.mailgun.secret'))
|
||||
->required()
|
||||
->default(env('MAILGUN_SECRET', config('services.mailgun.secret'))),
|
||||
TextInput::make('MAILGUN_ENDPOINT')
|
||||
->label('Endpoint')
|
||||
->label(trans('admin/setting.mail.mailgun.endpoint'))
|
||||
->required()
|
||||
->default(env('MAILGUN_ENDPOINT', config('services.mailgun.endpoint'))),
|
||||
]),
|
||||
@ -397,7 +408,7 @@ class Settings extends Page implements HasForms
|
||||
{
|
||||
return [
|
||||
ToggleButtons::make('APP_BACKUP_DRIVER')
|
||||
->label('Backup Driver')
|
||||
->label(trans('admin/setting.backup.backup_driver'))
|
||||
->columnSpanFull()
|
||||
->inline()
|
||||
->options([
|
||||
@ -406,50 +417,50 @@ class Settings extends Page implements HasForms
|
||||
])
|
||||
->live()
|
||||
->default(env('APP_BACKUP_DRIVER', config('backups.default'))),
|
||||
Section::make('Throttles')
|
||||
->description('Configure how many backups can be created in a period. Set period to 0 to disable this throttle.')
|
||||
Section::make(trans('admin/setting.backup.throttle'))
|
||||
->description(trans('admin/setting.backup.throttle_help'))
|
||||
->columns()
|
||||
->schema([
|
||||
TextInput::make('BACKUP_THROTTLE_LIMIT')
|
||||
->label('Limit')
|
||||
->label(trans('admin/setting.backup.limit'))
|
||||
->required()
|
||||
->numeric()
|
||||
->minValue(1)
|
||||
->default(config('backups.throttles.limit')),
|
||||
TextInput::make('BACKUP_THROTTLE_PERIOD')
|
||||
->label('Period')
|
||||
->label(trans('admin/setting.backup.period'))
|
||||
->required()
|
||||
->numeric()
|
||||
->minValue(0)
|
||||
->suffix('Seconds')
|
||||
->default(config('backups.throttles.period')),
|
||||
]),
|
||||
Section::make('S3 Configuration')
|
||||
Section::make(trans('admin/setting.backup.s3.s3_title'))
|
||||
->columns()
|
||||
->visible(fn (Get $get) => $get('APP_BACKUP_DRIVER') === Backup::ADAPTER_AWS_S3)
|
||||
->schema([
|
||||
TextInput::make('AWS_DEFAULT_REGION')
|
||||
->label('Default Region')
|
||||
->label(trans('admin/setting.backup.s3.default_region'))
|
||||
->required()
|
||||
->default(config('backups.disks.s3.region')),
|
||||
TextInput::make('AWS_ACCESS_KEY_ID')
|
||||
->label('Access Key ID')
|
||||
->label(trans('admin/setting.backup.s3.access_key'))
|
||||
->required()
|
||||
->default(config('backups.disks.s3.key')),
|
||||
TextInput::make('AWS_SECRET_ACCESS_KEY')
|
||||
->label('Secret Access Key')
|
||||
->label(trans('admin/setting.backup.s3.secret_key'))
|
||||
->required()
|
||||
->default(config('backups.disks.s3.secret')),
|
||||
TextInput::make('AWS_BACKUPS_BUCKET')
|
||||
->label('Bucket')
|
||||
->label(trans('admin/setting.backup.s3.bucket'))
|
||||
->required()
|
||||
->default(config('backups.disks.s3.bucket')),
|
||||
TextInput::make('AWS_ENDPOINT')
|
||||
->label('Endpoint')
|
||||
->label(trans('admin/setting.backup.s3.endpoint'))
|
||||
->required()
|
||||
->default(config('backups.disks.s3.endpoint')),
|
||||
Toggle::make('AWS_USE_PATH_STYLE_ENDPOINT')
|
||||
->label('Use path style endpoint?')
|
||||
->label(trans('admin/setting.backup.s3.use_path_style_endpoint'))
|
||||
->inline(false)
|
||||
->onIcon('tabler-check')
|
||||
->offIcon('tabler-x')
|
||||
@ -484,18 +495,18 @@ class Settings extends Page implements HasForms
|
||||
Actions::make([
|
||||
FormAction::make("disable_oauth_$id")
|
||||
->visible(fn (Get $get) => $get("OAUTH_{$id}_ENABLED"))
|
||||
->label('Disable')
|
||||
->label(trans('admin/setting.oauth.disable'))
|
||||
->color('danger')
|
||||
->action(function (Set $set) use ($id) {
|
||||
$set("OAUTH_{$id}_ENABLED", false);
|
||||
}),
|
||||
FormAction::make("enable_oauth_$id")
|
||||
->visible(fn (Get $get) => !$get("OAUTH_{$id}_ENABLED"))
|
||||
->label('Enable')
|
||||
->label(trans('admin/setting.oauth.enable'))
|
||||
->color('success')
|
||||
->steps($oauthProvider->getSetupSteps())
|
||||
->modalHeading("Enable $name")
|
||||
->modalSubmitActionLabel('Enable')
|
||||
->modalHeading(trans('admin/setting.oauth.enable') . $name)
|
||||
->modalSubmitActionLabel(trans('admin/setting.oauth.enable'))
|
||||
->modalCancelAction(false)
|
||||
->action(function ($data, Set $set) use ($id) {
|
||||
$data = array_merge([
|
||||
@ -522,14 +533,14 @@ class Settings extends Page implements HasForms
|
||||
private function miscSettings(): array
|
||||
{
|
||||
return [
|
||||
Section::make('Automatic Allocation Creation')
|
||||
->description('Toggle if Users can create allocations via the client area.')
|
||||
Section::make(trans('admin/setting.misc.auto_allocation.title'))
|
||||
->description(trans('admin/setting.misc.auto_allocation.helper'))
|
||||
->columns()
|
||||
->collapsible()
|
||||
->collapsed()
|
||||
->schema([
|
||||
Toggle::make('PANEL_CLIENT_ALLOCATIONS_ENABLED')
|
||||
->label('Allow Users to create allocations?')
|
||||
->label(trans('admin/setting.misc.auto_allocation.question'))
|
||||
->onIcon('tabler-check')
|
||||
->offIcon('tabler-x')
|
||||
->onColor('success')
|
||||
@ -540,7 +551,7 @@ class Settings extends Page implements HasForms
|
||||
->afterStateUpdated(fn ($state, Set $set) => $set('PANEL_CLIENT_ALLOCATIONS_ENABLED', (bool) $state))
|
||||
->default(env('PANEL_CLIENT_ALLOCATIONS_ENABLED', config('panel.client_features.allocations.enabled'))),
|
||||
TextInput::make('PANEL_CLIENT_ALLOCATIONS_RANGE_START')
|
||||
->label('Starting Port')
|
||||
->label(trans('admin/setting.misc.auto_allocation.start'))
|
||||
->required()
|
||||
->numeric()
|
||||
->minValue(1024)
|
||||
@ -548,7 +559,7 @@ class Settings extends Page implements HasForms
|
||||
->visible(fn (Get $get) => $get('PANEL_CLIENT_ALLOCATIONS_ENABLED'))
|
||||
->default(env('PANEL_CLIENT_ALLOCATIONS_RANGE_START')),
|
||||
TextInput::make('PANEL_CLIENT_ALLOCATIONS_RANGE_END')
|
||||
->label('Ending Port')
|
||||
->label(trans('admin/setting.misc.auto_allocation.end'))
|
||||
->required()
|
||||
->numeric()
|
||||
->minValue(1024)
|
||||
@ -556,14 +567,14 @@ class Settings extends Page implements HasForms
|
||||
->visible(fn (Get $get) => $get('PANEL_CLIENT_ALLOCATIONS_ENABLED'))
|
||||
->default(env('PANEL_CLIENT_ALLOCATIONS_RANGE_END')),
|
||||
]),
|
||||
Section::make('Mail Notifications')
|
||||
->description('Toggle which mail notifications should be sent to Users.')
|
||||
Section::make(trans('admin/setting.misc.mail_notifications.title'))
|
||||
->description(trans('admin/setting.misc.mail_notifications.helper'))
|
||||
->columns()
|
||||
->collapsible()
|
||||
->collapsed()
|
||||
->schema([
|
||||
Toggle::make('PANEL_SEND_INSTALL_NOTIFICATION')
|
||||
->label('Server Installed')
|
||||
->label(trans('admin/setting.misc.mail_notifications.server_installed'))
|
||||
->onIcon('tabler-check')
|
||||
->offIcon('tabler-x')
|
||||
->onColor('success')
|
||||
@ -574,7 +585,7 @@ class Settings extends Page implements HasForms
|
||||
->afterStateUpdated(fn ($state, Set $set) => $set('PANEL_SEND_INSTALL_NOTIFICATION', (bool) $state))
|
||||
->default(env('PANEL_SEND_INSTALL_NOTIFICATION', config('panel.email.send_install_notification'))),
|
||||
Toggle::make('PANEL_SEND_REINSTALL_NOTIFICATION')
|
||||
->label('Server Reinstalled')
|
||||
->label(trans('admin/setting.misc.mail_notifications.server_reinstalled'))
|
||||
->onIcon('tabler-check')
|
||||
->offIcon('tabler-x')
|
||||
->onColor('success')
|
||||
@ -585,45 +596,45 @@ class Settings extends Page implements HasForms
|
||||
->afterStateUpdated(fn ($state, Set $set) => $set('PANEL_SEND_REINSTALL_NOTIFICATION', (bool) $state))
|
||||
->default(env('PANEL_SEND_REINSTALL_NOTIFICATION', config('panel.email.send_reinstall_notification'))),
|
||||
]),
|
||||
Section::make('Connections')
|
||||
->description('Timeouts used when making requests.')
|
||||
Section::make(trans('admin/setting.misc.connections.title'))
|
||||
->description(trans('admin/setting.misc.connections.helper'))
|
||||
->columns()
|
||||
->collapsible()
|
||||
->collapsed()
|
||||
->schema([
|
||||
TextInput::make('GUZZLE_TIMEOUT')
|
||||
->label('Request Timeout')
|
||||
->label(trans('admin/setting.misc.connections.request_timeout'))
|
||||
->required()
|
||||
->numeric()
|
||||
->minValue(15)
|
||||
->maxValue(60)
|
||||
->suffix('Seconds')
|
||||
->suffix(trans('admin/setting.misc.connections.seconds'))
|
||||
->default(env('GUZZLE_TIMEOUT', config('panel.guzzle.timeout'))),
|
||||
TextInput::make('GUZZLE_CONNECT_TIMEOUT')
|
||||
->label('Connect Timeout')
|
||||
->label(trans('admin/setting.misc.connections.connection_timeout'))
|
||||
->required()
|
||||
->numeric()
|
||||
->minValue(5)
|
||||
->maxValue(60)
|
||||
->suffix('Seconds')
|
||||
->suffix(trans('admin/setting.misc.connections.seconds'))
|
||||
->default(env('GUZZLE_CONNECT_TIMEOUT', config('panel.guzzle.connect_timeout'))),
|
||||
]),
|
||||
Section::make('Activity Logs')
|
||||
->description('Configure how often old activity logs should be pruned and whether admin activities should be logged.')
|
||||
Section::make(trans('admin/setting.misc.activity_log.title'))
|
||||
->description(trans('admin/setting.misc.activity_log.helper'))
|
||||
->columns()
|
||||
->collapsible()
|
||||
->collapsed()
|
||||
->schema([
|
||||
TextInput::make('APP_ACTIVITY_PRUNE_DAYS')
|
||||
->label('Prune age')
|
||||
->label(trans('admin/setting.misc.activity_log.prune_age'))
|
||||
->required()
|
||||
->numeric()
|
||||
->minValue(1)
|
||||
->maxValue(365)
|
||||
->suffix('Days')
|
||||
->suffix(trans('admin/setting.misc.activity_log.days'))
|
||||
->default(env('APP_ACTIVITY_PRUNE_DAYS', config('activity.prune_days'))),
|
||||
Toggle::make('APP_ACTIVITY_HIDE_ADMIN')
|
||||
->label('Hide admin activities?')
|
||||
->label(trans('admin/setting.misc.activity_log.log_admin'))
|
||||
->inline(false)
|
||||
->onIcon('tabler-check')
|
||||
->offIcon('tabler-x')
|
||||
@ -634,35 +645,35 @@ class Settings extends Page implements HasForms
|
||||
->afterStateUpdated(fn ($state, Set $set) => $set('APP_ACTIVITY_HIDE_ADMIN', (bool) $state))
|
||||
->default(env('APP_ACTIVITY_HIDE_ADMIN', config('activity.hide_admin_activity'))),
|
||||
]),
|
||||
Section::make('API')
|
||||
->description('Defines the rate limit for the number of requests per minute that can be executed.')
|
||||
Section::make(trans('admin/setting.misc.api.title'))
|
||||
->description(trans('admin/setting.misc.api.helper'))
|
||||
->columns()
|
||||
->collapsible()
|
||||
->collapsed()
|
||||
->schema([
|
||||
TextInput::make('APP_API_CLIENT_RATELIMIT')
|
||||
->label('Client API Rate Limit')
|
||||
->label(trans('admin/setting.misc.api.client_rate'))
|
||||
->required()
|
||||
->numeric()
|
||||
->minValue(1)
|
||||
->suffix('Requests Per Minute')
|
||||
->suffix(trans('admin/setting.misc.api.rpm'))
|
||||
->default(env('APP_API_CLIENT_RATELIMIT', config('http.rate_limit.client'))),
|
||||
TextInput::make('APP_API_APPLICATION_RATELIMIT')
|
||||
->label('Application API Rate Limit')
|
||||
->label(trans('admin/setting.misc.api.app_rate'))
|
||||
->required()
|
||||
->numeric()
|
||||
->minValue(1)
|
||||
->suffix('Requests Per Minute')
|
||||
->suffix(trans('admin/setting.misc.api.rpm'))
|
||||
->default(env('APP_API_APPLICATION_RATELIMIT', config('http.rate_limit.application'))),
|
||||
]),
|
||||
Section::make('Server')
|
||||
->description('Settings for Servers.')
|
||||
Section::make(trans('admin/setting.misc.server.title'))
|
||||
->description(trans('admin/setting.misc.server.helper'))
|
||||
->columns()
|
||||
->collapsible()
|
||||
->collapsed()
|
||||
->schema([
|
||||
Toggle::make('PANEL_EDITABLE_SERVER_DESCRIPTIONS')
|
||||
->label('Allow Users to edit Server Descriptions?')
|
||||
->label(trans('admin/setting.misc.server.edit_server_desc'))
|
||||
->onIcon('tabler-check')
|
||||
->offIcon('tabler-x')
|
||||
->onColor('success')
|
||||
@ -673,19 +684,19 @@ class Settings extends Page implements HasForms
|
||||
->afterStateUpdated(fn ($state, Set $set) => $set('PANEL_EDITABLE_SERVER_DESCRIPTIONS', (bool) $state))
|
||||
->default(env('PANEL_EDITABLE_SERVER_DESCRIPTIONS', config('panel.editable_server_descriptions'))),
|
||||
]),
|
||||
Section::make('Webhook')
|
||||
->description('Configure how often old webhook logs should be pruned.')
|
||||
Section::make(trans('admin/setting.misc.webhook.title'))
|
||||
->description(trans('admin/setting.misc.webhook.helper'))
|
||||
->columns()
|
||||
->collapsible()
|
||||
->collapsed()
|
||||
->schema([
|
||||
TextInput::make('APP_WEBHOOK_PRUNE_DAYS')
|
||||
->label('Prune age')
|
||||
->label(trans('admin/setting.misc.webhook.prune_age'))
|
||||
->required()
|
||||
->numeric()
|
||||
->minValue(1)
|
||||
->maxValue(365)
|
||||
->suffix('Days')
|
||||
->suffix(trans('admin/setting.misc.webhook.days'))
|
||||
->default(env('APP_WEBHOOK_PRUNE_DAYS', config('panel.webhook.prune_days'))),
|
||||
]),
|
||||
];
|
||||
@ -712,12 +723,12 @@ class Settings extends Page implements HasForms
|
||||
$this->redirect($this->getUrl());
|
||||
|
||||
Notification::make()
|
||||
->title('Settings saved')
|
||||
->title(trans('admin/setting.save_success'))
|
||||
->success()
|
||||
->send();
|
||||
} catch (Exception $exception) {
|
||||
Notification::make()
|
||||
->title('Save failed')
|
||||
->title(trans('admin/setting.save_failed'))
|
||||
->body($exception->getMessage())
|
||||
->danger()
|
||||
->send();
|
||||
|
@ -10,21 +10,33 @@ class ApiKeyResource extends Resource
|
||||
{
|
||||
protected static ?string $model = ApiKey::class;
|
||||
|
||||
protected static ?string $modelLabel = 'Application API Key';
|
||||
|
||||
protected static ?string $pluralModelLabel = 'Application API Keys';
|
||||
|
||||
protected static ?string $navigationLabel = 'API Keys';
|
||||
|
||||
protected static ?string $navigationIcon = 'tabler-key';
|
||||
|
||||
protected static ?string $navigationGroup = 'Advanced';
|
||||
public static function getNavigationLabel(): string
|
||||
{
|
||||
return trans('admin/apikey.nav_title');
|
||||
}
|
||||
|
||||
public static function getModelLabel(): string
|
||||
{
|
||||
return trans('admin/apikey.model_label');
|
||||
}
|
||||
|
||||
public static function getPluralModelLabel(): string
|
||||
{
|
||||
return trans('admin/apikey.model_label_plural');
|
||||
}
|
||||
|
||||
public static function getNavigationBadge(): ?string
|
||||
{
|
||||
return static::getModel()::where('key_type', ApiKey::TYPE_APPLICATION)->count() ?: null;
|
||||
}
|
||||
|
||||
public static function getNavigationGroup(): ?string
|
||||
{
|
||||
return trans('admin/dashboard.advanced');
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
|
@ -57,10 +57,10 @@ class CreateApiKey extends CreateRecord
|
||||
collect(ApiKey::getPermissionList())->map(fn ($resource) => ToggleButtons::make('permissions_' . $resource)
|
||||
->label(str($resource)->replace('_', ' ')->title())->inline()
|
||||
->options([
|
||||
0 => 'None',
|
||||
1 => 'Read',
|
||||
// 2 => 'Write',
|
||||
3 => 'Read & Write',
|
||||
0 => trans('admin/apikey.permissions.none'),
|
||||
1 => trans('admin/apikey.permissions.read'),
|
||||
// 2 => 'Write', // Makes no sense to have write-only permissions when you can't read it?
|
||||
3 => trans('admin/apikey.permissions.read_write'),
|
||||
])
|
||||
->icons([
|
||||
0 => 'tabler-book-off',
|
||||
@ -85,18 +85,15 @@ class CreateApiKey extends CreateRecord
|
||||
),
|
||||
|
||||
TagsInput::make('allowed_ips')
|
||||
->placeholder('Example: 127.0.0.1 or 192.168.1.1')
|
||||
->label('Whitelisted IPv4 Addresses')
|
||||
->helperText('Press enter to add a new IP address or leave blank to allow any IP address')
|
||||
->placeholder('127.0.0.1 or 192.168.1.1')
|
||||
->label(trans('admin/apikey.whitelist'))
|
||||
->helperText(trans('admin/apikey.whitelist_help'))
|
||||
->columnSpanFull(),
|
||||
|
||||
Textarea::make('memo')
|
||||
->required()
|
||||
->label('Description')
|
||||
->helperText('
|
||||
Once you have assigned permissions and created this set of credentials you will be unable to come back and edit it.
|
||||
If you need to make changes down the road you will need to create a new set of credentials.
|
||||
')
|
||||
->label(trans('admin/apikey.description'))
|
||||
->helperText(trans('admin/apikey.description_help'))
|
||||
->columnSpanFull(),
|
||||
]);
|
||||
}
|
||||
|
@ -23,12 +23,13 @@ class ListApiKeys extends ListRecords
|
||||
->modifyQueryUsing(fn ($query) => $query->where('key_type', ApiKey::TYPE_APPLICATION))
|
||||
->columns([
|
||||
TextColumn::make('key')
|
||||
->label(trans('admin/apikey.table.key'))
|
||||
->copyable()
|
||||
->icon('tabler-clipboard-text')
|
||||
->state(fn (ApiKey $key) => $key->identifier . $key->token),
|
||||
|
||||
TextColumn::make('memo')
|
||||
->label('Description')
|
||||
->label(trans('admin/apikey.table.description'))
|
||||
->wrap()
|
||||
->limit(50),
|
||||
|
||||
@ -37,16 +38,16 @@ class ListApiKeys extends ListRecords
|
||||
->searchable(),
|
||||
|
||||
DateTimeColumn::make('last_used_at')
|
||||
->label('Last Used')
|
||||
->placeholder('Not Used')
|
||||
->label(trans('admin/apikey.table.last_used'))
|
||||
->placeholder(trans('admin/apikey.table.never_used'))
|
||||
->sortable(),
|
||||
|
||||
DateTimeColumn::make('created_at')
|
||||
->label('Created')
|
||||
->label(trans('admin/apikey.table.created'))
|
||||
->sortable(),
|
||||
|
||||
TextColumn::make('user.username')
|
||||
->label('Created By')
|
||||
->label(trans('admin/apikey.table.created_by'))
|
||||
->url(fn (ApiKey $apiKey): string => route('filament.admin.resources.users.edit', ['record' => $apiKey->user])),
|
||||
])
|
||||
->actions([
|
||||
@ -54,10 +55,10 @@ class ListApiKeys extends ListRecords
|
||||
])
|
||||
->emptyStateIcon('tabler-key')
|
||||
->emptyStateDescription('')
|
||||
->emptyStateHeading('No API Keys')
|
||||
->emptyStateHeading(trans('admin/apikey.empty_table'))
|
||||
->emptyStateActions([
|
||||
CreateAction::make('create')
|
||||
->label('Create API Key')
|
||||
->label(trans('admin/apikey.create_action', ['action' => trans('filament-actions::create.single.modal.actions.create.label')]))
|
||||
->button(),
|
||||
]);
|
||||
}
|
||||
@ -66,7 +67,7 @@ class ListApiKeys extends ListRecords
|
||||
{
|
||||
return [
|
||||
Actions\CreateAction::make()
|
||||
->label('Create API Key')
|
||||
->label(trans('admin/apikey.create_action', ['action' => trans('filament-actions::create.single.modal.actions.create.label')]))
|
||||
->hidden(fn () => ApiKey::where('key_type', ApiKey::TYPE_APPLICATION)->count() <= 0),
|
||||
];
|
||||
}
|
||||
|
@ -12,8 +12,6 @@ class DatabaseHostResource extends Resource
|
||||
|
||||
protected static ?string $navigationIcon = 'tabler-database';
|
||||
|
||||
protected static ?string $navigationGroup = 'Advanced';
|
||||
|
||||
protected static ?string $recordTitleAttribute = 'name';
|
||||
|
||||
public static function getNavigationBadge(): ?string
|
||||
@ -21,6 +19,26 @@ class DatabaseHostResource extends Resource
|
||||
return static::getModel()::count() ?: null;
|
||||
}
|
||||
|
||||
public static function getNavigationLabel(): string
|
||||
{
|
||||
return trans('admin/databasehost.nav_title');
|
||||
}
|
||||
|
||||
public static function getModelLabel(): string
|
||||
{
|
||||
return trans('admin/databasehost.model_label');
|
||||
}
|
||||
|
||||
public static function getPluralModelLabel(): string
|
||||
{
|
||||
return trans('admin/databasehost.model_label_plural');
|
||||
}
|
||||
|
||||
public static function getNavigationGroup(): ?string
|
||||
{
|
||||
return trans('admin/dashboard.advanced');
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
|
@ -42,44 +42,47 @@ class CreateDatabaseHost extends CreateRecord
|
||||
->schema([
|
||||
TextInput::make('host')
|
||||
->columnSpan(2)
|
||||
->helperText('The IP address or Domain name that should be used when attempting to connect to this MySQL host from this Panel to create new databases.')
|
||||
->label(trans('admin/databasehost.host'))
|
||||
->helperText(trans('admin/databasehost.host_help'))
|
||||
->required()
|
||||
->live(onBlur: true)
|
||||
->afterStateUpdated(fn ($state, Forms\Set $set) => $set('name', $state))
|
||||
->maxLength(255),
|
||||
TextInput::make('port')
|
||||
->columnSpan(1)
|
||||
->helperText('The port that MySQL is running on for this host.')
|
||||
->label(trans('admin/databasehost.port'))
|
||||
->helperText(trans('admin/databasehost.port_help'))
|
||||
->required()
|
||||
->numeric()
|
||||
->default(3306)
|
||||
->minValue(0)
|
||||
->maxValue(65535),
|
||||
TextInput::make('max_databases')
|
||||
->label('Max databases')
|
||||
->helpertext('Blank is unlimited.')
|
||||
->label(trans('admin/databasehost.max_database'))
|
||||
->helpertext(trans('admin/databasehost.max_databases_help'))
|
||||
->numeric(),
|
||||
TextInput::make('name')
|
||||
->label('Display Name')
|
||||
->helperText('A short identifier used to distinguish this location from others. Must be between 1 and 60 characters, for example, us.nyc.lvl3.')
|
||||
->label(trans('admin/databasehost.display_name'))
|
||||
->helperText(trans('admin/databasehost.display_name_help'))
|
||||
->required()
|
||||
->maxLength(60),
|
||||
TextInput::make('username')
|
||||
->helperText('The username of an account that has enough permissions to create new users and databases on the system.')
|
||||
->label(trans('admin/databasehost.username'))
|
||||
->helperText(trans('admin/databasehost.username_help'))
|
||||
->required()
|
||||
->maxLength(255),
|
||||
TextInput::make('password')
|
||||
->helperText('The password for the database user.')
|
||||
->label(trans('admin/databasehost.password'))
|
||||
->helperText(trans('admin/databasehost.password_help'))
|
||||
->password()
|
||||
->revealable()
|
||||
->maxLength(255)
|
||||
->required(),
|
||||
Select::make('node_ids')
|
||||
->required()
|
||||
->maxLength(255),
|
||||
Select::make('nodes')
|
||||
->multiple()
|
||||
->searchable()
|
||||
->preload()
|
||||
->helperText('This setting only defaults to this database host when adding a database to a server on the selected node.')
|
||||
->label('Linked Nodes')
|
||||
->helperText(trans('admin/databasehost.linked_nodes_help'))
|
||||
->label(trans('admin/databasehost.linked_nodes'))
|
||||
->relationship('nodes', 'name'),
|
||||
]),
|
||||
]);
|
||||
@ -103,7 +106,7 @@ class CreateDatabaseHost extends CreateRecord
|
||||
return $this->service->handle($data);
|
||||
} catch (PDOException $exception) {
|
||||
Notification::make()
|
||||
->title('Error connecting to database host')
|
||||
->title(trans('admin/databasehost.error'))
|
||||
->body($exception->getMessage())
|
||||
->color('danger')
|
||||
->icon('tabler-database')
|
||||
|
@ -43,33 +43,37 @@ class EditDatabaseHost extends EditRecord
|
||||
->schema([
|
||||
TextInput::make('host')
|
||||
->columnSpan(2)
|
||||
->helperText('The IP address or Domain name that should be used when attempting to connect to this MySQL host from this Panel to create new databases.')
|
||||
->label(trans('admin/databasehost.host'))
|
||||
->helperText(trans('admin/databasehost.host_help'))
|
||||
->required()
|
||||
->live(onBlur: true)
|
||||
->afterStateUpdated(fn ($state, Forms\Set $set) => $set('name', $state))
|
||||
->maxLength(255),
|
||||
TextInput::make('port')
|
||||
->columnSpan(1)
|
||||
->helperText('The port that MySQL is running on for this host.')
|
||||
->label(trans('admin/databasehost.port'))
|
||||
->helperText(trans('admin/databasehost.port_help'))
|
||||
->required()
|
||||
->numeric()
|
||||
->minValue(0)
|
||||
->maxValue(65535),
|
||||
TextInput::make('max_databases')
|
||||
->label('Max databases')
|
||||
->helpertext('Blank is unlimited.')
|
||||
->label(trans('admin/databasehost.max_database'))
|
||||
->helpertext(trans('admin/databasehost.max_databases_help'))
|
||||
->numeric(),
|
||||
TextInput::make('name')
|
||||
->label('Display Name')
|
||||
->helperText('A short identifier used to distinguish this location from others. Must be between 1 and 60 characters, for example, us.nyc.lvl3.')
|
||||
->label(trans('admin/databasehost.display_name'))
|
||||
->helperText(trans('admin/databasehost.display_name_help'))
|
||||
->required()
|
||||
->maxLength(60),
|
||||
TextInput::make('username')
|
||||
->helperText('The username of an account that has enough permissions to create new users and databases on the system.')
|
||||
->label(trans('admin/databasehost.username'))
|
||||
->helperText(trans('admin/databasehost.username_help'))
|
||||
->required()
|
||||
->maxLength(255),
|
||||
TextInput::make('password')
|
||||
->helperText('The password for the database user.')
|
||||
->label(trans('admin/databasehost.password'))
|
||||
->helperText(trans('admin/databasehost.password_help'))
|
||||
->password()
|
||||
->revealable()
|
||||
->maxLength(255),
|
||||
@ -77,8 +81,8 @@ class EditDatabaseHost extends EditRecord
|
||||
->multiple()
|
||||
->searchable()
|
||||
->preload()
|
||||
->helperText('This setting only defaults to this database host when adding a database to a server on the selected node.')
|
||||
->label('Linked Nodes')
|
||||
->helperText(trans('admin/databasehost.linked_nodes_help'))
|
||||
->label(trans('admin/databasehost.linked_nodes'))
|
||||
->relationship('nodes', 'name'),
|
||||
]),
|
||||
]);
|
||||
@ -88,7 +92,7 @@ class EditDatabaseHost extends EditRecord
|
||||
{
|
||||
return [
|
||||
Actions\DeleteAction::make()
|
||||
->label(fn (DatabaseHost $databaseHost) => $databaseHost->databases()->count() > 0 ? 'Database Host Has Databases' : 'Delete')
|
||||
->label(fn (DatabaseHost $databaseHost) => $databaseHost->databases()->count() > 0 ? trans('admin/databasehost.delete_help') : trans('filament-actions::delete.single.modal.actions.delete.label'))
|
||||
->disabled(fn (DatabaseHost $databaseHost) => $databaseHost->databases()->count() > 0),
|
||||
$this->getSaveFormAction()->formId('form'),
|
||||
];
|
||||
@ -120,7 +124,7 @@ class EditDatabaseHost extends EditRecord
|
||||
return $this->hostUpdateService->handle($record, $data);
|
||||
} catch (PDOException $exception) {
|
||||
Notification::make()
|
||||
->title('Error connecting to database host')
|
||||
->title(trans('admin/databasehost.connection_error'))
|
||||
->body($exception->getMessage())
|
||||
->color('danger')
|
||||
->icon('tabler-database')
|
||||
|
@ -17,29 +17,31 @@ class ListDatabaseHosts extends ListRecords
|
||||
{
|
||||
protected static string $resource = DatabaseHostResource::class;
|
||||
|
||||
protected ?string $heading = 'Database Hosts';
|
||||
|
||||
public function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->searchable(false)
|
||||
->columns([
|
||||
TextColumn::make('name')
|
||||
->label(trans('admin/databasehost.table.name'))
|
||||
->searchable(),
|
||||
TextColumn::make('host')
|
||||
->label(trans('admin/databasehost.table.host'))
|
||||
->searchable(),
|
||||
TextColumn::make('port')
|
||||
->label(trans('admin/databasehost.table.port'))
|
||||
->sortable(),
|
||||
TextColumn::make('username')
|
||||
->label(trans('admin/databasehost.table.username'))
|
||||
->searchable(),
|
||||
TextColumn::make('databases_count')
|
||||
->counts('databases')
|
||||
->icon('tabler-database')
|
||||
->label('Databases'),
|
||||
->label(trans('admin/databasehost.databases')),
|
||||
TextColumn::make('nodes.name')
|
||||
->icon('tabler-server-2')
|
||||
->badge()
|
||||
->placeholder('No Nodes')
|
||||
->placeholder(trans('admin/databasehost.no_nodes'))
|
||||
->sortable(),
|
||||
])
|
||||
->checkIfRecordIsSelectableUsing(fn (DatabaseHost $databaseHost) => !$databaseHost->databases_count)
|
||||
@ -54,10 +56,10 @@ class ListDatabaseHosts extends ListRecords
|
||||
])
|
||||
->emptyStateIcon('tabler-database')
|
||||
->emptyStateDescription('')
|
||||
->emptyStateHeading('No Database Hosts')
|
||||
->emptyStateHeading(trans('admin/databasehost.no_database_hosts'))
|
||||
->emptyStateActions([
|
||||
CreateAction::make('create')
|
||||
->label('Create Database Host')
|
||||
->label(trans('admin/databasehost.create_action', ['action' => trans('filament-actions::create.single.modal.actions.create.label')]))
|
||||
->button(),
|
||||
]);
|
||||
}
|
||||
@ -66,7 +68,7 @@ class ListDatabaseHosts extends ListRecords
|
||||
{
|
||||
return [
|
||||
Actions\CreateAction::make('create')
|
||||
->label('Create Database Host')
|
||||
->label(trans('admin/databasehost.create_action', ['action' => trans('filament-actions::create.single.modal.actions.create.label')]))
|
||||
->hidden(fn () => DatabaseHost::count() <= 0),
|
||||
];
|
||||
}
|
||||
|
@ -23,19 +23,22 @@ class DatabasesRelationManager extends RelationManager
|
||||
->schema([
|
||||
TextInput::make('database')
|
||||
->columnSpanFull(),
|
||||
TextInput::make('username'),
|
||||
TextInput::make('username')
|
||||
->label(trans('admin/databasehost.table.username')),
|
||||
TextInput::make('password')
|
||||
->label(trans('admin/databasehost.table.password'))
|
||||
->password()
|
||||
->revealable()
|
||||
->hintAction(RotateDatabasePasswordAction::make())
|
||||
->formatStateUsing(fn (Database $database) => $database->password),
|
||||
TextInput::make('remote')
|
||||
->label('Connections From')
|
||||
->formatStateUsing(fn (Database $record) => $record->remote === '%' ? 'Anywhere ( % )' : $record->remote),
|
||||
->label(trans('admin/databasehost.table.remote'))
|
||||
->formatStateUsing(fn (Database $record) => $record->remote === '%' ? trans('admin/databasehost.anywhere'). ' ( % )' : $record->remote),
|
||||
TextInput::make('max_connections')
|
||||
->formatStateUsing(fn (Database $record) => $record->max_connections === 0 ? 'Unlimited' : $record->max_connections),
|
||||
->label(trans('admin/databasehost.table.max_connections'))
|
||||
->formatStateUsing(fn (Database $record) => $record->max_connections === 0 ? trans('admin/databasehost.unlimited') : $record->max_connections),
|
||||
TextInput::make('jdbc')
|
||||
->label('JDBC Connection String')
|
||||
->label(trans('admin/databasehost.table.connection_string'))
|
||||
->columnSpanFull()
|
||||
->password()
|
||||
->revealable()
|
||||
@ -47,19 +50,24 @@ class DatabasesRelationManager extends RelationManager
|
||||
{
|
||||
return $table
|
||||
->recordTitleAttribute('servers')
|
||||
->heading('')
|
||||
->columns([
|
||||
TextColumn::make('database')
|
||||
->icon('tabler-database'),
|
||||
TextColumn::make('username')
|
||||
->label(trans('admin/databasehost.table.username'))
|
||||
->icon('tabler-user'),
|
||||
TextColumn::make('remote')
|
||||
->formatStateUsing(fn (Database $record) => $record->remote === '%' ? 'Anywhere ( % )' : $record->remote),
|
||||
->label(trans('admin/databasehost.table.remote'))
|
||||
->formatStateUsing(fn (Database $record) => $record->remote === '%' ? trans('admin/databasehost.anywhere'). ' ( % )' : $record->remote),
|
||||
TextColumn::make('server.name')
|
||||
->icon('tabler-brand-docker')
|
||||
->url(fn (Database $database) => route('filament.admin.resources.servers.edit', ['record' => $database->server_id])),
|
||||
TextColumn::make('max_connections')
|
||||
->formatStateUsing(fn ($record) => $record->max_connections === 0 ? 'Unlimited' : $record->max_connections),
|
||||
DateTimeColumn::make('created_at'),
|
||||
->label(trans('admin/databasehost.table.max_connections'))
|
||||
->formatStateUsing(fn ($record) => $record->max_connections === 0 ? trans('admin/databasehost.unlimited') : $record->max_connections),
|
||||
DateTimeColumn::make('created_at')
|
||||
->label(trans('admin/databasehost.table.created_at')),
|
||||
])
|
||||
->actions([
|
||||
DeleteAction::make()
|
||||
|
@ -12,8 +12,6 @@ class EggResource extends Resource
|
||||
|
||||
protected static ?string $navigationIcon = 'tabler-eggs';
|
||||
|
||||
protected static ?string $navigationGroup = 'Server';
|
||||
|
||||
protected static ?string $recordTitleAttribute = 'name';
|
||||
|
||||
public static function getNavigationBadge(): ?string
|
||||
@ -21,6 +19,26 @@ class EggResource extends Resource
|
||||
return static::getModel()::count() ?: null;
|
||||
}
|
||||
|
||||
public static function getNavigationGroup(): ?string
|
||||
{
|
||||
return trans('admin/dashboard.server');
|
||||
}
|
||||
|
||||
public static function getNavigationLabel(): string
|
||||
{
|
||||
return trans('admin/egg.nav_title');
|
||||
}
|
||||
|
||||
public static function getModelLabel(): string
|
||||
{
|
||||
return trans('admin/egg.model_label');
|
||||
}
|
||||
|
||||
public static function getPluralModelLabel(): string
|
||||
{
|
||||
return trans('admin/egg.model_label_plural');
|
||||
}
|
||||
|
||||
public static function getGloballySearchableAttributes(): array
|
||||
{
|
||||
return ['name', 'tags', 'uuid', 'id'];
|
||||
|
@ -48,69 +48,73 @@ class CreateEgg extends CreateRecord
|
||||
return $form
|
||||
->schema([
|
||||
Tabs::make()->tabs([
|
||||
Tab::make('Configuration')
|
||||
Tab::make(trans('admin/egg.tabs.configuration'))
|
||||
->columns(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 4])
|
||||
->schema([
|
||||
TextInput::make('name')
|
||||
->label(trans('admin/egg.name'))
|
||||
->required()
|
||||
->maxLength(255)
|
||||
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2])
|
||||
->helperText('A simple, human-readable name to use as an identifier for this Egg.'),
|
||||
->helperText(trans('admin/egg.name_help')),
|
||||
TextInput::make('author')
|
||||
->label(trans('admin/egg.author'))
|
||||
->maxLength(255)
|
||||
->required()
|
||||
->email()
|
||||
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2])
|
||||
->helperText('The author of this version of the Egg.'),
|
||||
->helperText(trans('admin/egg.author_help')),
|
||||
Textarea::make('description')
|
||||
->rows(3)
|
||||
->label(trans('admin/egg.description'))
|
||||
->rows(2)
|
||||
->columnSpanFull()
|
||||
->helperText('A description of this Egg that will be displayed throughout the Panel as needed.'),
|
||||
->helperText(trans('admin/egg.description_help')),
|
||||
Textarea::make('startup')
|
||||
->label(trans('admin/egg.startup'))
|
||||
->rows(3)
|
||||
->columnSpanFull()
|
||||
->required()
|
||||
->placeholder(implode("\n", [
|
||||
'java -Xms128M -XX:MaxRAMPercentage=95.0 -jar {{SERVER_JARFILE}}',
|
||||
]))
|
||||
->helperText('The default startup command that should be used for new servers using this Egg.'),
|
||||
->helperText(trans('admin/egg.startup_help')),
|
||||
TagsInput::make('file_denylist')
|
||||
->label(trans('admin/egg.file_denylist'))
|
||||
->placeholder('denied-file.txt')
|
||||
->helperText('A list of files that the end user is not allowed to edit.')
|
||||
->helperText(trans('admin/egg.file_denylist_help'))
|
||||
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2]),
|
||||
TagsInput::make('features')
|
||||
->placeholder('Add Feature')
|
||||
->helperText('')
|
||||
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2]),
|
||||
->label(trans('admin/egg.features'))
|
||||
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 1, 'lg' => 1]),
|
||||
Toggle::make('force_outgoing_ip')
|
||||
->label(trans('admin/egg.force_ip'))
|
||||
->hintIcon('tabler-question-mark')
|
||||
->hintIconTooltip("Forces all outgoing network traffic to have its Source IP NATed to the IP of the server's primary allocation IP.
|
||||
Required for certain games to work properly when the Node has multiple public IP addresses.
|
||||
Enabling this option will disable internal networking for any servers using this egg, causing them to be unable to internally access other servers on the same node."),
|
||||
->hintIconTooltip(trans('admin/egg.force_ip_help')),
|
||||
Hidden::make('script_is_privileged')
|
||||
->default(1),
|
||||
TagsInput::make('tags')
|
||||
->placeholder('Add Tags')
|
||||
->helperText('')
|
||||
->label(trans('admin/egg.tags'))
|
||||
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2]),
|
||||
TextInput::make('update_url')
|
||||
->label(trans('admin/egg.update_url'))
|
||||
->hintIcon('tabler-question-mark')
|
||||
->hintIconTooltip('URLs must point directly to the raw .json file.')
|
||||
->hintIconTooltip(trans('admin/egg.update_url_help'))
|
||||
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2])
|
||||
->url(),
|
||||
KeyValue::make('docker_images')
|
||||
->label(trans('admin/egg.docker_images'))
|
||||
->live()
|
||||
->columnSpanFull()
|
||||
->required()
|
||||
->addActionLabel('Add Image')
|
||||
->keyLabel('Name')
|
||||
->addActionLabel(trans('admin/egg.add_image'))
|
||||
->keyLabel(trans('admin/egg.docker_name'))
|
||||
->keyPlaceholder('Java 21')
|
||||
->valueLabel('Image URI')
|
||||
->valueLabel(trans('admin/egg.docker_uri'))
|
||||
->valuePlaceholder('ghcr.io/parkervcp/yolks:java_21')
|
||||
->helperText('The docker images available to servers using this egg.'),
|
||||
->helperText(trans('admin/egg.docker_help')),
|
||||
]),
|
||||
|
||||
Tab::make('Process Management')
|
||||
Tab::make(trans('admin/egg.tabs.process_management'))
|
||||
->columns()
|
||||
->schema([
|
||||
Hidden::make('config_from')
|
||||
@ -120,29 +124,29 @@ class CreateEgg extends CreateRecord
|
||||
// ->relationship('configFrom', 'name', ignoreRecord: true)
|
||||
->helperText('If you would like to default to settings from another Egg select it from the menu above.'),
|
||||
TextInput::make('config_stop')
|
||||
->label(trans('admin/egg.stop_command'))
|
||||
->required()
|
||||
->maxLength(255)
|
||||
->label('Stop Command')
|
||||
->helperText('The command that should be sent to server processes to stop them gracefully. If you need to send a SIGINT you should enter ^C here.'),
|
||||
->helperText(trans('admin/egg.stop_command_help')),
|
||||
Textarea::make('config_startup')->rows(10)->json()
|
||||
->label('Start Configuration')
|
||||
->label(trans('admin/egg.start_config'))
|
||||
->default('{}')
|
||||
->helperText('List of values the daemon should be looking for when booting a server to determine completion.'),
|
||||
->helperText(trans('admin/egg.start_config_help')),
|
||||
Textarea::make('config_files')->rows(10)->json()
|
||||
->label('Configuration Files')
|
||||
->label(trans('admin/egg.config_files'))
|
||||
->default('{}')
|
||||
->helperText('This should be a JSON representation of configuration files to modify and what parts should be changed.'),
|
||||
->helperText(trans('admin/egg.config_files_help')),
|
||||
Textarea::make('config_logs')->rows(10)->json()
|
||||
->label('Log Configuration')
|
||||
->label(trans('admin/egg.log_config'))
|
||||
->default('{}')
|
||||
->helperText('This should be a JSON representation of where log files are stored, and whether or not the daemon should be creating custom logs.'),
|
||||
->helperText(trans('admin/egg.log_config_help')),
|
||||
]),
|
||||
Tab::make('Egg Variables')
|
||||
Tab::make(trans('admin/egg.tabs.egg_variables'))
|
||||
->columnSpanFull()
|
||||
->schema([
|
||||
Repeater::make('variables')
|
||||
->label('')
|
||||
->addActionLabel('Add New Egg Variable')
|
||||
->addActionLabel(trans('admin/egg.add_new_variable'))
|
||||
->grid()
|
||||
->relationship('variables')
|
||||
->name('name')
|
||||
@ -171,6 +175,7 @@ class CreateEgg extends CreateRecord
|
||||
})
|
||||
->schema([
|
||||
TextInput::make('name')
|
||||
->label(trans('admin/egg.name'))
|
||||
->live()
|
||||
->debounce(750)
|
||||
->maxLength(255)
|
||||
@ -178,12 +183,12 @@ class CreateEgg extends CreateRecord
|
||||
->afterStateUpdated(fn (Set $set, $state) => $set('env_variable', str($state)->trim()->snake()->upper()->toString()))
|
||||
->unique(modifyRuleUsing: fn (Unique $rule, Get $get) => $rule->where('egg_id', $get('../../id')), ignoreRecord: true)
|
||||
->validationMessages([
|
||||
'unique' => 'A variable with this name already exists.',
|
||||
'unique' => trans('admin/egg.error_unique'),
|
||||
])
|
||||
->required(),
|
||||
Textarea::make('description')->columnSpanFull(),
|
||||
Textarea::make('description')->label(trans('admin/egg.description'))->columnSpanFull(),
|
||||
TextInput::make('env_variable')
|
||||
->label('Environment Variable')
|
||||
->label(trans('admin/egg.environment_variable'))
|
||||
->maxLength(255)
|
||||
->prefix('{{')
|
||||
->suffix('}}')
|
||||
@ -192,20 +197,20 @@ class CreateEgg extends CreateRecord
|
||||
->unique(modifyRuleUsing: fn (Unique $rule, Get $get) => $rule->where('egg_id', $get('../../id')), ignoreRecord: true)
|
||||
->rules(EggVariable::$validationRules['env_variable'])
|
||||
->validationMessages([
|
||||
'unique' => 'A variable with this name already exists.',
|
||||
'required' => ' The environment variable field is required.',
|
||||
'*' => 'This environment variable is reserved and cannot be used.',
|
||||
'unique' => trans('admin/egg.error_unique'),
|
||||
'required' => trans('admin/egg.error_required'),
|
||||
'*' => trans('admin/egg.error_reserved'),
|
||||
])
|
||||
->required(),
|
||||
TextInput::make('default_value')->maxLength(255),
|
||||
Fieldset::make('User Permissions')
|
||||
TextInput::make('default_value')->label(trans('admin/egg.default_value'))->maxLength(255),
|
||||
Fieldset::make(trans('admin/egg.user_permissions'))
|
||||
->schema([
|
||||
Checkbox::make('user_viewable')->label('Viewable'),
|
||||
Checkbox::make('user_editable')->label('Editable'),
|
||||
Checkbox::make('user_viewable')->label(trans('admin/egg.viewable')),
|
||||
Checkbox::make('user_editable')->label(trans('admin/egg.editable')),
|
||||
]),
|
||||
TagsInput::make('rules')
|
||||
->label(trans('admin/egg.rules'))
|
||||
->columnSpanFull()
|
||||
->placeholder('Add Rule')
|
||||
->reorderable()
|
||||
->suggestions([
|
||||
'required',
|
||||
@ -229,26 +234,26 @@ class CreateEgg extends CreateRecord
|
||||
]),
|
||||
]),
|
||||
]),
|
||||
Tab::make('Install Script')
|
||||
Tab::make(trans('admin/egg.tabs.install_script'))
|
||||
->columns(3)
|
||||
->schema([
|
||||
|
||||
Hidden::make('copy_script_from'),
|
||||
//->placeholder('None')
|
||||
//->relationship('scriptFrom', 'name', ignoreRecord: true),
|
||||
|
||||
TextInput::make('script_container')
|
||||
->label(trans('admin/egg.script_container'))
|
||||
->required()
|
||||
->maxLength(255)
|
||||
->default('ghcr.io/pelican-eggs/installers:debian'),
|
||||
|
||||
Select::make('script_entry')
|
||||
->label(trans('admin/egg.script_entry'))
|
||||
->selectablePlaceholder(false)
|
||||
->default('bash')
|
||||
->options(['bash', 'ash', '/bin/bash'])
|
||||
->required(),
|
||||
|
||||
MonacoEditor::make('script_install')
|
||||
->label(trans('admin/egg.script_install'))
|
||||
->columnSpanFull()
|
||||
->fontSize('16px')
|
||||
->language('shell')
|
||||
|
@ -37,98 +37,101 @@ class EditEgg extends EditRecord
|
||||
return $form
|
||||
->schema([
|
||||
Tabs::make()->tabs([
|
||||
Tab::make('Configuration')
|
||||
Tab::make(trans('admin/egg.tabs.configuration'))
|
||||
->columns(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 4])
|
||||
->icon('tabler-egg')
|
||||
->schema([
|
||||
TextInput::make('name')
|
||||
->label(trans('admin/egg.name'))
|
||||
->required()
|
||||
->maxLength(255)
|
||||
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 1])
|
||||
->helperText('A simple, human-readable name to use as an identifier for this Egg.'),
|
||||
->helperText(trans('admin/egg.name_help')),
|
||||
TextInput::make('uuid')
|
||||
->label('Egg UUID')
|
||||
->label(trans('admin/egg.egg_uuid'))
|
||||
->disabled()
|
||||
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 1, 'lg' => 2])
|
||||
->helperText('This is the globally unique identifier for this Egg which Wings uses as an identifier.'),
|
||||
->helperText(trans('admin/egg.uuid_help')),
|
||||
TextInput::make('id')
|
||||
->label('Egg ID')
|
||||
->label(trans('admin/egg.egg_id'))
|
||||
->disabled(),
|
||||
Textarea::make('description')
|
||||
->label(trans('admin/egg.description'))
|
||||
->rows(3)
|
||||
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2])
|
||||
->helperText('A description of this Egg that will be displayed throughout the Panel as needed.'),
|
||||
->helperText(trans('admin/egg.description_help')),
|
||||
TextInput::make('author')
|
||||
->label(trans('admin/egg.author'))
|
||||
->required()
|
||||
->maxLength(255)
|
||||
->email()
|
||||
->disabled()
|
||||
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2])
|
||||
->helperText('The author of this version of the Egg. Uploading a new Egg configuration from a different author will change this.'),
|
||||
->helperText(trans('admin/egg.author_help_edit')),
|
||||
Textarea::make('startup')
|
||||
->label(trans('admin/egg.startup'))
|
||||
->rows(3)
|
||||
->columnSpanFull()
|
||||
->required()
|
||||
->helperText('The default startup command that should be used for new servers using this Egg.'),
|
||||
->helperText(trans('admin/egg.startup_help')),
|
||||
TagsInput::make('file_denylist')
|
||||
->label(trans('admin/egg.file_denylist'))
|
||||
->placeholder('denied-file.txt')
|
||||
->helperText('A list of files that the end user is not allowed to edit.')
|
||||
->helperText(trans('admin/egg.file_denylist_help'))
|
||||
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2]),
|
||||
TagsInput::make('features')
|
||||
->placeholder('Add Feature')
|
||||
->helperText('')
|
||||
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2]),
|
||||
->label(trans('admin/egg.features'))
|
||||
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 1, 'lg' => 1]),
|
||||
Toggle::make('force_outgoing_ip')
|
||||
->inline(false)
|
||||
->label(trans('admin/egg.force_ip'))
|
||||
->hintIcon('tabler-question-mark')
|
||||
->hintIconTooltip("Forces all outgoing network traffic to have its Source IP NATed to the IP of the server's primary allocation IP.
|
||||
Required for certain games to work properly when the Node has multiple public IP addresses.
|
||||
Enabling this option will disable internal networking for any servers using this egg, causing them to be unable to internally access other servers on the same node."),
|
||||
->hintIconTooltip(trans('admin/egg.force_ip_help')),
|
||||
Hidden::make('script_is_privileged')
|
||||
->helperText('The docker images available to servers using this egg.'),
|
||||
TagsInput::make('tags')
|
||||
->placeholder('Add Tags')
|
||||
->helperText('')
|
||||
->label(trans('admin/egg.tags'))
|
||||
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2]),
|
||||
TextInput::make('update_url')
|
||||
->label('Update URL')
|
||||
->label(trans('admin/egg.update_url'))
|
||||
->url()
|
||||
->hintIcon('tabler-question-mark')
|
||||
->hintIconTooltip('URLs must point directly to the raw .json file.')
|
||||
->hintIconTooltip(trans('admin/egg.update_url_help'))
|
||||
->columnSpan(['default' => 1, 'sm' => 1, 'md' => 2, 'lg' => 2]),
|
||||
KeyValue::make('docker_images')
|
||||
->label(trans('admin/egg.docker_images'))
|
||||
->live()
|
||||
->columnSpanFull()
|
||||
->required()
|
||||
->addActionLabel('Add Image')
|
||||
->keyLabel('Name')
|
||||
->valueLabel('Image URI')
|
||||
->helperText('The docker images available to servers using this egg.'),
|
||||
->addActionLabel(trans('admin/egg.add_image'))
|
||||
->keyLabel(trans('admin/egg.docker_name'))
|
||||
->valueLabel(trans('admin/egg.docker_uri'))
|
||||
->helperText(trans('admin/egg.docker_help')),
|
||||
]),
|
||||
Tab::make('Process Management')
|
||||
Tab::make(trans('admin/egg.tabs.process_management'))
|
||||
->columns()
|
||||
->icon('tabler-server-cog')
|
||||
->schema([
|
||||
Select::make('config_from')
|
||||
->label('Copy Settings From')
|
||||
->placeholder('None')
|
||||
->label(trans('admin/egg.copy_from'))
|
||||
->placeholder(trans('admin/egg.none'))
|
||||
->relationship('configFrom', 'name', ignoreRecord: true)
|
||||
->helperText('If you would like to default to settings from another Egg select it from the menu above.'),
|
||||
->helperText(trans('admin/egg.copy_from_help')),
|
||||
TextInput::make('config_stop')
|
||||
->label(trans('admin/egg.stop_command'))
|
||||
->maxLength(255)
|
||||
->label('Stop Command')
|
||||
->helperText('The command that should be sent to server processes to stop them gracefully. If you need to send a SIGINT you should enter ^C here.'),
|
||||
->helperText(trans('admin/egg.stop_command_help')),
|
||||
Textarea::make('config_startup')->rows(10)->json()
|
||||
->label('Start Configuration')
|
||||
->helperText('List of values the daemon should be looking for when booting a server to determine completion.'),
|
||||
->label(trans('admin/egg.start_config'))
|
||||
->helperText(trans('admin/egg.start_config_help')),
|
||||
Textarea::make('config_files')->rows(10)->json()
|
||||
->label('Configuration Files')
|
||||
->helperText('This should be a JSON representation of configuration files to modify and what parts should be changed.'),
|
||||
->label(trans('admin/egg.config_files'))
|
||||
->helperText(trans('admin/egg.config_files_help')),
|
||||
Textarea::make('config_logs')->rows(10)->json()
|
||||
->label('Log Configuration')
|
||||
->helperText('This should be a JSON representation of where log files are stored, and whether or not the daemon should be creating custom logs.'),
|
||||
->label(trans('admin/egg.log_config'))
|
||||
->helperText(trans('admin/egg.log_config_help')),
|
||||
]),
|
||||
Tab::make('Egg Variables')
|
||||
Tab::make(trans('admin/egg.tabs.egg_variables'))
|
||||
->columnSpanFull()
|
||||
->icon('tabler-variable')
|
||||
->schema([
|
||||
@ -140,7 +143,7 @@ class EditEgg extends EditRecord
|
||||
->reorderable()
|
||||
->collapsible()->collapsed()
|
||||
->orderColumn()
|
||||
->addActionLabel('New Variable')
|
||||
->addActionLabel(trans('admin/egg.add_new_variable'))
|
||||
->itemLabel(fn (array $state) => $state['name'])
|
||||
->mutateRelationshipDataBeforeCreateUsing(function (array $data): array {
|
||||
$data['default_value'] ??= '';
|
||||
@ -162,6 +165,7 @@ class EditEgg extends EditRecord
|
||||
})
|
||||
->schema([
|
||||
TextInput::make('name')
|
||||
->label(trans('admin/egg.name'))
|
||||
->live()
|
||||
->debounce(750)
|
||||
->maxLength(255)
|
||||
@ -169,12 +173,12 @@ class EditEgg extends EditRecord
|
||||
->afterStateUpdated(fn (Set $set, $state) => $set('env_variable', str($state)->trim()->snake()->upper()->toString()))
|
||||
->unique(modifyRuleUsing: fn (Unique $rule, Get $get) => $rule->where('egg_id', $get('../../id')), ignoreRecord: true)
|
||||
->validationMessages([
|
||||
'unique' => 'A variable with this name already exists.',
|
||||
'unique' => trans('admin/egg.error_unique'),
|
||||
])
|
||||
->required(),
|
||||
Textarea::make('description')->columnSpanFull(),
|
||||
Textarea::make('description')->label(trans('admin/egg.description'))->columnSpanFull(),
|
||||
TextInput::make('env_variable')
|
||||
->label('Environment Variable')
|
||||
->label(trans('admin/egg.environment_variable'))
|
||||
->maxLength(255)
|
||||
->prefix('{{')
|
||||
->suffix('}}')
|
||||
@ -183,20 +187,20 @@ class EditEgg extends EditRecord
|
||||
->unique(modifyRuleUsing: fn (Unique $rule, Get $get) => $rule->where('egg_id', $get('../../id')), ignoreRecord: true)
|
||||
->rules(EggVariable::$validationRules['env_variable'])
|
||||
->validationMessages([
|
||||
'unique' => 'A variable with this name already exists.',
|
||||
'required' => ' The environment variable field is required.',
|
||||
'*' => 'This environment variable is reserved and cannot be used.',
|
||||
'unique' => trans('admin/egg.error_unique'),
|
||||
'required' => trans('admin/egg.error_required'),
|
||||
'*' => trans('admin/egg.error_reserved'),
|
||||
])
|
||||
->required(),
|
||||
TextInput::make('default_value')->maxLength(255),
|
||||
Fieldset::make('User Permissions')
|
||||
TextInput::make('default_value')->label(trans('admin/egg.default_value'))->maxLength(255),
|
||||
Fieldset::make(trans('admin/egg.user_permissions'))
|
||||
->schema([
|
||||
Checkbox::make('user_viewable')->label('Viewable'),
|
||||
Checkbox::make('user_editable')->label('Editable'),
|
||||
Checkbox::make('user_viewable')->label(trans('admin/egg.viewable')),
|
||||
Checkbox::make('user_editable')->label(trans('admin/egg.editable')),
|
||||
]),
|
||||
TagsInput::make('rules')
|
||||
->label(trans('admin/egg.rules'))
|
||||
->columnSpanFull()
|
||||
->placeholder('Add Rule')
|
||||
->reorderable()
|
||||
->suggestions([
|
||||
'required',
|
||||
@ -220,23 +224,26 @@ class EditEgg extends EditRecord
|
||||
]),
|
||||
]),
|
||||
]),
|
||||
Tab::make('Install Script')
|
||||
Tab::make(trans('admin/egg.tabs.install_script'))
|
||||
->columns(3)
|
||||
->icon('tabler-file-download')
|
||||
->schema([
|
||||
Select::make('copy_script_from')
|
||||
->placeholder('None')
|
||||
->label(trans('admin/egg.script_from'))
|
||||
->placeholder(trans('admin/egg.none'))
|
||||
->relationship('scriptFrom', 'name', ignoreRecord: true),
|
||||
TextInput::make('script_container')
|
||||
->label(trans('admin/egg.script_container'))
|
||||
->required()
|
||||
->maxLength(255)
|
||||
->default('alpine:3.4'),
|
||||
TextInput::make('script_entry')
|
||||
->label(trans('admin/egg.script_entry'))
|
||||
->required()
|
||||
->maxLength(255)
|
||||
->default('ash'),
|
||||
MonacoEditor::make('script_install')
|
||||
->label('Install Script')
|
||||
->label(trans('admin/egg.script_install'))
|
||||
->placeholderText('')
|
||||
->columnSpanFull()
|
||||
->fontSize('16px')
|
||||
@ -252,7 +259,7 @@ class EditEgg extends EditRecord
|
||||
return [
|
||||
DeleteAction::make()
|
||||
->disabled(fn (Egg $egg): bool => $egg->servers()->count() > 0)
|
||||
->label(fn (Egg $egg): string => $egg->servers()->count() <= 0 ? trans('filament-actions::delete.single.label') : 'In Use'),
|
||||
->label(fn (Egg $egg): string => $egg->servers()->count() <= 0 ? trans('filament-actions::delete.single.label') : trans('admin/egg.in_use')),
|
||||
ExportEggAction::make(),
|
||||
ImportEggAction::make(),
|
||||
$this->getSaveFormAction()->formId('form'),
|
||||
|
@ -32,6 +32,7 @@ class ListEggs extends ListRecords
|
||||
->label('Id')
|
||||
->hidden(),
|
||||
TextColumn::make('name')
|
||||
->label(trans('admin/egg.name'))
|
||||
->icon('tabler-egg')
|
||||
->description(fn ($record): ?string => (strlen($record->description) > 120) ? substr($record->description, 0, 120).'...' : $record->description)
|
||||
->wrap()
|
||||
@ -40,7 +41,7 @@ class ListEggs extends ListRecords
|
||||
TextColumn::make('servers_count')
|
||||
->counts('servers')
|
||||
->icon('tabler-server')
|
||||
->label('Servers'),
|
||||
->label(trans('admin/egg.servers')),
|
||||
])
|
||||
->actions([
|
||||
EditAction::make(),
|
||||
@ -55,10 +56,10 @@ class ListEggs extends ListRecords
|
||||
])
|
||||
->emptyStateIcon('tabler-eggs')
|
||||
->emptyStateDescription('')
|
||||
->emptyStateHeading('No Eggs')
|
||||
->emptyStateHeading(trans('admin/egg.no_eggs'))
|
||||
->emptyStateActions([
|
||||
CreateAction::make()
|
||||
->label('Create Egg'),
|
||||
->label(trans('admin/egg.create_action', ['action' => trans('filament-actions::create.single.modal.actions.create.label')])),
|
||||
ImportEggAction::make(),
|
||||
]);
|
||||
}
|
||||
@ -68,7 +69,7 @@ class ListEggs extends ListRecords
|
||||
return [
|
||||
ImportEggHeaderAction::make(),
|
||||
CreateHeaderAction::make()
|
||||
->label('Create Egg'),
|
||||
->label(trans('admin/egg.create_action', ['action' => trans('filament-actions::create.single.modal.actions.create.label')])),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -16,8 +16,10 @@ class ServersRelationManager extends RelationManager
|
||||
{
|
||||
return $table
|
||||
->recordTitleAttribute('servers')
|
||||
->emptyStateDescription('No Servers')->emptyStateHeading('No servers are assigned to this Egg.')
|
||||
->emptyStateDescription(trans('admin/egg.no_servers'))
|
||||
->emptyStateHeading(trans('admin/egg.no_servers_help'))
|
||||
->searchable(false)
|
||||
->heading(trans('admin/egg.servers'))
|
||||
->columns([
|
||||
TextColumn::make('user.username')
|
||||
->label('Owner')
|
||||
@ -25,6 +27,7 @@ class ServersRelationManager extends RelationManager
|
||||
->url(fn (Server $server): string => route('filament.admin.resources.users.edit', ['record' => $server->user]))
|
||||
->sortable(),
|
||||
TextColumn::make('name')
|
||||
->label(trans('admin/server.name'))
|
||||
->icon('tabler-brand-docker')
|
||||
->url(fn (Server $server): string => route('filament.admin.resources.servers.edit', ['record' => $server]))
|
||||
->sortable(),
|
||||
@ -32,9 +35,9 @@ class ServersRelationManager extends RelationManager
|
||||
->icon('tabler-server-2')
|
||||
->url(fn (Server $server): string => route('filament.admin.resources.nodes.edit', ['record' => $server->node])),
|
||||
TextColumn::make('image')
|
||||
->label('Docker Image'),
|
||||
->label(trans('admin/server.docker_image')),
|
||||
SelectColumn::make('allocation.id')
|
||||
->label('Primary Allocation')
|
||||
->label(trans('admin/server.primary_allocation'))
|
||||
->options(fn (Server $server) => [$server->allocation->id => $server->allocation->address])
|
||||
->selectablePlaceholder(false)
|
||||
->sortable(),
|
||||
|
@ -12,15 +12,33 @@ class MountResource extends Resource
|
||||
|
||||
protected static ?string $navigationIcon = 'tabler-layers-linked';
|
||||
|
||||
protected static ?string $navigationGroup = 'Advanced';
|
||||
|
||||
protected static ?string $recordTitleAttribute = 'name';
|
||||
|
||||
public static function getNavigationLabel(): string
|
||||
{
|
||||
return trans('admin/mount.nav_title');
|
||||
}
|
||||
|
||||
public static function getModelLabel(): string
|
||||
{
|
||||
return trans('admin/mount.model_label');
|
||||
}
|
||||
|
||||
public static function getPluralModelLabel(): string
|
||||
{
|
||||
return trans('admin/mount.model_label_plural');
|
||||
}
|
||||
|
||||
public static function getNavigationBadge(): ?string
|
||||
{
|
||||
return static::getModel()::count() ?: null;
|
||||
}
|
||||
|
||||
public static function getNavigationGroup(): ?string
|
||||
{
|
||||
return trans('admin/dashboard.advanced');
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
|
@ -39,15 +39,16 @@ class CreateMount extends CreateRecord
|
||||
->schema([
|
||||
Section::make()->schema([
|
||||
TextInput::make('name')
|
||||
->label(trans('admin/mount.name'))
|
||||
->required()
|
||||
->helperText('Unique name used to separate this mount from another.')
|
||||
->helperText(trans('admin/mount.name_help'))
|
||||
->maxLength(64),
|
||||
ToggleButtons::make('read_only')
|
||||
->label('Read only?')
|
||||
->helperText('Is the mount read only inside the container?')
|
||||
->label(trans('admin/mount.read_only'))
|
||||
->helperText(trans('admin/mount.read_only_help'))
|
||||
->options([
|
||||
false => 'Writeable',
|
||||
true => 'Read only',
|
||||
false => trans('admin/mount.toggles.writable'),
|
||||
true => trans('admin/mount.toggles.read_only'),
|
||||
])
|
||||
->icons([
|
||||
false => 'tabler-writing',
|
||||
@ -61,12 +62,14 @@ class CreateMount extends CreateRecord
|
||||
->default(false)
|
||||
->required(),
|
||||
TextInput::make('source')
|
||||
->label(trans('admin/mount.source'))
|
||||
->required()
|
||||
->helperText('File path on the host system to mount to a container.')
|
||||
->helperText(trans('admin/mount.source_help'))
|
||||
->maxLength(255),
|
||||
TextInput::make('target')
|
||||
->label(trans('admin/mount.target'))
|
||||
->required()
|
||||
->helperText('Where the mount will be accessible inside a container.')
|
||||
->helperText(trans('admin/mount.target_help'))
|
||||
->maxLength(255),
|
||||
ToggleButtons::make('user_mountable')
|
||||
->hidden()
|
||||
@ -87,7 +90,8 @@ class CreateMount extends CreateRecord
|
||||
->inline()
|
||||
->required(),
|
||||
Textarea::make('description')
|
||||
->helperText('A longer description for this mount.')
|
||||
->label(trans('admin/mount.description'))
|
||||
->helperText(trans('admin/mount.description_help'))
|
||||
->columnSpanFull(),
|
||||
Hidden::make('user_mountable')->default(1),
|
||||
])->columnSpan(1)->columns([
|
||||
@ -97,9 +101,11 @@ class CreateMount extends CreateRecord
|
||||
Group::make()->schema([
|
||||
Section::make()->schema([
|
||||
Select::make('eggs')->multiple()
|
||||
->label(trans('admin/mount.eggs'))
|
||||
->relationship('eggs', 'name')
|
||||
->preload(),
|
||||
Select::make('nodes')->multiple()
|
||||
->label(trans('admin/mount.nodes'))
|
||||
->relationship('nodes', 'name')
|
||||
->searchable(['name', 'fqdn'])
|
||||
->preload(),
|
||||
|
@ -23,15 +23,16 @@ class EditMount extends EditRecord
|
||||
->schema([
|
||||
Section::make()->schema([
|
||||
TextInput::make('name')
|
||||
->label(trans('admin/mount.name'))
|
||||
->required()
|
||||
->helperText('Unique name used to separate this mount from another.')
|
||||
->helperText(trans('admin/mount.name_help'))
|
||||
->maxLength(64),
|
||||
ToggleButtons::make('read_only')
|
||||
->label('Read only?')
|
||||
->helperText('Is the mount read only inside the container?')
|
||||
->label(trans('admin/mount.read_only'))
|
||||
->helperText(trans('admin/mount.read_only_help'))
|
||||
->options([
|
||||
false => 'Writeable',
|
||||
true => 'Read only',
|
||||
false => trans('admin/mount.toggles.writable'),
|
||||
true => trans('admin/mount.toggles.read_only'),
|
||||
])
|
||||
->icons([
|
||||
false => 'tabler-writing',
|
||||
@ -45,12 +46,14 @@ class EditMount extends EditRecord
|
||||
->default(false)
|
||||
->required(),
|
||||
TextInput::make('source')
|
||||
->label(trans('admin/mount.source'))
|
||||
->required()
|
||||
->helperText('File path on the host system to mount to a container.')
|
||||
->helperText(trans('admin/mount.source_help'))
|
||||
->maxLength(255),
|
||||
TextInput::make('target')
|
||||
->label(trans('admin/mount.target'))
|
||||
->required()
|
||||
->helperText('Where the mount will be accessible inside a container.')
|
||||
->helperText(trans('admin/mount.target_help'))
|
||||
->maxLength(255),
|
||||
ToggleButtons::make('user_mountable')
|
||||
->hidden()
|
||||
@ -71,7 +74,8 @@ class EditMount extends EditRecord
|
||||
->inline()
|
||||
->required(),
|
||||
Textarea::make('description')
|
||||
->helperText('A longer description for this mount.')
|
||||
->label(trans('admin/mount.description'))
|
||||
->helperText(trans('admin/mount.description_help'))
|
||||
->columnSpanFull(),
|
||||
])->columnSpan(1)->columns([
|
||||
'default' => 1,
|
||||
|
@ -24,17 +24,16 @@ class ListMounts extends ListRecords
|
||||
->searchable(false)
|
||||
->columns([
|
||||
TextColumn::make('name')
|
||||
->label(trans('admin/mount.table.name'))
|
||||
->searchable(),
|
||||
TextColumn::make('source')
|
||||
->label(trans('admin/mount.table.source'))
|
||||
->searchable(),
|
||||
TextColumn::make('target')
|
||||
->label(trans('admin/mount.table.target'))
|
||||
->searchable(),
|
||||
IconColumn::make('read_only')
|
||||
->icon(fn (bool $state) => $state ? 'tabler-circle-check-filled' : 'tabler-circle-x-filled')
|
||||
->color(fn (bool $state) => $state ? 'success' : 'danger')
|
||||
->sortable(),
|
||||
IconColumn::make('user_mountable')
|
||||
->hidden()
|
||||
->label(trans('admin/mount.table.read_only'))
|
||||
->icon(fn (bool $state) => $state ? 'tabler-circle-check-filled' : 'tabler-circle-x-filled')
|
||||
->color(fn (bool $state) => $state ? 'success' : 'danger')
|
||||
->sortable(),
|
||||
@ -50,10 +49,10 @@ class ListMounts extends ListRecords
|
||||
])
|
||||
->emptyStateIcon('tabler-layers-linked')
|
||||
->emptyStateDescription('')
|
||||
->emptyStateHeading('No Mounts')
|
||||
->emptyStateHeading(trans('admin/mount.no_mounts'))
|
||||
->emptyStateActions([
|
||||
CreateAction::make('create')
|
||||
->label('Create Mount')
|
||||
->label(trans('admin/mount.create_action', ['action' => trans('filament-actions::create.single.modal.actions.create.label')]))
|
||||
->button(),
|
||||
]);
|
||||
}
|
||||
@ -62,7 +61,7 @@ class ListMounts extends ListRecords
|
||||
{
|
||||
return [
|
||||
Actions\CreateAction::make()
|
||||
->label('Create Mount')
|
||||
->label(trans('admin/mount.create_action', ['action' => trans('filament-actions::create.single.modal.actions.create.label')]))
|
||||
->hidden(fn () => Mount::count() <= 0),
|
||||
];
|
||||
}
|
||||
|
@ -13,10 +13,28 @@ class NodeResource extends Resource
|
||||
|
||||
protected static ?string $navigationIcon = 'tabler-server-2';
|
||||
|
||||
protected static ?string $navigationGroup = 'Server';
|
||||
|
||||
protected static ?string $recordTitleAttribute = 'name';
|
||||
|
||||
public static function getNavigationLabel(): string
|
||||
{
|
||||
return trans('admin/node.nav_title');
|
||||
}
|
||||
|
||||
public static function getModelLabel(): string
|
||||
{
|
||||
return trans('admin/node.model_label');
|
||||
}
|
||||
|
||||
public static function getPluralModelLabel(): string
|
||||
{
|
||||
return trans('admin/node.model_label_plural');
|
||||
}
|
||||
|
||||
public static function getNavigationGroup(): ?string
|
||||
{
|
||||
return trans('admin/dashboard.server');
|
||||
}
|
||||
|
||||
public static function getNavigationBadge(): ?string
|
||||
{
|
||||
return static::getModel()::count() ?: null;
|
||||
|
@ -29,7 +29,7 @@ class CreateNode extends CreateRecord
|
||||
->schema([
|
||||
Wizard::make([
|
||||
Step::make('basic')
|
||||
->label('Basic Settings')
|
||||
->label(trans('admin/node.tabs.basic_settings'))
|
||||
->icon('tabler-server')
|
||||
->columnSpanFull()
|
||||
->columns([
|
||||
@ -45,29 +45,23 @@ class CreateNode extends CreateRecord
|
||||
->autofocus()
|
||||
->live(debounce: 1500)
|
||||
->rule('prohibited', fn ($state) => is_ip($state) && request()->isSecure())
|
||||
->label(fn ($state) => is_ip($state) ? 'IP Address' : 'Domain Name')
|
||||
->label(fn ($state) => is_ip($state) ? trans('admin/node.ip_address') : trans('admin/node.domain'))
|
||||
->placeholder(fn ($state) => is_ip($state) ? '192.168.1.1' : 'node.example.com')
|
||||
->helperText(function ($state) {
|
||||
if (is_ip($state)) {
|
||||
if (request()->isSecure()) {
|
||||
return '
|
||||
Your panel is currently secured via an SSL certificate and that means your nodes require one too.
|
||||
You must use a domain name, because you cannot get SSL certificates for IP Addresses
|
||||
';
|
||||
return trans('admin/node.fqdn_help');
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
return "
|
||||
This is the domain name that points to your node's IP Address.
|
||||
If you've already set up this, you can verify it by checking the next field!
|
||||
";
|
||||
return trans('admin/node.error');
|
||||
})
|
||||
->hintColor('danger')
|
||||
->hint(function ($state) {
|
||||
if (is_ip($state) && request()->isSecure()) {
|
||||
return 'You cannot connect to an IP Address over SSL';
|
||||
return trans('admin/node.ssl_ip');
|
||||
}
|
||||
|
||||
return '';
|
||||
@ -105,16 +99,16 @@ class CreateNode extends CreateRecord
|
||||
->hidden(),
|
||||
|
||||
ToggleButtons::make('dns')
|
||||
->label('DNS Record Check')
|
||||
->helperText('This lets you know if your DNS record correctly points to an IP Address.')
|
||||
->label(trans('admin/node.dns'))
|
||||
->helperText(trans('admin/node.dns_help'))
|
||||
->disabled()
|
||||
->inline()
|
||||
->default(null)
|
||||
->hint(fn (Get $get) => $get('ip'))
|
||||
->hintColor('success')
|
||||
->options([
|
||||
true => 'Valid',
|
||||
false => 'Invalid',
|
||||
true => trans('admin/node.valid'),
|
||||
false => trans('admin/node.invalid'),
|
||||
])
|
||||
->colors([
|
||||
true => 'success',
|
||||
@ -134,8 +128,8 @@ class CreateNode extends CreateRecord
|
||||
'md' => 1,
|
||||
'lg' => 1,
|
||||
])
|
||||
->label(trans('strings.port'))
|
||||
->helperText('If you are running the daemon behind Cloudflare you should set the daemon port to 8443 to allow websocket proxying over SSL.')
|
||||
->label(trans('admin/node.port'))
|
||||
->helperText(trans('admin/node.port_help'))
|
||||
->minValue(1)
|
||||
->maxValue(65535)
|
||||
->default(8080)
|
||||
@ -143,7 +137,7 @@ class CreateNode extends CreateRecord
|
||||
->integer(),
|
||||
|
||||
TextInput::make('name')
|
||||
->label('Display Name')
|
||||
->label(trans('admin/node.display_name'))
|
||||
->columnSpan([
|
||||
'default' => 1,
|
||||
'sm' => 1,
|
||||
@ -151,11 +145,10 @@ class CreateNode extends CreateRecord
|
||||
'lg' => 2,
|
||||
])
|
||||
->required()
|
||||
->helperText('This name is for display only and can be changed later.')
|
||||
->maxLength(100),
|
||||
|
||||
ToggleButtons::make('scheme')
|
||||
->label('Communicate over SSL')
|
||||
->label(trans('admin/node.ssl'))
|
||||
->columnSpan([
|
||||
'default' => 1,
|
||||
'sm' => 1,
|
||||
@ -165,11 +158,11 @@ class CreateNode extends CreateRecord
|
||||
->inline()
|
||||
->helperText(function (Get $get) {
|
||||
if (request()->isSecure()) {
|
||||
return new HtmlString('Your Panel is using a secure SSL connection,<br>so your Daemon must too.');
|
||||
return new HtmlString(trans('admin/node.panel_on_ssl'));
|
||||
}
|
||||
|
||||
if (is_ip($get('fqdn'))) {
|
||||
return 'An IP address cannot use SSL.';
|
||||
return trans('admin/node.ssl_help');
|
||||
}
|
||||
|
||||
return '';
|
||||
@ -190,7 +183,7 @@ class CreateNode extends CreateRecord
|
||||
->default(fn () => request()->isSecure() ? 'https' : 'http'),
|
||||
]),
|
||||
Step::make('advanced')
|
||||
->label('Advanced Settings')
|
||||
->label(trans('admin/node.tabs.advanced_settings'))
|
||||
->icon('tabler-server-cog')
|
||||
->columnSpanFull()
|
||||
->columns([
|
||||
@ -201,14 +194,14 @@ class CreateNode extends CreateRecord
|
||||
])
|
||||
->schema([
|
||||
ToggleButtons::make('maintenance_mode')
|
||||
->label('Maintenance Mode')->inline()
|
||||
->label(trans('admin/node.maintenance_mode'))->inline()
|
||||
->columnSpan(1)
|
||||
->default(false)
|
||||
->hinticon('tabler-question-mark')
|
||||
->hintIconTooltip("If the node is marked 'Under Maintenance' users won't be able to access servers that are on this node.")
|
||||
->hintIconTooltip(trans('admin/node.maintenance_mode_help'))
|
||||
->options([
|
||||
true => 'Enable',
|
||||
false => 'Disable',
|
||||
true => trans('admin/node.enabled'),
|
||||
false => trans('admin/node.disabled'),
|
||||
])
|
||||
->colors([
|
||||
true => 'danger',
|
||||
@ -217,21 +210,20 @@ class CreateNode extends CreateRecord
|
||||
ToggleButtons::make('public')
|
||||
->default(true)
|
||||
->columnSpan(1)
|
||||
->label('Use Node for deployment?')->inline()
|
||||
->label(trans('admin/node.use_for_deploy'))->inline()
|
||||
->options([
|
||||
true => 'Yes',
|
||||
false => 'No',
|
||||
true => trans('admin/node.yes'),
|
||||
false => trans('admin/node.no'),
|
||||
])
|
||||
->colors([
|
||||
true => 'success',
|
||||
false => 'danger',
|
||||
]),
|
||||
TagsInput::make('tags')
|
||||
->placeholder('Add Tags')
|
||||
->label(trans('admin/node.tags'))
|
||||
->columnSpan(2),
|
||||
TextInput::make('upload_size')
|
||||
->label('Upload Limit')
|
||||
->helperText('Enter the maximum size of files that can be uploaded through the web-based file manager.')
|
||||
->label(trans('admin/node.upload_limit'))
|
||||
->columnSpan(1)
|
||||
->numeric()->required()
|
||||
->default(256)
|
||||
@ -240,7 +232,7 @@ class CreateNode extends CreateRecord
|
||||
->suffix(config('panel.use_binary_prefix') ? 'MiB' : 'MB'),
|
||||
TextInput::make('daemon_sftp')
|
||||
->columnSpan(1)
|
||||
->label('SFTP Port')
|
||||
->label(trans('admin/node.sftp_port'))
|
||||
->minValue(1)
|
||||
->maxValue(65535)
|
||||
->default(2022)
|
||||
@ -248,21 +240,21 @@ class CreateNode extends CreateRecord
|
||||
->integer(),
|
||||
TextInput::make('daemon_sftp_alias')
|
||||
->columnSpan(2)
|
||||
->label('SFTP Alias')
|
||||
->helperText('Display alias for the SFTP address. Leave empty to use the Node FQDN.'),
|
||||
->label(trans('admin/node.sftp_alias'))
|
||||
->helperText(trans('admin/node.sftp_alias_help')),
|
||||
Grid::make()
|
||||
->columns(6)
|
||||
->columnSpanFull()
|
||||
->schema([
|
||||
ToggleButtons::make('unlimited_mem')
|
||||
->label('Memory')->inlineLabel()->inline()
|
||||
->label(trans('admin/node.memory'))->inlineLabel()->inline()
|
||||
->afterStateUpdated(fn (Set $set) => $set('memory', 0))
|
||||
->afterStateUpdated(fn (Set $set) => $set('memory_overallocate', 0))
|
||||
->formatStateUsing(fn (Get $get) => $get('memory') == 0)
|
||||
->live()
|
||||
->options([
|
||||
true => 'Unlimited',
|
||||
false => 'Limited',
|
||||
true => trans('admin/node.unlimited'),
|
||||
false => trans('admin/node.limited'),
|
||||
])
|
||||
->colors([
|
||||
true => 'primary',
|
||||
@ -272,7 +264,7 @@ class CreateNode extends CreateRecord
|
||||
TextInput::make('memory')
|
||||
->dehydratedWhenHidden()
|
||||
->hidden(fn (Get $get) => $get('unlimited_mem'))
|
||||
->label('Memory Limit')->inlineLabel()
|
||||
->label(trans('admin/node.memory_limit'))->inlineLabel()
|
||||
->suffix(config('panel.use_binary_prefix') ? 'MiB' : 'MB')
|
||||
->columnSpan(2)
|
||||
->numeric()
|
||||
@ -281,10 +273,8 @@ class CreateNode extends CreateRecord
|
||||
->required(),
|
||||
TextInput::make('memory_overallocate')
|
||||
->dehydratedWhenHidden()
|
||||
->label('Overallocate')->inlineLabel()
|
||||
->label(trans('admin/node.overallocate'))->inlineLabel()
|
||||
->hidden(fn (Get $get) => $get('unlimited_mem'))
|
||||
->hintIcon('tabler-question-mark')
|
||||
->hintIconTooltip('The % allowable to go over the set limit.')
|
||||
->columnSpan(2)
|
||||
->numeric()
|
||||
->minValue(-1)
|
||||
@ -298,14 +288,14 @@ class CreateNode extends CreateRecord
|
||||
->columnSpanFull()
|
||||
->schema([
|
||||
ToggleButtons::make('unlimited_disk')
|
||||
->label('Disk')->inlineLabel()->inline()
|
||||
->label(trans('admin/node.disk'))->inlineLabel()->inline()
|
||||
->live()
|
||||
->afterStateUpdated(fn (Set $set) => $set('disk', 0))
|
||||
->afterStateUpdated(fn (Set $set) => $set('disk_overallocate', 0))
|
||||
->formatStateUsing(fn (Get $get) => $get('disk') == 0)
|
||||
->options([
|
||||
true => 'Unlimited',
|
||||
false => 'Limited',
|
||||
true => trans('admin/node.unlimited'),
|
||||
false => trans('admin/node.limited'),
|
||||
])
|
||||
->colors([
|
||||
true => 'primary',
|
||||
@ -315,7 +305,7 @@ class CreateNode extends CreateRecord
|
||||
TextInput::make('disk')
|
||||
->dehydratedWhenHidden()
|
||||
->hidden(fn (Get $get) => $get('unlimited_disk'))
|
||||
->label('Disk Limit')->inlineLabel()
|
||||
->label(trans('admin/node.disk_limit'))->inlineLabel()
|
||||
->suffix(config('panel.use_binary_prefix') ? 'MiB' : 'MB')
|
||||
->columnSpan(2)
|
||||
->numeric()
|
||||
@ -325,9 +315,7 @@ class CreateNode extends CreateRecord
|
||||
TextInput::make('disk_overallocate')
|
||||
->dehydratedWhenHidden()
|
||||
->hidden(fn (Get $get) => $get('unlimited_disk'))
|
||||
->label('Overallocate')->inlineLabel()
|
||||
->hintIcon('tabler-question-mark')
|
||||
->hintIconTooltip('The % allowable to go over the set limit.')
|
||||
->label(trans('admin/node.overallocate'))->inlineLabel()
|
||||
->columnSpan(2)
|
||||
->numeric()
|
||||
->minValue(-1)
|
||||
@ -341,14 +329,14 @@ class CreateNode extends CreateRecord
|
||||
->columnSpanFull()
|
||||
->schema([
|
||||
ToggleButtons::make('unlimited_cpu')
|
||||
->label('CPU')->inlineLabel()->inline()
|
||||
->label(trans('admin/node.cpu'))->inlineLabel()->inline()
|
||||
->live()
|
||||
->afterStateUpdated(fn (Set $set) => $set('cpu', 0))
|
||||
->afterStateUpdated(fn (Set $set) => $set('cpu_overallocate', 0))
|
||||
->formatStateUsing(fn (Get $get) => $get('cpu') == 0)
|
||||
->options([
|
||||
true => 'Unlimited',
|
||||
false => 'Limited',
|
||||
true => trans('admin/node.unlimited'),
|
||||
false => trans('admin/node.limited'),
|
||||
])
|
||||
->colors([
|
||||
true => 'primary',
|
||||
@ -358,7 +346,7 @@ class CreateNode extends CreateRecord
|
||||
TextInput::make('cpu')
|
||||
->dehydratedWhenHidden()
|
||||
->hidden(fn (Get $get) => $get('unlimited_cpu'))
|
||||
->label('CPU Limit')->inlineLabel()
|
||||
->label(trans('admin/node.cpu_limit'))->inlineLabel()
|
||||
->suffix('%')
|
||||
->columnSpan(2)
|
||||
->numeric()
|
||||
@ -368,9 +356,7 @@ class CreateNode extends CreateRecord
|
||||
TextInput::make('cpu_overallocate')
|
||||
->dehydratedWhenHidden()
|
||||
->hidden(fn (Get $get) => $get('unlimited_cpu'))
|
||||
->label('Overallocate')->inlineLabel()
|
||||
->hintIcon('tabler-question-mark')
|
||||
->hintIconTooltip('The % allowable to go over the set limit.')
|
||||
->label(trans('admin/node.overallocate'))->inlineLabel()
|
||||
->columnSpan(2)
|
||||
->numeric()
|
||||
->default(0)
|
||||
@ -381,7 +367,7 @@ class CreateNode extends CreateRecord
|
||||
]),
|
||||
]),
|
||||
])->columnSpanFull()
|
||||
->nextAction(fn (Action $action) => $action->label('Next Step'))
|
||||
->nextAction(fn (Action $action) => $action->label(trans('admin/node.next_step')))
|
||||
->submitAction(new HtmlString(Blade::render(<<<'BLADE'
|
||||
<x-filament::button
|
||||
type="submit"
|
||||
|
@ -57,7 +57,7 @@ class EditNode extends EditRecord
|
||||
->columnSpanFull()
|
||||
->tabs([
|
||||
Tab::make('')
|
||||
->label('Overview')
|
||||
->label(trans('admin/node.tabs.overview'))
|
||||
->icon('tabler-chart-area-line-filled')
|
||||
->columns([
|
||||
'default' => 4,
|
||||
@ -67,21 +67,21 @@ class EditNode extends EditRecord
|
||||
])
|
||||
->schema([
|
||||
Fieldset::make()
|
||||
->label('Node Information')
|
||||
->label(trans('admin/node.node_info'))
|
||||
->columns(4)
|
||||
->schema([
|
||||
Placeholder::make('')
|
||||
->label('Wings Version')
|
||||
->content(fn (Node $node, SoftwareVersionService $versionService) => ($node->systemInformation()['version'] ?? 'Unknown') . ' (Latest: ' . $versionService->latestWingsVersion() . ')'),
|
||||
->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() . ')'),
|
||||
Placeholder::make('')
|
||||
->label('CPU Threads')
|
||||
->label(trans('admin/node.cpu_threads'))
|
||||
->content(fn (Node $node) => $node->systemInformation()['cpu_count'] ?? 0),
|
||||
Placeholder::make('')
|
||||
->label('Architecture')
|
||||
->content(fn (Node $node) => $node->systemInformation()['architecture'] ?? 'Unknown'),
|
||||
->label(trans('admin/node.architecture'))
|
||||
->content(fn (Node $node) => $node->systemInformation()['architecture'] ?? trans('admin/node.unknown')),
|
||||
Placeholder::make('')
|
||||
->label('Kernel')
|
||||
->content(fn (Node $node) => $node->systemInformation()['kernel_version'] ?? 'Unknown'),
|
||||
->label(trans('admin/node.kernel'))
|
||||
->content(fn (Node $node) => $node->systemInformation()['kernel_version'] ?? trans('admin/node.unknown')),
|
||||
]),
|
||||
View::make('filament.components.node-cpu-chart')
|
||||
->columnSpan([
|
||||
@ -100,7 +100,7 @@ class EditNode extends EditRecord
|
||||
View::make('filament.components.node-storage-chart')
|
||||
->columnSpanFull(),
|
||||
]),
|
||||
Tab::make('Basic Settings')
|
||||
Tab::make(trans('admin/node.tabs.basic_settings'))
|
||||
->icon('tabler-server')
|
||||
->schema([
|
||||
TextInput::make('fqdn')
|
||||
@ -109,29 +109,23 @@ class EditNode extends EditRecord
|
||||
->autofocus()
|
||||
->live(debounce: 1500)
|
||||
->rule('prohibited', fn ($state) => is_ip($state) && request()->isSecure())
|
||||
->label(fn ($state) => is_ip($state) ? 'IP Address' : 'Domain Name')
|
||||
->label(fn ($state) => is_ip($state) ? trans('admin/node.ip_address') : trans('admin/node.domain'))
|
||||
->placeholder(fn ($state) => is_ip($state) ? '192.168.1.1' : 'node.example.com')
|
||||
->helperText(function ($state) {
|
||||
if (is_ip($state)) {
|
||||
if (request()->isSecure()) {
|
||||
return '
|
||||
Your panel is currently secured via an SSL certificate and that means your nodes require one too.
|
||||
You must use a domain name, because you cannot get SSL certificates for IP Addresses.
|
||||
';
|
||||
return trans('admin/node.fqdn_help');
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
return "
|
||||
This is the domain name that points to your node's IP Address.
|
||||
If you've already set up this, you can verify it by checking the next field!
|
||||
";
|
||||
return trans('admin/node.error');
|
||||
})
|
||||
->hintColor('danger')
|
||||
->hint(function ($state) {
|
||||
if (is_ip($state) && request()->isSecure()) {
|
||||
return 'You cannot connect to an IP Address over SSL!';
|
||||
return trans('admin/node.ssl_ip');
|
||||
}
|
||||
|
||||
return '';
|
||||
@ -167,16 +161,16 @@ class EditNode extends EditRecord
|
||||
->disabled()
|
||||
->hidden(),
|
||||
ToggleButtons::make('dns')
|
||||
->label('DNS Record Check')
|
||||
->helperText('This lets you know if your DNS record correctly points to an IP Address.')
|
||||
->label(trans('admin/node.dns'))
|
||||
->helperText(trans('admin/node.dns_help'))
|
||||
->disabled()
|
||||
->inline()
|
||||
->default(null)
|
||||
->hint(fn (Get $get) => $get('ip'))
|
||||
->hintColor('success')
|
||||
->options([
|
||||
true => 'Valid',
|
||||
false => 'Invalid',
|
||||
true => trans('admin/node.valid'),
|
||||
false => trans('admin/node.invalid'),
|
||||
])
|
||||
->colors([
|
||||
true => 'success',
|
||||
@ -185,15 +179,15 @@ class EditNode extends EditRecord
|
||||
->columnSpan(1),
|
||||
TextInput::make('daemon_listen')
|
||||
->columnSpan(1)
|
||||
->label(trans('strings.port'))
|
||||
->helperText('If you are running the daemon behind Cloudflare you should set the daemon port to 8443 to allow websocket proxying over SSL.')
|
||||
->label(trans('admin/node.port'))
|
||||
->helperText(trans('admin/node.port_help'))
|
||||
->minValue(1)
|
||||
->maxValue(65535)
|
||||
->default(8080)
|
||||
->required()
|
||||
->integer(),
|
||||
TextInput::make('name')
|
||||
->label('Display Name')
|
||||
->label(trans('admin/node.display_name'))
|
||||
->columnSpan([
|
||||
'default' => 1,
|
||||
'sm' => 1,
|
||||
@ -201,19 +195,18 @@ class EditNode extends EditRecord
|
||||
'lg' => 2,
|
||||
])
|
||||
->required()
|
||||
->helperText('This name is for display only and can be changed later.')
|
||||
->maxLength(100),
|
||||
ToggleButtons::make('scheme')
|
||||
->label('Communicate over SSL')
|
||||
->label(trans('admin/node.ssl'))
|
||||
->columnSpan(1)
|
||||
->inline()
|
||||
->helperText(function (Get $get) {
|
||||
if (request()->isSecure()) {
|
||||
return new HtmlString('Your Panel is using a secure SSL connection,<br>so your Daemon must too.');
|
||||
return new HtmlString(trans('admin/node.panel_on_ssl'));
|
||||
}
|
||||
|
||||
if (is_ip($get('fqdn'))) {
|
||||
return 'An IP address cannot use SSL.';
|
||||
return trans('admin/node.ssl_help');
|
||||
}
|
||||
|
||||
return '';
|
||||
@ -232,7 +225,8 @@ class EditNode extends EditRecord
|
||||
'https' => 'tabler-lock',
|
||||
])
|
||||
->default(fn () => request()->isSecure() ? 'https' : 'http'), ]),
|
||||
Tab::make('Advanced Settings')
|
||||
Tab::make('adv')
|
||||
->label(trans('admin/node.tabs.advanced_settings'))
|
||||
->columns([
|
||||
'default' => 1,
|
||||
'sm' => 1,
|
||||
@ -242,7 +236,7 @@ class EditNode extends EditRecord
|
||||
->icon('tabler-server-cog')
|
||||
->schema([
|
||||
TextInput::make('id')
|
||||
->label('Node ID')
|
||||
->label(trans('admin/node.node_id'))
|
||||
->columnSpan([
|
||||
'default' => 1,
|
||||
'sm' => 1,
|
||||
@ -257,17 +251,18 @@ class EditNode extends EditRecord
|
||||
'md' => 2,
|
||||
'lg' => 2,
|
||||
])
|
||||
->label('Node UUID')
|
||||
->label(trans('admin/node.node_uuid'))
|
||||
->hintAction(fn () => request()->isSecure() ? CopyAction::make() : null)
|
||||
->disabled(),
|
||||
TagsInput::make('tags')
|
||||
->label(trans('admin/node.tags'))
|
||||
->placeholder('')
|
||||
->columnSpan([
|
||||
'default' => 1,
|
||||
'sm' => 1,
|
||||
'md' => 2,
|
||||
'lg' => 2,
|
||||
])
|
||||
->placeholder('Add Tags'),
|
||||
]),
|
||||
TextInput::make('upload_size')
|
||||
->columnSpan([
|
||||
'default' => 1,
|
||||
@ -275,9 +270,7 @@ class EditNode extends EditRecord
|
||||
'md' => 2,
|
||||
'lg' => 1,
|
||||
])
|
||||
->label('Upload Limit')
|
||||
->hintIcon('tabler-question-mark')
|
||||
->hintIconTooltip('Enter the maximum size of files that can be uploaded through the web-based file manager.')
|
||||
->label(trans('admin/node.upload_limit'))
|
||||
->numeric()->required()
|
||||
->minValue(1)
|
||||
->maxValue(1024)
|
||||
@ -289,7 +282,7 @@ class EditNode extends EditRecord
|
||||
'md' => 1,
|
||||
'lg' => 3,
|
||||
])
|
||||
->label('SFTP Port')
|
||||
->label(trans('admin/node.sftp_port'))
|
||||
->minValue(1)
|
||||
->maxValue(65535)
|
||||
->default(2022)
|
||||
@ -302,8 +295,8 @@ class EditNode extends EditRecord
|
||||
'md' => 1,
|
||||
'lg' => 3,
|
||||
])
|
||||
->label('SFTP Alias')
|
||||
->helperText('Display alias for the SFTP address. Leave empty to use the Node FQDN.'),
|
||||
->label(trans('admin/node.sftp_alias'))
|
||||
->helperText(trans('admin/node.sftp_alias_help')),
|
||||
ToggleButtons::make('public')
|
||||
->columnSpan([
|
||||
'default' => 1,
|
||||
@ -311,10 +304,10 @@ class EditNode extends EditRecord
|
||||
'md' => 1,
|
||||
'lg' => 3,
|
||||
])
|
||||
->label('Use Node for deployment?')->inline()
|
||||
->label(trans('admin/node.use_for_deploy'))->inline()
|
||||
->options([
|
||||
true => 'Yes',
|
||||
false => 'No',
|
||||
true => trans('admin/node.yes'),
|
||||
false => trans('admin/node.no'),
|
||||
])
|
||||
->colors([
|
||||
true => 'success',
|
||||
@ -327,12 +320,12 @@ class EditNode extends EditRecord
|
||||
'md' => 1,
|
||||
'lg' => 3,
|
||||
])
|
||||
->label('Maintenance Mode')->inline()
|
||||
->label(trans('admin/node.maintenance_mode'))->inline()
|
||||
->hinticon('tabler-question-mark')
|
||||
->hintIconTooltip("If the node is marked 'Under Maintenance' users won't be able to access servers that are on this node.")
|
||||
->hintIconTooltip(trans('admin/node.maintenance_mode_help'))
|
||||
->options([
|
||||
false => 'Disable',
|
||||
true => 'Enable',
|
||||
true => trans('admin/node.enabled'),
|
||||
false => trans('admin/node.disabled'),
|
||||
])
|
||||
->colors([
|
||||
false => 'success',
|
||||
@ -348,14 +341,14 @@ class EditNode extends EditRecord
|
||||
->columnSpanFull()
|
||||
->schema([
|
||||
ToggleButtons::make('unlimited_mem')
|
||||
->label('Memory')->inlineLabel()->inline()
|
||||
->label(trans('admin/node.memory'))->inlineLabel()->inline()
|
||||
->afterStateUpdated(fn (Set $set) => $set('memory', 0))
|
||||
->afterStateUpdated(fn (Set $set) => $set('memory_overallocate', 0))
|
||||
->formatStateUsing(fn (Get $get) => $get('memory') == 0)
|
||||
->live()
|
||||
->options([
|
||||
true => 'Unlimited',
|
||||
false => 'Limited',
|
||||
true => trans('admin/node.unlimited'),
|
||||
false => trans('admin/node.limited'),
|
||||
])
|
||||
->colors([
|
||||
true => 'primary',
|
||||
@ -370,7 +363,7 @@ class EditNode extends EditRecord
|
||||
TextInput::make('memory')
|
||||
->dehydratedWhenHidden()
|
||||
->hidden(fn (Get $get) => $get('unlimited_mem'))
|
||||
->label('Memory Limit')->inlineLabel()
|
||||
->label(trans('admin/node.memory_limit'))->inlineLabel()
|
||||
->suffix(config('panel.use_binary_prefix') ? 'MiB' : 'MB')
|
||||
->required()
|
||||
->columnSpan([
|
||||
@ -383,11 +376,9 @@ class EditNode extends EditRecord
|
||||
->minValue(0),
|
||||
TextInput::make('memory_overallocate')
|
||||
->dehydratedWhenHidden()
|
||||
->label('Overallocate')->inlineLabel()
|
||||
->label(trans('admin/node.overallocate'))->inlineLabel()
|
||||
->required()
|
||||
->hidden(fn (Get $get) => $get('unlimited_mem'))
|
||||
->hintIcon('tabler-question-mark')
|
||||
->hintIconTooltip('The % allowable to go over the set limit.')
|
||||
->columnSpan([
|
||||
'default' => 1,
|
||||
'sm' => 1,
|
||||
@ -408,14 +399,14 @@ class EditNode extends EditRecord
|
||||
])
|
||||
->schema([
|
||||
ToggleButtons::make('unlimited_disk')
|
||||
->label('Disk')->inlineLabel()->inline()
|
||||
->label(trans('admin/node.disk'))->inlineLabel()->inline()
|
||||
->live()
|
||||
->afterStateUpdated(fn (Set $set) => $set('disk', 0))
|
||||
->afterStateUpdated(fn (Set $set) => $set('disk_overallocate', 0))
|
||||
->formatStateUsing(fn (Get $get) => $get('disk') == 0)
|
||||
->options([
|
||||
true => 'Unlimited',
|
||||
false => 'Limited',
|
||||
true => trans('admin/node.unlimited'),
|
||||
false => trans('admin/node.limited'),
|
||||
])
|
||||
->colors([
|
||||
true => 'primary',
|
||||
@ -430,7 +421,7 @@ class EditNode extends EditRecord
|
||||
TextInput::make('disk')
|
||||
->dehydratedWhenHidden()
|
||||
->hidden(fn (Get $get) => $get('unlimited_disk'))
|
||||
->label('Disk Limit')->inlineLabel()
|
||||
->label(trans('admin/node.disk_limit'))->inlineLabel()
|
||||
->suffix(config('panel.use_binary_prefix') ? 'MiB' : 'MB')
|
||||
->required()
|
||||
->columnSpan([
|
||||
@ -444,9 +435,7 @@ class EditNode extends EditRecord
|
||||
TextInput::make('disk_overallocate')
|
||||
->dehydratedWhenHidden()
|
||||
->hidden(fn (Get $get) => $get('unlimited_disk'))
|
||||
->label('Overallocate')->inlineLabel()
|
||||
->hintIcon('tabler-question-mark')
|
||||
->hintIconTooltip('The % allowable to go over the set limit.')
|
||||
->label(trans('admin/node.overallocate'))->inlineLabel()
|
||||
->columnSpan([
|
||||
'default' => 1,
|
||||
'sm' => 1,
|
||||
@ -464,14 +453,14 @@ class EditNode extends EditRecord
|
||||
->columnSpanFull()
|
||||
->schema([
|
||||
ToggleButtons::make('unlimited_cpu')
|
||||
->label('CPU')->inlineLabel()->inline()
|
||||
->label(trans('admin/node.cpu'))->inlineLabel()->inline()
|
||||
->live()
|
||||
->afterStateUpdated(fn (Set $set) => $set('cpu', 0))
|
||||
->afterStateUpdated(fn (Set $set) => $set('cpu_overallocate', 0))
|
||||
->formatStateUsing(fn (Get $get) => $get('cpu') == 0)
|
||||
->options([
|
||||
true => 'Unlimited',
|
||||
false => 'Limited',
|
||||
true => trans('admin/node.unlimited'),
|
||||
false => trans('admin/node.limited'),
|
||||
])
|
||||
->colors([
|
||||
true => 'primary',
|
||||
@ -481,7 +470,7 @@ class EditNode extends EditRecord
|
||||
TextInput::make('cpu')
|
||||
->dehydratedWhenHidden()
|
||||
->hidden(fn (Get $get) => $get('unlimited_cpu'))
|
||||
->label('CPU Limit')->inlineLabel()
|
||||
->label(trans('admin/node.cpu_limit'))->inlineLabel()
|
||||
->suffix('%')
|
||||
->required()
|
||||
->columnSpan(2)
|
||||
@ -490,9 +479,7 @@ class EditNode extends EditRecord
|
||||
TextInput::make('cpu_overallocate')
|
||||
->dehydratedWhenHidden()
|
||||
->hidden(fn (Get $get) => $get('unlimited_cpu'))
|
||||
->label('Overallocate')->inlineLabel()
|
||||
->hintIcon('tabler-question-mark')
|
||||
->hintIconTooltip('The % allowable to go over the set limit.')
|
||||
->label(trans('admin/node.overallocate'))->inlineLabel()
|
||||
->columnSpan(2)
|
||||
->required()
|
||||
->numeric()
|
||||
@ -501,14 +488,14 @@ class EditNode extends EditRecord
|
||||
->suffix('%'),
|
||||
]),
|
||||
]),
|
||||
Tab::make('Configuration File')
|
||||
Tab::make('Config')
|
||||
->label(trans('admin/node.tabs.config_file'))
|
||||
->icon('tabler-code')
|
||||
->schema([
|
||||
Placeholder::make('instructions')
|
||||
->label(trans('admin/node.instructions'))
|
||||
->columnSpanFull()
|
||||
->content(new HtmlString('
|
||||
Save this file to your <span title="usually /etc/pelican/">daemon\'s root directory</span>, named <code>config.yml</code>
|
||||
')),
|
||||
->content(new HtmlString(trans('admin/node.instructions_help'))),
|
||||
Textarea::make('config')
|
||||
->label('/etc/pelican/config.yml')
|
||||
->disabled()
|
||||
@ -520,9 +507,9 @@ class EditNode extends EditRecord
|
||||
->schema([
|
||||
FormActions::make([
|
||||
FormActions\Action::make('autoDeploy')
|
||||
->label('Auto Deploy Command')
|
||||
->label(trans('admin/node.auto_deploy'))
|
||||
->color('primary')
|
||||
->modalHeading('Auto Deploy Command')
|
||||
->modalHeading(trans('admin/node.auto_deploy'))
|
||||
->icon('tabler-rocket')
|
||||
->modalSubmitAction(false)
|
||||
->modalCancelAction(false)
|
||||
@ -531,13 +518,13 @@ class EditNode extends EditRecord
|
||||
ToggleButtons::make('docker')
|
||||
->label('Type')
|
||||
->live()
|
||||
->helperText('Choose between Standalone and Docker install.')
|
||||
->helperText(trans('admin/node.auto_question'))
|
||||
->inline()
|
||||
->default(false)
|
||||
->afterStateUpdated(fn (bool $state, NodeAutoDeployService $service, Node $node, Set $set) => $set('generatedToken', $service->handle(request(), $node, $state)))
|
||||
->options([
|
||||
false => 'Standalone',
|
||||
true => 'Docker',
|
||||
false => trans('admin/node.standalone'),
|
||||
true => trans('admin/node.docker'),
|
||||
])
|
||||
->colors([
|
||||
false => 'primary',
|
||||
@ -545,27 +532,26 @@ class EditNode extends EditRecord
|
||||
])
|
||||
->columnSpan(1),
|
||||
Textarea::make('generatedToken')
|
||||
->label('To auto-configure your node run the following command:')
|
||||
->label(trans('admin/node.auto_command'))
|
||||
->readOnly()
|
||||
->autosize()
|
||||
->hintAction(fn (string $state) => request()->isSecure() ? CopyAction::make()->copyable($state) : null)
|
||||
->formatStateUsing(fn (NodeAutoDeployService $service, Node $node, Set $set, Get $get) => $set('generatedToken', $service->handle(request(), $node, $get('docker')))),
|
||||
])
|
||||
->mountUsing(function (Forms\Form $form) {
|
||||
Notification::make()->success()->title('Autodeploy Generated')->send();
|
||||
$form->fill();
|
||||
}),
|
||||
])->fullWidth(),
|
||||
FormActions::make([
|
||||
FormActions\Action::make('resetKey')
|
||||
->label('Reset Daemon Token')
|
||||
->label(trans('admin/node.reset_token'))
|
||||
->color('danger')
|
||||
->requiresConfirmation()
|
||||
->modalHeading('Reset Daemon Token?')
|
||||
->modalDescription('Resetting the daemon token will void any request coming from the old token. This token is used for all sensitive operations on the daemon including server creation and deletion. We suggest changing this token regularly for security.')
|
||||
->modalHeading(trans('admin/node.reset_token'))
|
||||
->modalDescription(trans('admin/node.reset_help'))
|
||||
->action(function (Node $node) {
|
||||
$this->nodeUpdateService->handle($node, [], true);
|
||||
Notification::make()->success()->title('Daemon Key Reset')->send();
|
||||
Notification::make()->success()->title(trans('admin/node.token_reset'))->send();
|
||||
$this->fillForm();
|
||||
}),
|
||||
])->fullWidth(),
|
||||
@ -610,8 +596,8 @@ class EditNode extends EditRecord
|
||||
$this->errored = true;
|
||||
|
||||
Notification::make()
|
||||
->title('Error connecting to the node')
|
||||
->body('The configuration could not be automatically updated on Wings, you will need to manually update the configuration file.')
|
||||
->title(trans('admin/node.error_connecting'))
|
||||
->body(trans('admin/node.error_connecting_description'))
|
||||
->color('warning')
|
||||
->icon('tabler-database')
|
||||
->warning()
|
||||
@ -640,7 +626,7 @@ class EditNode extends EditRecord
|
||||
return [
|
||||
Actions\DeleteAction::make()
|
||||
->disabled(fn (Node $node) => $node->servers()->count() > 0)
|
||||
->label(fn (Node $node) => $node->servers()->count() > 0 ? 'Node Has Servers' : trans('filament-actions::delete.single.label')),
|
||||
->label(fn (Node $node) => $node->servers()->count() > 0 ? trans('admin/node.node_has_servers') : trans('filament-actions::delete.single.label')),
|
||||
$this->getSaveFormAction()->formId('form'),
|
||||
];
|
||||
}
|
||||
|
@ -27,14 +27,15 @@ class ListNodes extends ListRecords
|
||||
->label('UUID')
|
||||
->searchable()
|
||||
->hidden(),
|
||||
NodeHealthColumn::make('health'),
|
||||
NodeHealthColumn::make('health')->label(trans('admin/node.table.health')),
|
||||
TextColumn::make('name')
|
||||
->label(trans('admin/node.table.name'))
|
||||
->icon('tabler-server-2')
|
||||
->sortable()
|
||||
->searchable(),
|
||||
TextColumn::make('fqdn')
|
||||
->visibleFrom('md')
|
||||
->label('Address')
|
||||
->label(trans('admin/node.table.address'))
|
||||
->icon('tabler-network')
|
||||
->sortable()
|
||||
->searchable(),
|
||||
@ -45,13 +46,14 @@ class ListNodes extends ListRecords
|
||||
->falseIcon('tabler-lock-open-off')
|
||||
->state(fn (Node $node) => $node->scheme === 'https'),
|
||||
IconColumn::make('public')
|
||||
->label(trans('admin/node.table.public'))
|
||||
->visibleFrom('lg')
|
||||
->trueIcon('tabler-eye-check')
|
||||
->falseIcon('tabler-eye-cancel'),
|
||||
TextColumn::make('servers_count')
|
||||
->visibleFrom('sm')
|
||||
->counts('servers')
|
||||
->label('Servers')
|
||||
->label(trans('admin/node.table.servers'))
|
||||
->sortable()
|
||||
->icon('tabler-brand-docker'),
|
||||
])
|
||||
@ -60,10 +62,10 @@ class ListNodes extends ListRecords
|
||||
])
|
||||
->emptyStateIcon('tabler-server-2')
|
||||
->emptyStateDescription('')
|
||||
->emptyStateHeading('No Nodes')
|
||||
->emptyStateHeading(trans('admin/node.no_nodes'))
|
||||
->emptyStateActions([
|
||||
CreateAction::make('create')
|
||||
->label('Create Node')
|
||||
->label(trans('admin/node.create_action', ['action' => trans('filament-actions::create.single.modal.actions.create.label')]))
|
||||
->button(),
|
||||
]);
|
||||
}
|
||||
@ -72,7 +74,7 @@ class ListNodes extends ListRecords
|
||||
{
|
||||
return [
|
||||
Actions\CreateAction::make()
|
||||
->label('Create Node')
|
||||
->label(trans('admin/node.create_action', ['action' => trans('filament-actions::create.single.modal.actions.create.label')]))
|
||||
->hidden(fn () => Node::count() <= 0),
|
||||
];
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ use App\Services\Allocations\AssignmentService;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Components\TagsInput;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Forms\Get;
|
||||
use Filament\Forms\Set;
|
||||
use Filament\Resources\RelationManagers\RelationManager;
|
||||
@ -20,7 +19,6 @@ use Filament\Tables\Columns\SelectColumn;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Columns\TextInputColumn;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Support\HtmlString;
|
||||
|
||||
/**
|
||||
* @method Node getOwnerRecord()
|
||||
@ -31,14 +29,10 @@ class AllocationsRelationManager extends RelationManager
|
||||
|
||||
protected static ?string $icon = 'tabler-plug-connected';
|
||||
|
||||
public function form(Form $form): Form
|
||||
public function setTitle(): string
|
||||
{
|
||||
return $form
|
||||
->schema([
|
||||
TextInput::make('ip')
|
||||
->required()
|
||||
->maxLength(255),
|
||||
]);
|
||||
return trans('admin/server.allocations');
|
||||
|
||||
}
|
||||
|
||||
public function table(Table $table): Table
|
||||
@ -51,8 +45,9 @@ class AllocationsRelationManager extends RelationManager
|
||||
|
||||
// All assigned allocations
|
||||
->checkIfRecordIsSelectableUsing(fn (Allocation $allocation) => $allocation->server_id === null)
|
||||
->paginationPageOptions(['10', '20', '50', '100', '200', '500', '1000'])
|
||||
->paginationPageOptions(['10', '20', '50', '100', '200', '500'])
|
||||
->searchable()
|
||||
->heading('')
|
||||
->selectCurrentPageOnly() //Prevent people from trying to nuke 30,000 ports at once.... -,-
|
||||
->columns([
|
||||
TextColumn::make('id')
|
||||
@ -60,48 +55,44 @@ class AllocationsRelationManager extends RelationManager
|
||||
->toggledHiddenByDefault(),
|
||||
TextColumn::make('port')
|
||||
->searchable()
|
||||
->label('Port'),
|
||||
->label(trans('admin/node.table.servers')),
|
||||
TextColumn::make('server.name')
|
||||
->label('Server')
|
||||
->label(trans('admin/node.table.servers'))
|
||||
->icon('tabler-brand-docker')
|
||||
->visibleFrom('md')
|
||||
->searchable()
|
||||
->url(fn (Allocation $allocation): string => $allocation->server ? route('filament.admin.resources.servers.edit', ['record' => $allocation->server]) : ''),
|
||||
TextInputColumn::make('ip_alias')
|
||||
->searchable()
|
||||
->label('Alias'),
|
||||
->label(trans('admin/node.table.alias')),
|
||||
SelectColumn::make('ip')
|
||||
->options(fn (Allocation $allocation) => collect($this->getOwnerRecord()->ipAddresses())->merge([$allocation->ip])->mapWithKeys(fn (string $ip) => [$ip => $ip]))
|
||||
->selectablePlaceholder(false)
|
||||
->searchable()
|
||||
->label('IP'),
|
||||
->label(trans('admin/node.table.ip')),
|
||||
])
|
||||
->headerActions([
|
||||
Tables\Actions\Action::make('create new allocation')->label('Create Allocations')
|
||||
Tables\Actions\Action::make('create new allocation')
|
||||
->label(trans('admin/node.create_allocations'))
|
||||
->form(fn () => [
|
||||
Select::make('allocation_ip')
|
||||
->options(collect($this->getOwnerRecord()->ipAddresses())->mapWithKeys(fn (string $ip) => [$ip => $ip]))
|
||||
->label('IP Address')
|
||||
->label(trans('admin/node.ip_address'))
|
||||
->inlineLabel()
|
||||
->ipv4()
|
||||
->helperText("Usually your machine's public IP unless you are port forwarding.")
|
||||
->helperText(trans('admin/node.ip_help'))
|
||||
->afterStateUpdated(fn (Set $set) => $set('allocation_ports', []))
|
||||
->live()
|
||||
->required(),
|
||||
TextInput::make('allocation_alias')
|
||||
->label('Alias')
|
||||
->label(trans('admin/node.table.alias'))
|
||||
->inlineLabel()
|
||||
->default(null)
|
||||
->helperText('Optional display name to help you remember what these are.')
|
||||
->helperText(trans('admin/node.alias_help'))
|
||||
->required(false),
|
||||
TagsInput::make('allocation_ports')
|
||||
->placeholder('Examples: 27015, 27017-27019')
|
||||
->helperText(new HtmlString('
|
||||
These are the ports that users can connect to this Server through.
|
||||
<br />
|
||||
You would have to port forward these on your home network.
|
||||
'))
|
||||
->label('Ports')
|
||||
->placeholder('27015, 27017-27019')
|
||||
->label(trans('admin/node.ports'))
|
||||
->inlineLabel()
|
||||
->live()
|
||||
->disabled(fn (Get $get) => empty($get('allocation_ip')))
|
||||
|
@ -14,41 +14,49 @@ class NodesRelationManager extends RelationManager
|
||||
|
||||
protected static ?string $icon = 'tabler-brand-docker';
|
||||
|
||||
public function setTitle(): string
|
||||
{
|
||||
return trans('admin/node.table.servers');
|
||||
}
|
||||
|
||||
public function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->searchable(false)
|
||||
->heading('')
|
||||
->columns([
|
||||
TextColumn::make('user.username')
|
||||
->label('Owner')
|
||||
->label(trans('admin/node.table.owner'))
|
||||
->icon('tabler-user')
|
||||
->url(fn (Server $server): string => route('filament.admin.resources.users.edit', ['record' => $server->user]))
|
||||
->searchable(),
|
||||
TextColumn::make('name')
|
||||
->label(trans('admin/node.table.name'))
|
||||
->icon('tabler-brand-docker')
|
||||
->url(fn (Server $server): string => route('filament.admin.resources.servers.edit', ['record' => $server]))
|
||||
->searchable()
|
||||
->sortable(),
|
||||
TextColumn::make('egg.name')
|
||||
->label(trans('admin/node.table.egg'))
|
||||
->icon('tabler-egg')
|
||||
->url(fn (Server $server): string => route('filament.admin.resources.eggs.edit', ['record' => $server->user]))
|
||||
->sortable(),
|
||||
SelectColumn::make('allocation.id')
|
||||
->label('Primary Allocation')
|
||||
->label(trans('admin/node.primary_allocation'))
|
||||
->options(fn (Server $server) => [$server->allocation->id => $server->allocation->address])
|
||||
->selectablePlaceholder(false)
|
||||
->sortable(),
|
||||
TextColumn::make('memory')->icon('tabler-device-desktop-analytics'),
|
||||
TextColumn::make('cpu')->icon('tabler-cpu'),
|
||||
TextColumn::make('memory')->label(trans('admin/node.memory'))->icon('tabler-device-desktop-analytics'),
|
||||
TextColumn::make('cpu')->label(trans('admin/node.cpu'))->icon('tabler-cpu'),
|
||||
TextColumn::make('databases_count')
|
||||
->counts('databases')
|
||||
->label('Databases')
|
||||
->label(trans('admin/node.databases'))
|
||||
->icon('tabler-database')
|
||||
->numeric()
|
||||
->sortable(),
|
||||
TextColumn::make('backups_count')
|
||||
->counts('backups')
|
||||
->label('Backups')
|
||||
->label(trans('admin/node.backups'))
|
||||
->icon('tabler-file-download')
|
||||
->numeric()
|
||||
->sortable(),
|
||||
|
@ -72,8 +72,8 @@ class NodeCpuChart extends ChartWidget
|
||||
$threads = $this->node->systemInformation()['cpu_count'] ?? 0;
|
||||
|
||||
$cpu = Number::format(collect(cache()->get("nodes.{$this->node->id}.cpu_percent"))->last() * $threads, maxPrecision: 2, locale: auth()->user()->language);
|
||||
$max = Number::format($threads * 100, locale: auth()->user()->language) . '%';
|
||||
$max = Number::format($threads * 100, locale: auth()->user()->language);
|
||||
|
||||
return 'CPU - ' . $cpu . '% Of ' . $max;
|
||||
return trans('admin/node.cpu_chart', ['cpu' => $cpu, 'max' => $max]);
|
||||
}
|
||||
}
|
||||
|
@ -77,6 +77,6 @@ class NodeMemoryChart extends ChartWidget
|
||||
? Number::format($totalMemory / 1024 / 1024 / 1024, maxPrecision: 2, locale: auth()->user()->language) .' GiB'
|
||||
: Number::format($totalMemory / 1000 / 1000 / 1000, maxPrecision: 2, locale: auth()->user()->language) . ' GB';
|
||||
|
||||
return 'Memory - ' . $used . ' Of ' . $total;
|
||||
return trans('admin/node.memory_chart', ['used' => $used, 'total' => $total]);
|
||||
}
|
||||
}
|
||||
|
@ -8,8 +8,6 @@ use Illuminate\Support\Number;
|
||||
|
||||
class NodeStorageChart extends ChartWidget
|
||||
{
|
||||
protected static ?string $heading = 'Storage';
|
||||
|
||||
protected static ?string $pollingInterval = '360s';
|
||||
|
||||
protected static ?string $maxHeight = '200px';
|
||||
@ -62,7 +60,7 @@ class NodeStorageChart extends ChartWidget
|
||||
],
|
||||
],
|
||||
],
|
||||
'labels' => ['Used', 'Unused'],
|
||||
'labels' => [trans('admin/node.used'), trans('admin/node.unused')],
|
||||
'locale' => auth()->user()->language ?? 'en',
|
||||
];
|
||||
}
|
||||
@ -74,6 +72,9 @@ class NodeStorageChart extends ChartWidget
|
||||
|
||||
public function getHeading(): string
|
||||
{
|
||||
return 'Storage - ' . convert_bytes_to_readable($this->node->statistics()['disk_used'] ?? 0) . ' Of ' . convert_bytes_to_readable($this->node->statistics()['disk_total'] ?? 0);
|
||||
$used = convert_bytes_to_readable($this->node->statistics()['disk_used'] ?? 0);
|
||||
$total = convert_bytes_to_readable($this->node->statistics()['disk_total'] ?? 0);
|
||||
|
||||
return trans('admin/node.disk_chart', ['used' => $used, 'total' => $total]);
|
||||
}
|
||||
}
|
||||
|
@ -24,10 +24,28 @@ class RoleResource extends Resource
|
||||
|
||||
protected static ?string $navigationIcon = 'tabler-users-group';
|
||||
|
||||
protected static ?string $navigationGroup = 'User';
|
||||
|
||||
protected static ?string $recordTitleAttribute = 'name';
|
||||
|
||||
public static function getNavigationLabel(): string
|
||||
{
|
||||
return trans('admin/role.nav_title');
|
||||
}
|
||||
|
||||
public static function getModelLabel(): string
|
||||
{
|
||||
return trans('admin/role.model_label');
|
||||
}
|
||||
|
||||
public static function getPluralModelLabel(): string
|
||||
{
|
||||
return trans('admin/role.model_label_plural');
|
||||
}
|
||||
|
||||
public static function getNavigationGroup(): ?string
|
||||
{
|
||||
return trans('admin/dashboard.user');
|
||||
}
|
||||
|
||||
public static function getNavigationBadge(): ?string
|
||||
{
|
||||
return static::getModel()::count() ?: null;
|
||||
@ -67,7 +85,7 @@ class RoleResource extends Resource
|
||||
->columns(1)
|
||||
->schema([
|
||||
TextInput::make('name')
|
||||
->label('Role Name')
|
||||
->label(trans('admin/role.name'))
|
||||
->required()
|
||||
->disabled(fn (Get $get) => $get('name') === Role::ROOT_ADMIN),
|
||||
TextInput::make('guard_name')
|
||||
@ -75,12 +93,13 @@ class RoleResource extends Resource
|
||||
->default(Role::DEFAULT_GUARD_NAME)
|
||||
->nullable()
|
||||
->hidden(),
|
||||
Fieldset::make('Permissions')
|
||||
Fieldset::make(trans('admin/role.permissions'))
|
||||
->columns(3)
|
||||
->schema($permissions)
|
||||
->hidden(fn (Get $get) => $get('name') === Role::ROOT_ADMIN),
|
||||
Placeholder::make('permissions')
|
||||
->content('The Root Admin has all permissions.')
|
||||
->label(trans('admin/role.permissions'))
|
||||
->content(trans('admin/role.root_admin', ['role' => Role::ROOT_ADMIN]))
|
||||
->visible(fn (Get $get) => $get('name') === Role::ROOT_ADMIN),
|
||||
]);
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ class EditRole extends EditRecord
|
||||
return [
|
||||
DeleteAction::make()
|
||||
->disabled(fn (Role $role) => $role->isRootAdmin() || $role->users_count >= 1)
|
||||
->label(fn (Role $role) => $role->isRootAdmin() ? 'Can\'t delete Root Admin' : ($role->users_count >= 1 ? 'In Use' : 'Delete')),
|
||||
->label(fn (Role $role) => $role->isRootAdmin() ? trans('admin/role.root_admin_delete') : ($role->users_count >= 1 ? trans('admin/role.in_use') : trans('filament-actions::delete.single.label'))),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ use App\Models\Role;
|
||||
use Filament\Actions\CreateAction;
|
||||
use Filament\Resources\Pages\ListRecords;
|
||||
use Filament\Tables\Actions\BulkActionGroup;
|
||||
use Filament\Tables\Actions\CreateAction as CreateActionTable;
|
||||
use Filament\Tables\Actions\DeleteBulkAction;
|
||||
use Filament\Tables\Actions\EditAction;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
@ -22,6 +21,7 @@ class ListRoles extends ListRecords
|
||||
return $table
|
||||
->columns([
|
||||
TextColumn::make('name')
|
||||
->label(trans('admin/role.name'))
|
||||
->sortable()
|
||||
->searchable(),
|
||||
TextColumn::make('guard_name')
|
||||
@ -29,12 +29,12 @@ class ListRoles extends ListRecords
|
||||
->sortable()
|
||||
->searchable(),
|
||||
TextColumn::make('permissions_count')
|
||||
->label('Permissions')
|
||||
->label(trans('admin/role.permissions'))
|
||||
->badge()
|
||||
->counts('permissions')
|
||||
->formatStateUsing(fn (Role $role, $state) => $role->isRootAdmin() ? 'All' : $state),
|
||||
->formatStateUsing(fn (Role $role, $state) => $role->isRootAdmin() ? trans('admin/role.all') : $state),
|
||||
TextColumn::make('users_count')
|
||||
->label('Users')
|
||||
->label(trans('admin/role.users'))
|
||||
->counts('users')
|
||||
->icon('tabler-users'),
|
||||
])
|
||||
@ -47,14 +47,6 @@ class ListRoles extends ListRecords
|
||||
DeleteBulkAction::make()
|
||||
->authorize(fn () => auth()->user()->can('delete role')),
|
||||
]),
|
||||
])
|
||||
->emptyStateIcon('tabler-users-group')
|
||||
->emptyStateDescription('')
|
||||
->emptyStateHeading('No Roles')
|
||||
->emptyStateActions([
|
||||
CreateActionTable::make('create')
|
||||
->label('Create Role')
|
||||
->button(),
|
||||
]);
|
||||
}
|
||||
|
||||
@ -62,7 +54,7 @@ class ListRoles extends ListRecords
|
||||
{
|
||||
return [
|
||||
CreateAction::make()
|
||||
->label('Create Role'),
|
||||
->label(trans('admin/role.create_action', ['action' => trans('filament-actions::create.single.modal.actions.create.label')])),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -12,10 +12,28 @@ class ServerResource extends Resource
|
||||
|
||||
protected static ?string $navigationIcon = 'tabler-brand-docker';
|
||||
|
||||
protected static ?string $navigationGroup = 'Server';
|
||||
|
||||
protected static ?string $recordTitleAttribute = 'name';
|
||||
|
||||
public static function getNavigationLabel(): string
|
||||
{
|
||||
return trans('admin/server.nav_title');
|
||||
}
|
||||
|
||||
public static function getModelLabel(): string
|
||||
{
|
||||
return trans('admin/server.model_label');
|
||||
}
|
||||
|
||||
public static function getPluralModelLabel(): string
|
||||
{
|
||||
return trans('admin/server.model_label_plural');
|
||||
}
|
||||
|
||||
public static function getNavigationGroup(): ?string
|
||||
{
|
||||
return trans('admin/dashboard.server');
|
||||
}
|
||||
|
||||
public static function getNavigationBadge(): ?string
|
||||
{
|
||||
return static::getModel()::count() ?: null;
|
||||
|
@ -65,7 +65,7 @@ class CreateServer extends CreateRecord
|
||||
->schema([
|
||||
Wizard::make([
|
||||
Step::make('Information')
|
||||
->label('Information')
|
||||
->label(trans('admin/server.tabs.information'))
|
||||
->icon('tabler-info-circle')
|
||||
->completedIcon('tabler-check')
|
||||
->columns([
|
||||
@ -76,7 +76,7 @@ class CreateServer extends CreateRecord
|
||||
->schema([
|
||||
TextInput::make('name')
|
||||
->prefixIcon('tabler-server')
|
||||
->label('Name')
|
||||
->label(trans('admin/server.name'))
|
||||
->suffixAction(Forms\Components\Actions\Action::make('random')
|
||||
->icon('tabler-dice-' . random_int(1, 6))
|
||||
->action(function (Set $set, Get $get) {
|
||||
@ -96,7 +96,7 @@ class CreateServer extends CreateRecord
|
||||
->maxLength(255),
|
||||
|
||||
TextInput::make('external_id')
|
||||
->label('External ID')
|
||||
->label(trans('admin/server.external_id'))
|
||||
->columnSpan([
|
||||
'default' => 1,
|
||||
'sm' => 2,
|
||||
@ -128,7 +128,7 @@ class CreateServer extends CreateRecord
|
||||
->preload()
|
||||
->prefixIcon('tabler-user')
|
||||
->default(auth()->user()->id)
|
||||
->label('Owner')
|
||||
->label(trans('admin/server.owner'))
|
||||
->columnSpan([
|
||||
'default' => 1,
|
||||
'sm' => 2,
|
||||
@ -139,20 +139,23 @@ class CreateServer extends CreateRecord
|
||||
->getOptionLabelFromRecordUsing(fn (User $user) => "$user->email | $user->username " . (blank($user->roles) ? '' : '(' . $user->roles->first()->name . ')'))
|
||||
->createOptionForm([
|
||||
TextInput::make('username')
|
||||
->label(trans('admin/user.edit.username'))
|
||||
->alphaNum()
|
||||
->required()
|
||||
->minLength(3)
|
||||
->maxLength(255),
|
||||
|
||||
TextInput::make('email')
|
||||
->label(trans('admin/user.edit.email'))
|
||||
->email()
|
||||
->required()
|
||||
->unique()
|
||||
->maxLength(255),
|
||||
|
||||
TextInput::make('password')
|
||||
->label(trans('admin/user.edit.password'))
|
||||
->hintIcon('tabler-question-mark')
|
||||
->hintIconTooltip('Providing a user password is optional. New user email will prompt users to create a password the first time they login.')
|
||||
->hintIconTooltip(trans('admin/user.password_help'))
|
||||
->password(),
|
||||
])
|
||||
->createOptionUsing(function ($data, UserCreationService $service) {
|
||||
@ -166,7 +169,7 @@ class CreateServer extends CreateRecord
|
||||
->preload()
|
||||
->live()
|
||||
->prefixIcon('tabler-network')
|
||||
->label('Primary Allocation')
|
||||
->label(trans('admin/server.primary_allocation'))
|
||||
->columnSpan([
|
||||
'default' => 1,
|
||||
'sm' => 2,
|
||||
@ -186,10 +189,10 @@ class CreateServer extends CreateRecord
|
||||
$node = Node::find($get('node_id'));
|
||||
|
||||
if ($node?->allocations) {
|
||||
return 'Select an Allocation';
|
||||
return trans('admin/server.select_allocation');
|
||||
}
|
||||
|
||||
return 'Create a New Allocation';
|
||||
return trans('admin/server.new_allocation');
|
||||
})
|
||||
->relationship(
|
||||
'allocation',
|
||||
@ -204,32 +207,23 @@ class CreateServer extends CreateRecord
|
||||
return [
|
||||
Select::make('allocation_ip')
|
||||
->options(collect(Node::find($get('node_id'))?->ipAddresses())->mapWithKeys(fn (string $ip) => [$ip => $ip]))
|
||||
->label('IP Address')
|
||||
->helperText("Usually your machine's public IP unless you are port forwarding.")
|
||||
->label(trans('admin/server.ip_address'))->inlineLabel()
|
||||
->helperText(trans('admin/server.ip_address_helper'))
|
||||
->afterStateUpdated(fn (Set $set) => $set('allocation_ports', []))
|
||||
->inlineLabel()
|
||||
->ipv4()
|
||||
->live()
|
||||
->required(),
|
||||
TextInput::make('allocation_alias')
|
||||
->label('Alias')
|
||||
->inlineLabel()
|
||||
->label(trans('admin/server.alias'))->inlineLabel()
|
||||
->default(null)
|
||||
->datalist([
|
||||
$get('name'),
|
||||
Egg::find($get('egg_id'))?->name,
|
||||
])
|
||||
->helperText('Optional display name to help you remember what these are.')
|
||||
->required(false),
|
||||
->helperText(trans('admin/server.alias_helper')),
|
||||
TagsInput::make('allocation_ports')
|
||||
->placeholder('Examples: 27015, 27017-27019')
|
||||
->helperText(new HtmlString('
|
||||
These are the ports that users can connect to this Server through.
|
||||
<br />
|
||||
You would have to port forward these on your home network.
|
||||
'))
|
||||
->label('Ports')
|
||||
->inlineLabel()
|
||||
->label(trans('admin/server.port'))->inlineLabel()
|
||||
->placeholder('27015, 27017-27019')
|
||||
->live()
|
||||
->disabled(fn (Get $get) => empty($get('allocation_ip')))
|
||||
->afterStateUpdated(fn ($state, Set $set, Get $get) => $set('allocation_ports',
|
||||
@ -247,7 +241,7 @@ class CreateServer extends CreateRecord
|
||||
->required(),
|
||||
|
||||
Repeater::make('allocation_additional')
|
||||
->label('Additional Allocations')
|
||||
->label(trans('admin/server.additional_allocations'))
|
||||
->columnSpan([
|
||||
'default' => 1,
|
||||
'sm' => 2,
|
||||
@ -271,7 +265,7 @@ class CreateServer extends CreateRecord
|
||||
fn (Allocation $allocation) => "$allocation->ip:$allocation->port" .
|
||||
($allocation->ip_alias ? " ($allocation->ip_alias)" : '')
|
||||
)
|
||||
->placeholder('Select additional Allocations')
|
||||
->placeholder(trans('admin/server.select_additional'))
|
||||
->disableOptionsWhenSelectedInSiblingRepeaterItems()
|
||||
->relationship(
|
||||
'allocations',
|
||||
@ -284,18 +278,16 @@ class CreateServer extends CreateRecord
|
||||
),
|
||||
|
||||
Textarea::make('description')
|
||||
->placeholder('Description')
|
||||
->label(trans('admin/server.description'))
|
||||
->rows(3)
|
||||
->columnSpan([
|
||||
'default' => 1,
|
||||
'sm' => 4,
|
||||
'md' => 4,
|
||||
])
|
||||
->label('Description'),
|
||||
]),
|
||||
]),
|
||||
|
||||
Step::make('Egg Configuration')
|
||||
->label('Egg Configuration')
|
||||
Step::make(trans('admin/server.tabs.egg_configuration'))
|
||||
->icon('tabler-egg')
|
||||
->completedIcon('tabler-check')
|
||||
->columns([
|
||||
@ -306,6 +298,7 @@ class CreateServer extends CreateRecord
|
||||
])
|
||||
->schema([
|
||||
Select::make('egg_id')
|
||||
->label(trans('admin/server.name'))
|
||||
->prefixIcon('tabler-egg')
|
||||
->relationship('egg', 'name')
|
||||
->columnSpan([
|
||||
@ -346,7 +339,7 @@ class CreateServer extends CreateRecord
|
||||
->required(),
|
||||
|
||||
ToggleButtons::make('skip_scripts')
|
||||
->label('Run Egg Install Script?')
|
||||
->label(trans('admin/server.install_script'))
|
||||
->default(false)
|
||||
->columnSpan([
|
||||
'default' => 1,
|
||||
@ -355,8 +348,8 @@ class CreateServer extends CreateRecord
|
||||
'lg' => 1,
|
||||
])
|
||||
->options([
|
||||
false => 'Yes',
|
||||
true => 'Skip',
|
||||
false => trans('admin/server.yes'),
|
||||
true => trans('admin/server.skip'),
|
||||
])
|
||||
->colors([
|
||||
false => 'primary',
|
||||
@ -370,7 +363,7 @@ class CreateServer extends CreateRecord
|
||||
->required(),
|
||||
|
||||
ToggleButtons::make('start_on_completion')
|
||||
->label('Start Server After Install?')
|
||||
->label(trans('admin/server.start_after'))
|
||||
->default(true)
|
||||
->required()
|
||||
->columnSpan([
|
||||
@ -380,8 +373,8 @@ class CreateServer extends CreateRecord
|
||||
'lg' => 1,
|
||||
])
|
||||
->options([
|
||||
true => 'Yes',
|
||||
false => 'No',
|
||||
true => trans('admin/server.yes'),
|
||||
false => trans('admin/server.no'),
|
||||
])
|
||||
->colors([
|
||||
true => 'primary',
|
||||
@ -395,7 +388,7 @@ class CreateServer extends CreateRecord
|
||||
|
||||
Textarea::make('startup')
|
||||
->hintIcon('tabler-code')
|
||||
->label('Startup Command')
|
||||
->label(trans('admin/server.startup_cmd'))
|
||||
->hidden(fn (Get $get) => $get('egg_id') === null)
|
||||
->required()
|
||||
->live()
|
||||
@ -414,17 +407,17 @@ class CreateServer extends CreateRecord
|
||||
|
||||
Hidden::make('environment')->default([]),
|
||||
|
||||
Section::make('Variables')
|
||||
Section::make(trans('admin/server.variables'))
|
||||
->icon('tabler-eggs')
|
||||
->iconColor('primary')
|
||||
->hidden(fn (Get $get) => $get('egg_id') === null)
|
||||
->collapsible()
|
||||
->columnSpanFull()
|
||||
->schema([
|
||||
Placeholder::make('Select an egg first to show its variables!')
|
||||
Placeholder::make(trans('admin/server.select_egg'))
|
||||
->hidden(fn (Get $get) => $get('egg_id')),
|
||||
|
||||
Placeholder::make('The selected egg has no variables!')
|
||||
Placeholder::make(trans('admin/server.no_variables'))
|
||||
->hidden(fn (Get $get) => !$get('egg_id') ||
|
||||
Egg::query()->find($get('egg_id'))?->variables()?->count()
|
||||
),
|
||||
@ -486,12 +479,11 @@ class CreateServer extends CreateRecord
|
||||
->columnSpan(2),
|
||||
]),
|
||||
]),
|
||||
Step::make('Environment Configuration')
|
||||
->label('Environment Configuration')
|
||||
Step::make(trans('admin/server.tabs.environment_configuration'))
|
||||
->icon('tabler-brand-docker')
|
||||
->completedIcon('tabler-check')
|
||||
->schema([
|
||||
Fieldset::make('Resource Limits')
|
||||
Fieldset::make(trans('admin/server.resource_limits'))
|
||||
->columnSpan(6)
|
||||
->columns([
|
||||
'default' => 1,
|
||||
@ -505,13 +497,13 @@ class CreateServer extends CreateRecord
|
||||
->columnSpanFull()
|
||||
->schema([
|
||||
ToggleButtons::make('unlimited_cpu')
|
||||
->label('CPU')->inlineLabel()->inline()
|
||||
->label(trans('admin/server.cpu'))->inlineLabel()->inline()
|
||||
->default(true)
|
||||
->afterStateUpdated(fn (Set $set) => $set('cpu', 0))
|
||||
->live()
|
||||
->options([
|
||||
true => 'Unlimited',
|
||||
false => 'Limited',
|
||||
true => trans('admin/server.unlimited'),
|
||||
false => trans('admin/server.limited'),
|
||||
])
|
||||
->colors([
|
||||
true => 'primary',
|
||||
@ -522,27 +514,27 @@ class CreateServer extends CreateRecord
|
||||
TextInput::make('cpu')
|
||||
->dehydratedWhenHidden()
|
||||
->hidden(fn (Get $get) => $get('unlimited_cpu'))
|
||||
->label('CPU Limit')->inlineLabel()
|
||||
->label(trans('admin/server.cpu_limit'))->inlineLabel()
|
||||
->suffix('%')
|
||||
->default(0)
|
||||
->required()
|
||||
->columnSpan(2)
|
||||
->numeric()
|
||||
->minValue(0)
|
||||
->helperText('100% equals one CPU core.'),
|
||||
->helperText(trans('admin/server.cpu_helper')),
|
||||
]),
|
||||
Grid::make()
|
||||
->columns(4)
|
||||
->columnSpanFull()
|
||||
->schema([
|
||||
ToggleButtons::make('unlimited_mem')
|
||||
->label('Memory')->inlineLabel()->inline()
|
||||
->label(trans('admin/server.memory'))->inlineLabel()->inline()
|
||||
->default(true)
|
||||
->afterStateUpdated(fn (Set $set) => $set('memory', 0))
|
||||
->live()
|
||||
->options([
|
||||
true => 'Unlimited',
|
||||
false => 'Limited',
|
||||
true => trans('admin/server.unlimited'),
|
||||
false => trans('admin/server.limited'),
|
||||
])
|
||||
->colors([
|
||||
true => 'primary',
|
||||
@ -553,7 +545,7 @@ class CreateServer extends CreateRecord
|
||||
TextInput::make('memory')
|
||||
->dehydratedWhenHidden()
|
||||
->hidden(fn (Get $get) => $get('unlimited_mem'))
|
||||
->label('Memory Limit')->inlineLabel()
|
||||
->label(trans('admin/server.memory_limit'))->inlineLabel()
|
||||
->suffix(config('panel.use_binary_prefix') ? 'MiB' : 'MB')
|
||||
->default(0)
|
||||
->required()
|
||||
@ -566,13 +558,13 @@ class CreateServer extends CreateRecord
|
||||
->columnSpanFull()
|
||||
->schema([
|
||||
ToggleButtons::make('unlimited_disk')
|
||||
->label('Disk Space')->inlineLabel()->inline()
|
||||
->label(trans('admin/server.disk'))->inlineLabel()->inline()
|
||||
->default(true)
|
||||
->live()
|
||||
->afterStateUpdated(fn (Set $set) => $set('disk', 0))
|
||||
->options([
|
||||
true => 'Unlimited',
|
||||
false => 'Limited',
|
||||
true => trans('admin/server.unlimited'),
|
||||
false => trans('admin/server.limited'),
|
||||
])
|
||||
->colors([
|
||||
true => 'primary',
|
||||
@ -583,7 +575,7 @@ class CreateServer extends CreateRecord
|
||||
TextInput::make('disk')
|
||||
->dehydratedWhenHidden()
|
||||
->hidden(fn (Get $get) => $get('unlimited_disk'))
|
||||
->label('Disk Space Limit')->inlineLabel()
|
||||
->label(trans('admin/server.disk_limit'))->inlineLabel()
|
||||
->suffix(config('panel.use_binary_prefix') ? 'MiB' : 'MB')
|
||||
->default(0)
|
||||
->required()
|
||||
@ -594,7 +586,7 @@ class CreateServer extends CreateRecord
|
||||
|
||||
]),
|
||||
|
||||
Fieldset::make('Advanced Limits')
|
||||
Fieldset::make(trans('admin/server.advanced_limits'))
|
||||
->columnSpan(6)
|
||||
->columns([
|
||||
'default' => 1,
|
||||
@ -613,13 +605,13 @@ class CreateServer extends CreateRecord
|
||||
->columnSpanFull()
|
||||
->schema([
|
||||
ToggleButtons::make('cpu_pinning')
|
||||
->label('CPU Pinning')->inlineLabel()->inline()
|
||||
->label(trans('admin/server.cpu_pin'))->inlineLabel()->inline()
|
||||
->default(false)
|
||||
->afterStateUpdated(fn (Set $set) => $set('threads', []))
|
||||
->live()
|
||||
->options([
|
||||
false => 'Disabled',
|
||||
true => 'Enabled',
|
||||
false => trans('admin/server.disabled'),
|
||||
true => trans('admin/server.enabled'),
|
||||
])
|
||||
->colors([
|
||||
false => 'success',
|
||||
@ -630,12 +622,12 @@ class CreateServer extends CreateRecord
|
||||
TagsInput::make('threads')
|
||||
->dehydratedWhenHidden()
|
||||
->hidden(fn (Get $get) => !$get('cpu_pinning'))
|
||||
->label('Pinned Threads')->inlineLabel()
|
||||
->label(trans('admin/server.threads'))->inlineLabel()
|
||||
->required(fn (Get $get) => $get('cpu_pinning'))
|
||||
->columnSpan(2)
|
||||
->separator()
|
||||
->splitKeys([','])
|
||||
->placeholder('Add pinned thread, e.g. 0 or 2-4'),
|
||||
->placeholder(trans('admin/server.pin_help')),
|
||||
]),
|
||||
Grid::make()
|
||||
->columns(4)
|
||||
@ -643,7 +635,7 @@ class CreateServer extends CreateRecord
|
||||
->schema([
|
||||
ToggleButtons::make('swap_support')
|
||||
->live()
|
||||
->label('Swap Memory')
|
||||
->label(trans('admin/server.swap'))
|
||||
->inlineLabel()
|
||||
->inline()
|
||||
->columnSpan(2)
|
||||
@ -659,9 +651,9 @@ class CreateServer extends CreateRecord
|
||||
$set('swap', $value);
|
||||
})
|
||||
->options([
|
||||
'unlimited' => 'Unlimited',
|
||||
'limited' => 'Limited',
|
||||
'disabled' => 'Disabled',
|
||||
'unlimited' => trans('admin/server.unlimited'),
|
||||
'limited' => trans('admin/server.limited'),
|
||||
'disabled' => trans('admin/server.disabled'),
|
||||
])
|
||||
->colors([
|
||||
'unlimited' => 'primary',
|
||||
@ -675,7 +667,7 @@ class CreateServer extends CreateRecord
|
||||
'disabled', 'unlimited' => true,
|
||||
default => false,
|
||||
})
|
||||
->label('Swap Memory')
|
||||
->label(trans('admin/server.swap_limit'))
|
||||
->default(0)
|
||||
->suffix(config('panel.use_binary_prefix') ? 'MiB' : 'MB')
|
||||
->minValue(-1)
|
||||
@ -690,13 +682,13 @@ class CreateServer extends CreateRecord
|
||||
->columnSpanFull()
|
||||
->schema([
|
||||
ToggleButtons::make('oom_killer')
|
||||
->label('OOM Killer')
|
||||
->label(trans('admin/server.oom'))
|
||||
->inlineLabel()->inline()
|
||||
->default(false)
|
||||
->columnSpan(2)
|
||||
->options([
|
||||
false => 'Disabled',
|
||||
true => 'Enabled',
|
||||
false => trans('admin/server.disabled'),
|
||||
true => trans('admin/server.enabled'),
|
||||
])
|
||||
->colors([
|
||||
false => 'success',
|
||||
@ -708,7 +700,7 @@ class CreateServer extends CreateRecord
|
||||
]),
|
||||
]),
|
||||
|
||||
Fieldset::make('Feature Limits')
|
||||
Fieldset::make(trans('admin/server.feature_limits'))
|
||||
->inlineLabel()
|
||||
->columnSpan(6)
|
||||
->columns([
|
||||
@ -719,28 +711,28 @@ class CreateServer extends CreateRecord
|
||||
])
|
||||
->schema([
|
||||
TextInput::make('allocation_limit')
|
||||
->label('Allocations')
|
||||
->label(trans('admin/server.allocations'))
|
||||
->suffixIcon('tabler-network')
|
||||
->required()
|
||||
->numeric()
|
||||
->minValue(0)
|
||||
->default(0),
|
||||
TextInput::make('database_limit')
|
||||
->label('Databases')
|
||||
->label(trans('admin/server.databases'))
|
||||
->suffixIcon('tabler-database')
|
||||
->required()
|
||||
->numeric()
|
||||
->minValue(0)
|
||||
->default(0),
|
||||
TextInput::make('backup_limit')
|
||||
->label('Backups')
|
||||
->label(trans('admin/server.backups'))
|
||||
->suffixIcon('tabler-copy-check')
|
||||
->required()
|
||||
->numeric()
|
||||
->minValue(0)
|
||||
->default(0),
|
||||
]),
|
||||
Fieldset::make('Docker Settings')
|
||||
Fieldset::make(trans('admin/server.docker_settings'))
|
||||
->columns([
|
||||
'default' => 1,
|
||||
'sm' => 2,
|
||||
@ -750,7 +742,7 @@ class CreateServer extends CreateRecord
|
||||
->columnSpan(6)
|
||||
->schema([
|
||||
Select::make('select_image')
|
||||
->label('Image Name')
|
||||
->label(trans('admin/server.image_name'))
|
||||
->live()
|
||||
->afterStateUpdated(fn (Set $set, $state) => $set('image', $state))
|
||||
->options(function ($state, Get $get, Set $set) {
|
||||
@ -775,7 +767,7 @@ class CreateServer extends CreateRecord
|
||||
]),
|
||||
|
||||
TextInput::make('image')
|
||||
->label('Image')
|
||||
->label(trans('admin/server.image'))
|
||||
->required()
|
||||
->afterStateUpdated(function ($state, Get $get, Set $set) {
|
||||
$egg = Egg::query()->find($get('egg_id'));
|
||||
@ -787,7 +779,7 @@ class CreateServer extends CreateRecord
|
||||
$set('select_image', 'ghcr.io/custom-image');
|
||||
}
|
||||
})
|
||||
->placeholder('Enter a custom Image')
|
||||
->placeholder(trans('admin/server.image_placeholder'))
|
||||
->columnSpan([
|
||||
'default' => 1,
|
||||
'sm' => 2,
|
||||
@ -797,23 +789,23 @@ class CreateServer extends CreateRecord
|
||||
|
||||
KeyValue::make('docker_labels')
|
||||
->label('Container Labels')
|
||||
->keyLabel('Title')
|
||||
->valueLabel('Description')
|
||||
->keyLabel(trans('admin/server.title'))
|
||||
->valueLabel(trans('admin/server.description'))
|
||||
->columnSpanFull(),
|
||||
|
||||
CheckboxList::make('mounts')
|
||||
->label('Mounts')
|
||||
->live()
|
||||
->relationship('mounts')
|
||||
->options(fn () => $this->node?->mounts->mapWithKeys(fn ($mount) => [$mount->id => $mount->name]) ?? [])
|
||||
->descriptions(fn () => $this->node?->mounts->mapWithKeys(fn ($mount) => [$mount->id => "$mount->source -> $mount->target"]) ?? [])
|
||||
->label('Mounts')
|
||||
->helperText(fn () => $this->node?->mounts->isNotEmpty() ? '' : 'No Mounts exist for this Node')
|
||||
->columnSpanFull(),
|
||||
]),
|
||||
]),
|
||||
])
|
||||
->columnSpanFull()
|
||||
->nextAction(fn (Action $action) => $action->label('Next Step'))
|
||||
->nextAction(fn (Action $action) => $action->label(trans('admin/server.next_step')))
|
||||
->submitAction(new HtmlString(Blade::render(<<<'BLADE'
|
||||
<x-filament::button
|
||||
type="submit"
|
||||
@ -843,7 +835,7 @@ class CreateServer extends CreateRecord
|
||||
return $this->serverCreationService->handle($data);
|
||||
} catch (Exception $exception) {
|
||||
Notification::make()
|
||||
->title('Could not create server')
|
||||
->title(trans('admin/server.notifications.create_failed'))
|
||||
->body($exception->getMessage())
|
||||
->color('danger')
|
||||
->danger()
|
||||
@ -906,9 +898,9 @@ class CreateServer extends CreateRecord
|
||||
|
||||
if (!is_numeric($start) || !is_numeric($end)) {
|
||||
Notification::make()
|
||||
->title('Invalid Port Range')
|
||||
->title(trans('admin/server.notifications.invalid_port_range'))
|
||||
->danger()
|
||||
->body("Your port range are not valid integers: $portEntry")
|
||||
->body(trans('admin/server.notifications.invalid_port_range_body', ['port' => $portEntry]))
|
||||
->send();
|
||||
|
||||
continue;
|
||||
@ -920,9 +912,9 @@ class CreateServer extends CreateRecord
|
||||
|
||||
if (count($range) > $portRangeLimit) {
|
||||
Notification::make()
|
||||
->title('Too many ports at one time!')
|
||||
->title(trans('admin/server.notifications.too_many_ports'))
|
||||
->danger()
|
||||
->body("The current limit is $portRangeLimit number of ports at one time.")
|
||||
->body(trans('admin/server.notifications.too_many_ports_body', ['limit' => $portRangeLimit]))
|
||||
->send();
|
||||
|
||||
continue;
|
||||
@ -932,9 +924,9 @@ class CreateServer extends CreateRecord
|
||||
// Invalid port number
|
||||
if ($i <= $portFloor || $i > $portCeil) {
|
||||
Notification::make()
|
||||
->title('Port not in valid range')
|
||||
->title(trans('admin/server.notifications.invalid_port'))
|
||||
->danger()
|
||||
->body("$i is not in the valid port range between $portFloor-$portCeil")
|
||||
->body(trans('admin/server.notifications.invalid_port_body', ['i' => $i, 'portFloor' => $portFloor, 'portCeil' => $portCeil]))
|
||||
->send();
|
||||
|
||||
continue;
|
||||
@ -943,9 +935,9 @@ class CreateServer extends CreateRecord
|
||||
// Already exists
|
||||
if (in_array($i, $existingPorts)) {
|
||||
Notification::make()
|
||||
->title('Port already in use')
|
||||
->title(trans('admin/server.notifications.already_exists'))
|
||||
->danger()
|
||||
->body("$i is already with an allocation")
|
||||
->body(trans('admin/server.notifications.already_exists_body', ['i' => $i]))
|
||||
->send();
|
||||
|
||||
continue;
|
||||
|
@ -71,12 +71,12 @@ class EditServer extends EditRecord
|
||||
])
|
||||
->columnSpanFull()
|
||||
->tabs([
|
||||
Tab::make('Information')
|
||||
Tab::make(trans('admin/server.tabs.information'))
|
||||
->icon('tabler-info-circle')
|
||||
->schema([
|
||||
TextInput::make('name')
|
||||
->prefixIcon('tabler-server')
|
||||
->label('Display Name')
|
||||
->label(trans('admin/server.name'))
|
||||
->suffixAction(Action::make('random')
|
||||
->icon('tabler-dice-' . random_int(1, 6))
|
||||
->action(function (Set $set, Get $get) {
|
||||
@ -98,7 +98,7 @@ class EditServer extends EditRecord
|
||||
|
||||
Select::make('owner_id')
|
||||
->prefixIcon('tabler-user')
|
||||
->label('Owner')
|
||||
->label(trans('admin/server.owner'))
|
||||
->columnSpan([
|
||||
'default' => 2,
|
||||
'sm' => 1,
|
||||
@ -112,7 +112,7 @@ class EditServer extends EditRecord
|
||||
->required(),
|
||||
|
||||
ToggleButtons::make('condition')
|
||||
->label('Server Status')
|
||||
->label(trans('admin/server.server_status'))
|
||||
->formatStateUsing(fn (Server $server) => $server->condition)
|
||||
->options(fn ($state) => collect(array_merge(ContainerStatus::cases(), ServerState::cases()))
|
||||
->filter(fn ($condition) => $condition->value === $state)
|
||||
@ -132,10 +132,11 @@ class EditServer extends EditRecord
|
||||
]),
|
||||
|
||||
Textarea::make('description')
|
||||
->label('Description')
|
||||
->label(trans('admin/server.description'))
|
||||
->columnSpanFull(),
|
||||
|
||||
TextInput::make('uuid')
|
||||
->label(trans('admin/server.uuid'))
|
||||
->suffixAction(fn () => request()->isSecure() ? CopyAction::make() : null)
|
||||
->columnSpan([
|
||||
'default' => 2,
|
||||
@ -146,7 +147,7 @@ class EditServer extends EditRecord
|
||||
->readOnly()
|
||||
->dehydrated(false),
|
||||
TextInput::make('uuid_short')
|
||||
->label('Short UUID')
|
||||
->label(trans('admin/server.short_uuid'))
|
||||
->suffixAction(fn () => request()->isSecure() ? CopyAction::make() : null)
|
||||
->columnSpan([
|
||||
'default' => 2,
|
||||
@ -157,7 +158,7 @@ class EditServer extends EditRecord
|
||||
->readOnly()
|
||||
->dehydrated(false),
|
||||
TextInput::make('external_id')
|
||||
->label('External ID')
|
||||
->label(trans('admin/server.external_id'))
|
||||
->columnSpan([
|
||||
'default' => 2,
|
||||
'sm' => 1,
|
||||
@ -167,7 +168,7 @@ class EditServer extends EditRecord
|
||||
->unique()
|
||||
->maxLength(255),
|
||||
Select::make('node_id')
|
||||
->label('Node')
|
||||
->label(trans('admin/server.node'))
|
||||
->relationship('node', 'name')
|
||||
->columnSpan([
|
||||
'default' => 2,
|
||||
@ -177,10 +178,10 @@ class EditServer extends EditRecord
|
||||
])
|
||||
->disabled(),
|
||||
]),
|
||||
Tab::make('Environment')
|
||||
Tab::make(trans('admin/server.tabs.environment_configuration'))
|
||||
->icon('tabler-brand-docker')
|
||||
->schema([
|
||||
Fieldset::make('Resource Limits')
|
||||
Fieldset::make(trans('admin/server.resource_limits'))
|
||||
->columns([
|
||||
'default' => 1,
|
||||
'sm' => 2,
|
||||
@ -193,13 +194,13 @@ class EditServer extends EditRecord
|
||||
->columnSpanFull()
|
||||
->schema([
|
||||
ToggleButtons::make('unlimited_cpu')
|
||||
->label('CPU')->inlineLabel()->inline()
|
||||
->label(trans('admin/server.cpu'))->inlineLabel()->inline()
|
||||
->afterStateUpdated(fn (Set $set) => $set('cpu', 0))
|
||||
->formatStateUsing(fn (Get $get) => $get('cpu') == 0)
|
||||
->live()
|
||||
->options([
|
||||
true => 'Unlimited',
|
||||
false => 'Limited',
|
||||
true => trans('admin/server.unlimited'),
|
||||
false => trans('admin/server.limited'),
|
||||
])
|
||||
->colors([
|
||||
true => 'primary',
|
||||
@ -210,7 +211,7 @@ class EditServer extends EditRecord
|
||||
TextInput::make('cpu')
|
||||
->dehydratedWhenHidden()
|
||||
->hidden(fn (Get $get) => $get('unlimited_cpu'))
|
||||
->label('CPU Limit')->inlineLabel()
|
||||
->label(trans('admin/server.cpu_limit'))->inlineLabel()
|
||||
->suffix('%')
|
||||
->required()
|
||||
->columnSpan(2)
|
||||
@ -222,13 +223,13 @@ class EditServer extends EditRecord
|
||||
->columnSpanFull()
|
||||
->schema([
|
||||
ToggleButtons::make('unlimited_mem')
|
||||
->label('Memory')->inlineLabel()->inline()
|
||||
->label(trans('admin/server.memory'))->inlineLabel()->inline()
|
||||
->afterStateUpdated(fn (Set $set) => $set('memory', 0))
|
||||
->formatStateUsing(fn (Get $get) => $get('memory') == 0)
|
||||
->live()
|
||||
->options([
|
||||
true => 'Unlimited',
|
||||
false => 'Limited',
|
||||
true => trans('admin/server.unlimited'),
|
||||
false => trans('admin/server.limited'),
|
||||
])
|
||||
->colors([
|
||||
true => 'primary',
|
||||
@ -239,7 +240,7 @@ class EditServer extends EditRecord
|
||||
TextInput::make('memory')
|
||||
->dehydratedWhenHidden()
|
||||
->hidden(fn (Get $get) => $get('unlimited_mem'))
|
||||
->label('Memory Limit')->inlineLabel()
|
||||
->label(trans('admin/server.memory_limit'))->inlineLabel()
|
||||
->suffix(config('panel.use_binary_prefix') ? 'MiB' : 'MB')
|
||||
->required()
|
||||
->columnSpan(2)
|
||||
@ -252,13 +253,13 @@ class EditServer extends EditRecord
|
||||
->columnSpanFull()
|
||||
->schema([
|
||||
ToggleButtons::make('unlimited_disk')
|
||||
->label('Disk Space')->inlineLabel()->inline()
|
||||
->label(trans('admin/server.disk'))->inlineLabel()->inline()
|
||||
->live()
|
||||
->afterStateUpdated(fn (Set $set) => $set('disk', 0))
|
||||
->formatStateUsing(fn (Get $get) => $get('disk') == 0)
|
||||
->options([
|
||||
true => 'Unlimited',
|
||||
false => 'Limited',
|
||||
true => trans('admin/server.unlimited'),
|
||||
false => trans('admin/server.limited'),
|
||||
])
|
||||
->colors([
|
||||
true => 'primary',
|
||||
@ -269,7 +270,7 @@ class EditServer extends EditRecord
|
||||
TextInput::make('disk')
|
||||
->dehydratedWhenHidden()
|
||||
->hidden(fn (Get $get) => $get('unlimited_disk'))
|
||||
->label('Disk Space Limit')->inlineLabel()
|
||||
->label(trans('admin/server.disk_limit'))->inlineLabel()
|
||||
->suffix(config('panel.use_binary_prefix') ? 'MiB' : 'MB')
|
||||
->required()
|
||||
->columnSpan(2)
|
||||
@ -278,7 +279,7 @@ class EditServer extends EditRecord
|
||||
]),
|
||||
]),
|
||||
|
||||
Fieldset::make('Advanced Limits')
|
||||
Fieldset::make(trans('admin/server.advanced_limits'))
|
||||
->columns([
|
||||
'default' => 1,
|
||||
'sm' => 2,
|
||||
@ -295,14 +296,14 @@ class EditServer extends EditRecord
|
||||
->columnSpanFull()
|
||||
->schema([
|
||||
ToggleButtons::make('cpu_pinning')
|
||||
->label('CPU Pinning')->inlineLabel()->inline()
|
||||
->label(trans('admin/server.cpu_pin'))->inlineLabel()->inline()
|
||||
->default(false)
|
||||
->afterStateUpdated(fn (Set $set) => $set('threads', []))
|
||||
->formatStateUsing(fn (Get $get) => !empty($get('threads')))
|
||||
->live()
|
||||
->options([
|
||||
false => 'Disabled',
|
||||
true => 'Enabled',
|
||||
false => trans('admin/server.disabled'),
|
||||
true => trans('admin/server.enabled'),
|
||||
])
|
||||
->colors([
|
||||
false => 'success',
|
||||
@ -313,16 +314,16 @@ class EditServer extends EditRecord
|
||||
TagsInput::make('threads')
|
||||
->dehydratedWhenHidden()
|
||||
->hidden(fn (Get $get) => !$get('cpu_pinning'))
|
||||
->label('Pinned Threads')->inlineLabel()
|
||||
->label(trans('admin/server.threads'))->inlineLabel()
|
||||
->required(fn (Get $get) => $get('cpu_pinning'))
|
||||
->columnSpan(2)
|
||||
->separator()
|
||||
->splitKeys([','])
|
||||
->placeholder('Add pinned thread, e.g. 0 or 2-4'),
|
||||
->placeholder(trans('admin/server.pin_help')),
|
||||
]),
|
||||
ToggleButtons::make('swap_support')
|
||||
->live()
|
||||
->label('Swap Memory')->inlineLabel()->inline()
|
||||
->label(trans('admin/server.swap'))->inlineLabel()->inline()
|
||||
->columnSpan(2)
|
||||
->afterStateUpdated(function ($state, Set $set) {
|
||||
$value = match ($state) {
|
||||
@ -343,9 +344,9 @@ class EditServer extends EditRecord
|
||||
};
|
||||
})
|
||||
->options([
|
||||
'unlimited' => 'Unlimited',
|
||||
'limited' => 'Limited',
|
||||
'disabled' => 'Disabled',
|
||||
'unlimited' => trans('admin/server.unlimited'),
|
||||
'limited' => trans('admin/server.limited'),
|
||||
'disabled' => trans('admin/server.disabled'),
|
||||
])
|
||||
->colors([
|
||||
'unlimited' => 'primary',
|
||||
@ -359,7 +360,7 @@ class EditServer extends EditRecord
|
||||
'disabled', 'unlimited', true => true,
|
||||
default => false,
|
||||
})
|
||||
->label('Swap Memory')->inlineLabel()
|
||||
->label(trans('admin/server.swap'))->inlineLabel()
|
||||
->suffix(config('panel.use_binary_prefix') ? 'MiB' : 'MB')
|
||||
->minValue(-1)
|
||||
->columnSpan(2)
|
||||
@ -376,11 +377,11 @@ class EditServer extends EditRecord
|
||||
->columnSpanFull()
|
||||
->schema([
|
||||
ToggleButtons::make('oom_killer')
|
||||
->label('OOM Killer')->inlineLabel()->inline()
|
||||
->label(trans('admin/server.oom'))->inlineLabel()->inline()
|
||||
->columnSpan(2)
|
||||
->options([
|
||||
false => 'Disabled',
|
||||
true => 'Enabled',
|
||||
false => trans('admin/server.disabled'),
|
||||
true => trans('admin/server.enabled'),
|
||||
])
|
||||
->colors([
|
||||
false => 'success',
|
||||
@ -392,7 +393,7 @@ class EditServer extends EditRecord
|
||||
]),
|
||||
]),
|
||||
|
||||
Fieldset::make('Feature Limits')
|
||||
Fieldset::make(trans('admin/server.feature_limits'))
|
||||
->inlineLabel()
|
||||
->columns([
|
||||
'default' => 1,
|
||||
@ -402,25 +403,25 @@ class EditServer extends EditRecord
|
||||
])
|
||||
->schema([
|
||||
TextInput::make('allocation_limit')
|
||||
->label('Allocations')
|
||||
->label(trans('admin/server.allocations'))
|
||||
->suffixIcon('tabler-network')
|
||||
->required()
|
||||
->minValue(0)
|
||||
->numeric(),
|
||||
TextInput::make('database_limit')
|
||||
->label('Databases')
|
||||
->label(trans('admin/server.databases'))
|
||||
->suffixIcon('tabler-database')
|
||||
->required()
|
||||
->minValue(0)
|
||||
->numeric(),
|
||||
TextInput::make('backup_limit')
|
||||
->label('Backups')
|
||||
->label(trans('admin/server.backups'))
|
||||
->suffixIcon('tabler-copy-check')
|
||||
->required()
|
||||
->minValue(0)
|
||||
->numeric(),
|
||||
]),
|
||||
Fieldset::make('Docker Settings')
|
||||
Fieldset::make(trans('admin/server.docker_settings'))
|
||||
->columns([
|
||||
'default' => 1,
|
||||
'sm' => 2,
|
||||
@ -429,7 +430,7 @@ class EditServer extends EditRecord
|
||||
])
|
||||
->schema([
|
||||
Select::make('select_image')
|
||||
->label('Image Name')
|
||||
->label(trans('admin/server.image_name'))
|
||||
->live()
|
||||
->afterStateUpdated(fn (Set $set, $state) => $set('image', $state))
|
||||
->options(function ($state, Get $get, Set $set) {
|
||||
@ -454,7 +455,7 @@ class EditServer extends EditRecord
|
||||
]),
|
||||
|
||||
TextInput::make('image')
|
||||
->label('Image')
|
||||
->label(trans('admin/server.image'))
|
||||
->required()
|
||||
->afterStateUpdated(function ($state, Get $get, Set $set) {
|
||||
$egg = Egg::query()->find($get('egg_id'));
|
||||
@ -466,7 +467,7 @@ class EditServer extends EditRecord
|
||||
$set('select_image', 'ghcr.io/custom-image');
|
||||
}
|
||||
})
|
||||
->placeholder('Enter a custom Image')
|
||||
->placeholder(trans('admin/server.image_placeholder'))
|
||||
->columnSpan([
|
||||
'default' => 1,
|
||||
'sm' => 2,
|
||||
@ -475,13 +476,13 @@ class EditServer extends EditRecord
|
||||
]),
|
||||
|
||||
KeyValue::make('docker_labels')
|
||||
->label('Container Labels')
|
||||
->keyLabel('Label Name')
|
||||
->valueLabel('Label Description')
|
||||
->label(trans('admin/server.container_labels'))
|
||||
->keyLabel(trans('admin/server.title'))
|
||||
->valueLabel(trans('admin/server.description'))
|
||||
->columnSpanFull(),
|
||||
]),
|
||||
]),
|
||||
Tab::make('Egg')
|
||||
Tab::make(trans('admin/server.egg'))
|
||||
->icon('tabler-egg')
|
||||
->columns([
|
||||
'default' => 1,
|
||||
@ -500,11 +501,13 @@ class EditServer extends EditRecord
|
||||
'lg' => 4,
|
||||
])
|
||||
->relationship('egg', 'name')
|
||||
->label(trans('admin/server.name'))
|
||||
->searchable()
|
||||
->preload()
|
||||
->required()
|
||||
->hintAction(
|
||||
Action::make('change_egg')
|
||||
->label('admin/server.change_egg')
|
||||
->action(function (array $data, Server $server, EggChangerService $service) {
|
||||
$service->handle($server, $data['egg_id'], $data['keepOldVariables']);
|
||||
|
||||
@ -513,20 +516,20 @@ class EditServer extends EditRecord
|
||||
})
|
||||
->form(fn (Server $server) => [
|
||||
Select::make('egg_id')
|
||||
->label('New Egg')
|
||||
->label(trans('admin/server.new_egg'))
|
||||
->prefixIcon('tabler-egg')
|
||||
->options(fn () => Egg::all()->filter(fn (Egg $egg) => $egg->id !== $server->egg->id)->mapWithKeys(fn (Egg $egg) => [$egg->id => $egg->name]))
|
||||
->searchable()
|
||||
->preload()
|
||||
->required(),
|
||||
Toggle::make('keepOldVariables')
|
||||
->label('Keep old variables if possible?')
|
||||
->label(trans('admin/server.keep_old_variables'))
|
||||
->default(true),
|
||||
])
|
||||
),
|
||||
|
||||
ToggleButtons::make('skip_scripts')
|
||||
->label('Run Egg Install Script?')->inline()
|
||||
->label(trans('admin/server.install_script'))->inline()
|
||||
->columnSpan([
|
||||
'default' => 6,
|
||||
'sm' => 1,
|
||||
@ -534,8 +537,8 @@ class EditServer extends EditRecord
|
||||
'lg' => 2,
|
||||
])
|
||||
->options([
|
||||
false => 'Yes',
|
||||
true => 'Skip',
|
||||
false => trans('admin/server.yes'),
|
||||
true => trans('admin/server.skip'),
|
||||
])
|
||||
->colors([
|
||||
false => 'primary',
|
||||
@ -548,14 +551,14 @@ class EditServer extends EditRecord
|
||||
->required(),
|
||||
|
||||
Textarea::make('startup')
|
||||
->label('Startup Command')
|
||||
->label(trans('admin/server.startup_cmd'))
|
||||
->required()
|
||||
->columnSpan(6)
|
||||
->autosize(),
|
||||
|
||||
Textarea::make('defaultStartup')
|
||||
->hintAction(fn () => request()->isSecure() ? CopyAction::make() : null)
|
||||
->label('Default Startup Command')
|
||||
->label(trans('admin/server.default_startup'))
|
||||
->disabled()
|
||||
->autosize()
|
||||
->columnSpan(6)
|
||||
@ -566,6 +569,7 @@ class EditServer extends EditRecord
|
||||
}),
|
||||
|
||||
Repeater::make('server_variables')
|
||||
->label('')
|
||||
->relationship('serverVariables', function (Builder $query) {
|
||||
/** @var Server $server */
|
||||
$server = $this->getRecord();
|
||||
@ -632,52 +636,56 @@ class EditServer extends EditRecord
|
||||
})
|
||||
->columnSpan(6),
|
||||
]),
|
||||
Tab::make('Mounts')
|
||||
Tab::make(trans('admin/server.mounts'))
|
||||
->icon('tabler-layers-linked')
|
||||
->schema([
|
||||
CheckboxList::make('mounts')
|
||||
->label('')
|
||||
->relationship('mounts')
|
||||
->options(fn (Server $server) => $server->node->mounts->filter(fn (Mount $mount) => $mount->eggs->contains($server->egg))->mapWithKeys(fn (Mount $mount) => [$mount->id => $mount->name]))
|
||||
->descriptions(fn (Server $server) => $server->node->mounts->mapWithKeys(fn (Mount $mount) => [$mount->id => "$mount->source -> $mount->target"]))
|
||||
->label('Mounts')
|
||||
->helperText(fn (Server $server) => $server->node->mounts->isNotEmpty() ? '' : 'No Mounts exist for this Node')
|
||||
->helperText(fn (Server $server) => $server->node->mounts->isNotEmpty() ? '' : trans('admin/server.no_mounts'))
|
||||
->columnSpanFull(),
|
||||
]),
|
||||
Tab::make('Databases')
|
||||
Tab::make(trans('admin/server.databases'))
|
||||
->hidden(fn () => !auth()->user()->can('viewList database'))
|
||||
->icon('tabler-database')
|
||||
->columns(4)
|
||||
->schema([
|
||||
Repeater::make('databases')
|
||||
->label('')
|
||||
->grid()
|
||||
->helperText(fn (Server $server) => $server->databases->isNotEmpty() ? '' : 'No Databases exist for this Server')
|
||||
->helperText(fn (Server $server) => $server->databases->isNotEmpty() ? '' : trans('admin/server.no_databases'))
|
||||
->columns(2)
|
||||
->schema([
|
||||
TextInput::make('database')
|
||||
->columnSpan(2)
|
||||
->label('Database Name')
|
||||
->label(trans('admin/server.name'))
|
||||
->disabled()
|
||||
->formatStateUsing(fn ($record) => $record->database)
|
||||
->hintAction(
|
||||
Action::make('Delete')
|
||||
->label(trans('filament-actions::delete.single.modal.actions.delete.label'))
|
||||
->authorize(fn (Database $database) => auth()->user()->can('delete database', $database))
|
||||
->color('danger')
|
||||
->icon('tabler-trash')
|
||||
->requiresConfirmation()
|
||||
->modalIcon('tabler-database-x')
|
||||
->modalHeading('Delete Database?')
|
||||
->modalHeading(trans('admin/server.delete_db_heading'))
|
||||
->modalSubmitActionLabel(fn (Get $get) => 'Delete ' . $get('database') . '?')
|
||||
->modalDescription(fn (Get $get) => 'Are you sure you want to delete ' . $get('database') . '?')
|
||||
->modalDescription(fn (Get $get) => trans('admin/server.delete_db') . $get('database') . '?')
|
||||
->action(function (DatabaseManagementService $databaseManagementService, $record) {
|
||||
$databaseManagementService->delete($record);
|
||||
$this->fillForm();
|
||||
})
|
||||
),
|
||||
TextInput::make('username')
|
||||
->label(trans('admin/databasehost.table.username'))
|
||||
->disabled()
|
||||
->formatStateUsing(fn ($record) => $record->username)
|
||||
->columnSpan(1),
|
||||
TextInput::make('password')
|
||||
->label(trans('admin/databasehost.table.password'))
|
||||
->disabled()
|
||||
->password()
|
||||
->revealable()
|
||||
@ -688,8 +696,9 @@ class EditServer extends EditRecord
|
||||
->disabled()
|
||||
->formatStateUsing(fn (Database $record) => $record->remote === '%' ? 'Anywhere ( % )' : $record->remote)
|
||||
->columnSpan(1)
|
||||
->label('Connections From'),
|
||||
->label(trans('admin/databasehost.table.remote')),
|
||||
TextInput::make('max_connections')
|
||||
->label(trans('admin/databasehost.table.max_connections'))
|
||||
->disabled()
|
||||
->formatStateUsing(fn (Database $record) => $record->max_connections === 0 ? 'Unlimited' : $record->max_connections)
|
||||
->columnSpan(1),
|
||||
@ -697,7 +706,7 @@ class EditServer extends EditRecord
|
||||
->disabled()
|
||||
->password()
|
||||
->revealable()
|
||||
->label('JDBC Connection String')
|
||||
->label(trans('admin/databasehost.table.connection_string'))
|
||||
->columnSpan(2)
|
||||
->formatStateUsing(fn (Database $record) => $record->jdbc),
|
||||
])
|
||||
@ -709,9 +718,9 @@ class EditServer extends EditRecord
|
||||
Action::make('createDatabase')
|
||||
->authorize(fn () => auth()->user()->can('create database'))
|
||||
->disabled(fn () => DatabaseHost::query()->count() < 1)
|
||||
->label(fn () => DatabaseHost::query()->count() < 1 ? 'No Database Hosts' : 'Create Database')
|
||||
->label(fn () => DatabaseHost::query()->count() < 1 ? trans('admin/server.no_db_hosts') : trans('admin/server.create_database'))
|
||||
->color(fn () => DatabaseHost::query()->count() < 1 ? 'danger' : 'primary')
|
||||
->modalSubmitActionLabel('Create Database')
|
||||
->modalSubmitActionLabel(trans('admin/server.create_database'))
|
||||
->action(function (array $data, DatabaseManagementService $service, Server $server, RandomWordService $randomWordService) {
|
||||
if (empty($data['database'])) {
|
||||
$data['database'] = $randomWordService->word() . random_int(1, 420);
|
||||
@ -726,7 +735,7 @@ class EditServer extends EditRecord
|
||||
$service->setValidateDatabaseLimit(false)->create($server, $data);
|
||||
} catch (Exception $e) {
|
||||
Notification::make()
|
||||
->title('Failed to Create Database')
|
||||
->title(trans('admin/server.failed_to_create'))
|
||||
->body($e->getMessage())
|
||||
->danger()
|
||||
->persistent()->send();
|
||||
@ -735,7 +744,7 @@ class EditServer extends EditRecord
|
||||
})
|
||||
->form([
|
||||
Select::make('database_host_id')
|
||||
->label('Database Host')
|
||||
->label(trans('admin/databasehost.table.name'))
|
||||
->required()
|
||||
->placeholder('Select Database Host')
|
||||
->options(fn (Server $server) => DatabaseHost::query()
|
||||
@ -745,24 +754,24 @@ class EditServer extends EditRecord
|
||||
->default(fn () => (DatabaseHost::query()->first())?->id)
|
||||
->selectablePlaceholder(false),
|
||||
TextInput::make('database')
|
||||
->label('Database Name')
|
||||
->label(trans('admin/server.name'))
|
||||
->alphaDash()
|
||||
->prefix(fn (Server $server) => 's' . $server->id . '_')
|
||||
->hintIcon('tabler-question-mark')
|
||||
->hintIconTooltip('Leaving this blank will auto generate a random name'),
|
||||
->hintIconTooltip(trans('admin/databasehost.table.name_helper')),
|
||||
TextInput::make('remote')
|
||||
->columnSpan(1)
|
||||
->regex('/^[\w\-\/.%:]+$/')
|
||||
->label('Connections From')
|
||||
->label(trans('admin/databasehost.table.remote'))
|
||||
->hintIcon('tabler-question-mark')
|
||||
->hintIconTooltip('Where connections should be allowed from. Leave blank to allow connections from anywhere.'),
|
||||
->hintIconTooltip(trans('admin/databasehost.table.remote_helper')),
|
||||
]),
|
||||
])->alignCenter()->columnSpanFull(),
|
||||
]),
|
||||
Tab::make('Actions')
|
||||
Tab::make(trans('admin/server.actions'))
|
||||
->icon('tabler-settings')
|
||||
->schema([
|
||||
Fieldset::make('Server Actions')
|
||||
Fieldset::make(trans('admin/server.actions'))
|
||||
->columns([
|
||||
'default' => 1,
|
||||
'sm' => 2,
|
||||
@ -775,7 +784,7 @@ class EditServer extends EditRecord
|
||||
->schema([
|
||||
Forms\Components\Actions::make([
|
||||
Action::make('toggleInstall')
|
||||
->label('Toggle Install Status')
|
||||
->label(trans('admin/server.toggle_install'))
|
||||
->disabled(fn (Server $server) => $server->isSuspended())
|
||||
->action(function (ToggleInstallService $service, Server $server) {
|
||||
$service->handle($server);
|
||||
@ -784,54 +793,54 @@ class EditServer extends EditRecord
|
||||
}),
|
||||
])->fullWidth(),
|
||||
ToggleButtons::make('')
|
||||
->hint('If you need to change the install status from uninstalled to installed, or vice versa, you may do so with this button.'),
|
||||
->hint(trans('admin/server.toggle_install_help')),
|
||||
]),
|
||||
Grid::make()
|
||||
->columnSpan(3)
|
||||
->schema([
|
||||
Forms\Components\Actions::make([
|
||||
Action::make('toggleSuspend')
|
||||
->label('Suspend')
|
||||
->label(trans('admin/server.suspend'))
|
||||
->color('warning')
|
||||
->hidden(fn (Server $server) => $server->isSuspended())
|
||||
->action(function (SuspensionService $suspensionService, Server $server) {
|
||||
try {
|
||||
$suspensionService->handle($server, SuspendAction::Suspend);
|
||||
} catch (\Exception $exception) {
|
||||
Notification::make()->warning()->title('Server Suspension')->body($exception->getMessage())->send();
|
||||
Notification::make()->warning()->title(trans('admin/server.notifications.server_suspension'))->body($exception->getMessage())->send();
|
||||
}
|
||||
Notification::make()->success()->title('Server Suspended!')->send();
|
||||
Notification::make()->success()->title(trans('admin/server.notifications.server_suspended'))->send();
|
||||
|
||||
$this->refreshFormData(['status', 'docker']);
|
||||
}),
|
||||
Action::make('toggleUnsuspend')
|
||||
->label('Unsuspend')
|
||||
->label(trans('admin/server.unsuspend'))
|
||||
->color('success')
|
||||
->hidden(fn (Server $server) => !$server->isSuspended())
|
||||
->action(function (SuspensionService $suspensionService, Server $server) {
|
||||
try {
|
||||
$suspensionService->handle($server, SuspendAction::Unsuspend);
|
||||
} catch (\Exception $exception) {
|
||||
Notification::make()->warning()->title('Server Suspension')->body($exception->getMessage())->send();
|
||||
Notification::make()->warning()->title(trans('admin/server.notifications.server_suspension'))->body($exception->getMessage())->send();
|
||||
}
|
||||
Notification::make()->success()->title('Server Unsuspended!')->send();
|
||||
Notification::make()->success()->title(trans('admin/server.notifications.server_unsuspended'))->send();
|
||||
|
||||
$this->refreshFormData(['status', 'docker']);
|
||||
}),
|
||||
])->fullWidth(),
|
||||
ToggleButtons::make('')
|
||||
->hidden(fn (Server $server) => $server->isSuspended())
|
||||
->hint('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.'),
|
||||
->hint(trans('admin/server.notifications.server_suspend_help')),
|
||||
ToggleButtons::make('')
|
||||
->hidden(fn (Server $server) => !$server->isSuspended())
|
||||
->hint('This will unsuspend the server and restore normal user access.'),
|
||||
->hint(trans('admin/server.notifications.server_unsuspend_help')),
|
||||
]),
|
||||
Grid::make()
|
||||
->columnSpan(3)
|
||||
->schema([
|
||||
Forms\Components\Actions::make([
|
||||
Action::make('transfer')
|
||||
->label('Transfer Soon™')
|
||||
->label(trans('admin/server.transfer'))
|
||||
->action(fn (TransferServerService $transfer, Server $server) => $transfer->handle($server, []))
|
||||
->disabled() //TODO!
|
||||
->form([ //TODO!
|
||||
@ -856,26 +865,26 @@ class EditServer extends EditRecord
|
||||
false => 'off',
|
||||
]),
|
||||
])
|
||||
->modalHeading('Transfer'),
|
||||
->modalheading(trans('admin/server.transfer')),
|
||||
])->fullWidth(),
|
||||
ToggleButtons::make('')
|
||||
->hint('Transfer this server to another node connected to this panel. Warning! This feature has not been fully tested and may have bugs.'),
|
||||
->hint(trans('admin/server.transfer_help')),
|
||||
]),
|
||||
Grid::make()
|
||||
->columnSpan(3)
|
||||
->schema([
|
||||
Forms\Components\Actions::make([
|
||||
Action::make('reinstall')
|
||||
->label('Reinstall')
|
||||
->label(trans('admin/server.reinstall'))
|
||||
->color('danger')
|
||||
->requiresConfirmation()
|
||||
->modalHeading('Are you sure you want to reinstall this server?')
|
||||
->modalDescription('!! This can result in unrecoverable data loss !!')
|
||||
->modalHeading(trans('admin/server.reinstall_modal_heading'))
|
||||
->modalDescription(trans('admin/server.reinstall_modal_description'))
|
||||
->disabled(fn (Server $server) => $server->isSuspended())
|
||||
->action(fn (ReinstallServerService $service, Server $server) => $service->handle($server)),
|
||||
])->fullWidth(),
|
||||
ToggleButtons::make('')
|
||||
->hint('This will reinstall the server with the assigned egg install script.'),
|
||||
->hint(trans('admin/server.reinstall_help')),
|
||||
]),
|
||||
]),
|
||||
]),
|
||||
@ -902,7 +911,7 @@ class EditServer extends EditRecord
|
||||
Actions\Action::make('Delete')
|
||||
->successRedirectUrl(route('filament.admin.resources.servers.index'))
|
||||
->color('danger')
|
||||
->label('Delete')
|
||||
->label(trans('filament-actions::delete.single.modal.actions.delete.label'))
|
||||
->requiresConfirmation()
|
||||
->action(function (Server $server, ServerDeletionService $service) {
|
||||
$service->handle($server);
|
||||
@ -911,7 +920,7 @@ class EditServer extends EditRecord
|
||||
})
|
||||
->authorize(fn (Server $server) => auth()->user()->can('delete server', $server)),
|
||||
Actions\Action::make('console')
|
||||
->label('Console')
|
||||
->label(trans('admin/server.console'))
|
||||
->icon('tabler-terminal')
|
||||
->url(fn (Server $server) => Console::getUrl(panel: 'server', tenant: $server)),
|
||||
$this->getSaveFormAction()->formId('form'),
|
||||
|
@ -31,6 +31,7 @@ class ListServers extends ListRecords
|
||||
])
|
||||
->columns([
|
||||
TextColumn::make('condition')
|
||||
->label(trans('admin/server.condition'))
|
||||
->default('unknown')
|
||||
->badge()
|
||||
->icon(fn (Server $server) => $server->conditionIcon())
|
||||
@ -40,10 +41,12 @@ class ListServers extends ListRecords
|
||||
->label('UUID')
|
||||
->searchable(),
|
||||
TextColumn::make('name')
|
||||
->label(trans('admin/server.name'))
|
||||
->icon('tabler-brand-docker')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
TextColumn::make('node.name')
|
||||
->label(trans('admin/server.node'))
|
||||
->icon('tabler-server-2')
|
||||
->url(fn (Server $server): string => route('filament.admin.resources.nodes.edit', ['record' => $server->node]))
|
||||
->hidden(fn (Table $table) => $table->getGrouping()?->getId() === 'node.name')
|
||||
@ -51,37 +54,39 @@ class ListServers extends ListRecords
|
||||
->searchable(),
|
||||
TextColumn::make('egg.name')
|
||||
->icon('tabler-egg')
|
||||
->label(trans('admin/server.egg'))
|
||||
->url(fn (Server $server): string => route('filament.admin.resources.eggs.edit', ['record' => $server->egg]))
|
||||
->hidden(fn (Table $table) => $table->getGrouping()?->getId() === 'egg.name')
|
||||
->sortable()
|
||||
->searchable(),
|
||||
TextColumn::make('user.username')
|
||||
->icon('tabler-user')
|
||||
->label('Owner')
|
||||
->label(trans('admin/user.username'))
|
||||
->url(fn (Server $server): string => route('filament.admin.resources.users.edit', ['record' => $server->user]))
|
||||
->hidden(fn (Table $table) => $table->getGrouping()?->getId() === 'user.username')
|
||||
->sortable()
|
||||
->searchable(),
|
||||
SelectColumn::make('allocation_id')
|
||||
->label('Primary Allocation')
|
||||
->label(trans('admin/server.primary_allocation'))
|
||||
->hidden(!auth()->user()->can('update server'))
|
||||
->options(fn (Server $server) => $server->allocations->mapWithKeys(fn ($allocation) => [$allocation->id => $allocation->address]))
|
||||
->selectablePlaceholder(false)
|
||||
->sortable(),
|
||||
TextColumn::make('allocation_id_readonly')
|
||||
->label('Primary Allocation')
|
||||
->label(trans('admin/server.primary_allocation'))
|
||||
->hidden(auth()->user()->can('update server'))
|
||||
->state(fn (Server $server) => $server->allocation->address),
|
||||
TextColumn::make('image')->hidden(),
|
||||
TextColumn::make('backups_count')
|
||||
->counts('backups')
|
||||
->label('Backups')
|
||||
->label(trans('admin/server.backups'))
|
||||
->icon('tabler-file-download')
|
||||
->numeric()
|
||||
->sortable(),
|
||||
])
|
||||
->actions([
|
||||
Action::make('View')
|
||||
->label(trans('admin/server.view'))
|
||||
->icon('tabler-terminal')
|
||||
->url(fn (Server $server) => Console::getUrl(panel: 'server', tenant: $server))
|
||||
->authorize(fn (Server $server) => auth()->user()->canAccessTenant($server)),
|
||||
@ -90,10 +95,10 @@ class ListServers extends ListRecords
|
||||
->emptyStateIcon('tabler-brand-docker')
|
||||
->searchable()
|
||||
->emptyStateDescription('')
|
||||
->emptyStateHeading('No Servers')
|
||||
->emptyStateHeading(trans('admin/server.no_servers'))
|
||||
->emptyStateActions([
|
||||
CreateAction::make('create')
|
||||
->label('Create Server')
|
||||
->label(trans('admin/server.create_action', ['action' => trans('filament-actions::create.single.modal.actions.create.label')]))
|
||||
->button(),
|
||||
]);
|
||||
}
|
||||
@ -102,7 +107,7 @@ class ListServers extends ListRecords
|
||||
{
|
||||
return [
|
||||
Actions\CreateAction::make()
|
||||
->label('Create Server')
|
||||
->label(trans('admin/server.create_action', ['action' => trans('filament-actions::create.single.modal.actions.create.label')]))
|
||||
->hidden(fn () => Server::count() <= 0),
|
||||
];
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ use App\Services\Allocations\AssignmentService;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Components\TagsInput;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Forms\Get;
|
||||
use Filament\Forms\Set;
|
||||
use Filament\Resources\RelationManagers\RelationManager;
|
||||
@ -21,7 +20,6 @@ use Filament\Tables\Columns\IconColumn;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Columns\TextInputColumn;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Support\HtmlString;
|
||||
|
||||
/**
|
||||
* @method Server getOwnerRecord()
|
||||
@ -30,16 +28,6 @@ class AllocationsRelationManager extends RelationManager
|
||||
{
|
||||
protected static string $relationship = 'allocations';
|
||||
|
||||
public function form(Form $form): Form
|
||||
{
|
||||
return $form
|
||||
->schema([
|
||||
TextInput::make('ip')
|
||||
->required()
|
||||
->maxLength(255),
|
||||
]);
|
||||
}
|
||||
|
||||
public function table(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
@ -48,10 +36,11 @@ class AllocationsRelationManager extends RelationManager
|
||||
->recordTitle(fn (Allocation $allocation) => "$allocation->ip:$allocation->port")
|
||||
->checkIfRecordIsSelectableUsing(fn (Allocation $record) => $record->id !== $this->getOwnerRecord()->allocation_id)
|
||||
->inverseRelationship('server')
|
||||
->heading(trans('admin/server.allocations'))
|
||||
->columns([
|
||||
TextColumn::make('ip')->label('IP'),
|
||||
TextColumn::make('port')->label('Port'),
|
||||
TextInputColumn::make('ip_alias')->label('Alias'),
|
||||
TextColumn::make('ip')->label(trans('admin/server.ip_address')),
|
||||
TextColumn::make('port')->label(trans('admin/server.port')),
|
||||
TextInputColumn::make('ip_alias')->label(trans('admin/server.alias')),
|
||||
IconColumn::make('primary')
|
||||
->icon(fn ($state) => match ($state) {
|
||||
true => 'tabler-star-filled',
|
||||
@ -63,39 +52,33 @@ class AllocationsRelationManager extends RelationManager
|
||||
})
|
||||
->action(fn (Allocation $allocation) => $this->getOwnerRecord()->update(['allocation_id' => $allocation->id]) && $this->deselectAllTableRecords())
|
||||
->default(fn (Allocation $allocation) => $allocation->id === $this->getOwnerRecord()->allocation_id)
|
||||
->label('Primary'),
|
||||
->label(trans('admin/server.primary')),
|
||||
])
|
||||
->actions([
|
||||
Action::make('make-primary')
|
||||
->action(fn (Allocation $allocation) => $this->getOwnerRecord()->update(['allocation_id' => $allocation->id]) && $this->deselectAllTableRecords())
|
||||
->label(fn (Allocation $allocation) => $allocation->id === $this->getOwnerRecord()->allocation_id ? '' : 'Make Primary'),
|
||||
->label(fn (Allocation $allocation) => $allocation->id === $this->getOwnerRecord()->allocation_id ? '' : trans('admin/server.make_primary')),
|
||||
])
|
||||
->headerActions([
|
||||
CreateAction::make()->label('Create Allocation')
|
||||
CreateAction::make()->label(trans('admin/node.create_allocations'))
|
||||
->createAnother(false)
|
||||
->form(fn () => [
|
||||
Select::make('allocation_ip')
|
||||
->options(collect($this->getOwnerRecord()->node->ipAddresses())->mapWithKeys(fn (string $ip) => [$ip => $ip]))
|
||||
->label('IP Address')
|
||||
->label(trans('admin/server.ip_address'))
|
||||
->inlineLabel()
|
||||
->ipv4()
|
||||
->helperText("Usually your machine's public IP unless you are port forwarding.")
|
||||
->afterStateUpdated(fn (Set $set) => $set('allocation_ports', []))
|
||||
->required(),
|
||||
TextInput::make('allocation_alias')
|
||||
->label('Alias')
|
||||
->label(trans('admin/server.alias'))
|
||||
->inlineLabel()
|
||||
->default(null)
|
||||
->helperText('Optional display name to help you remember what these are.')
|
||||
->helperText(trans('admin/server.alias_helper'))
|
||||
->required(false),
|
||||
TagsInput::make('allocation_ports')
|
||||
->placeholder('Examples: 27015, 27017-27019')
|
||||
->helperText(new HtmlString('
|
||||
These are the ports that users can connect to this Server through.
|
||||
<br />
|
||||
You would have to port forward these on your home network.
|
||||
'))
|
||||
->label('Ports')
|
||||
->placeholder('27015, 27017-27019')
|
||||
->label(trans('admin/server.ports'))
|
||||
->inlineLabel()
|
||||
->live()
|
||||
->afterStateUpdated(fn ($state, Set $set, Get $get) => $set('allocation_ports',
|
||||
@ -111,7 +94,7 @@ class AllocationsRelationManager extends RelationManager
|
||||
->preloadRecordSelect()
|
||||
->recordSelectOptionsQuery(fn ($query) => $query->whereBelongsTo($this->getOwnerRecord()->node)->whereNull('server_id'))
|
||||
->recordSelectSearchColumns(['ip', 'port'])
|
||||
->label('Add Allocation'),
|
||||
->label(trans('admin/server.add_allocations')),
|
||||
])
|
||||
->bulkActions([
|
||||
Tables\Actions\BulkActionGroup::make([
|
||||
|
@ -13,10 +13,28 @@ class UserResource extends Resource
|
||||
|
||||
protected static ?string $navigationIcon = 'tabler-users';
|
||||
|
||||
protected static ?string $navigationGroup = 'User';
|
||||
|
||||
protected static ?string $recordTitleAttribute = 'username';
|
||||
|
||||
public static function getNavigationLabel(): string
|
||||
{
|
||||
return trans('admin/user.nav_title');
|
||||
}
|
||||
|
||||
public static function getModelLabel(): string
|
||||
{
|
||||
return trans('admin/user.model_label');
|
||||
}
|
||||
|
||||
public static function getPluralModelLabel(): string
|
||||
{
|
||||
return trans('admin/user.model_label_plural');
|
||||
}
|
||||
|
||||
public static function getNavigationGroup(): ?string
|
||||
{
|
||||
return trans('admin/dashboard.user');
|
||||
}
|
||||
|
||||
public static function getNavigationBadge(): ?string
|
||||
{
|
||||
return static::getModel()::count() ?: null;
|
||||
|
@ -30,25 +30,28 @@ class CreateUser extends CreateRecord
|
||||
->columns(['default' => 1, 'lg' => 3])
|
||||
->schema([
|
||||
TextInput::make('username')
|
||||
->label(trans('admin/user.username'))
|
||||
->alphaNum()
|
||||
->required()
|
||||
->unique()
|
||||
->minLength(3)
|
||||
->maxLength(255),
|
||||
TextInput::make('email')
|
||||
->label(trans('admin/user.email'))
|
||||
->email()
|
||||
->required()
|
||||
->unique()
|
||||
->maxLength(255),
|
||||
TextInput::make('password')
|
||||
->label(trans('admin/user.password'))
|
||||
->hintIcon('tabler-question-mark')
|
||||
->hintIconTooltip('Providing a user password is optional. New user email will prompt users to create a password the first time they login.')
|
||||
->hintIconTooltip(trans('admin/user.password_help'))
|
||||
->password(),
|
||||
CheckboxList::make('roles')
|
||||
->disableOptionWhen(fn (string $value): bool => $value == Role::getRootAdmin()->id)
|
||||
->relationship('roles', 'name')
|
||||
->dehydrated()
|
||||
->label('Admin Roles')
|
||||
->label(trans('admin/user.admin_roles'))
|
||||
->columnSpanFull()
|
||||
->bulkToggleable(false),
|
||||
]);
|
||||
|
@ -5,12 +5,10 @@ namespace App\Filament\Admin\Resources\UserResource\Pages;
|
||||
use App\Filament\Admin\Resources\UserResource;
|
||||
use App\Models\Role;
|
||||
use App\Models\User;
|
||||
use App\Services\Helpers\LanguageService;
|
||||
use Filament\Actions\DeleteAction;
|
||||
use Filament\Forms\Components\CheckboxList;
|
||||
use Filament\Forms\Components\Hidden;
|
||||
use Filament\Forms\Components\Section;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Resources\Pages\EditRecord;
|
||||
@ -26,29 +24,27 @@ class EditUser extends EditRecord
|
||||
->schema([
|
||||
Section::make()->schema([
|
||||
TextInput::make('username')
|
||||
->label(trans('admin/user.username'))
|
||||
->required()
|
||||
->minLength(3)
|
||||
->maxLength(255),
|
||||
TextInput::make('email')
|
||||
->label(trans('admin/user.email'))
|
||||
->email()
|
||||
->required()
|
||||
->maxLength(255),
|
||||
TextInput::make('password')
|
||||
->label(trans('admin/user.password'))
|
||||
->dehydrateStateUsing(fn (string $state): string => Hash::make($state))
|
||||
->dehydrated(fn (?string $state): bool => filled($state))
|
||||
->password(),
|
||||
Select::make('language')
|
||||
->required()
|
||||
->hidden()
|
||||
->default('en')
|
||||
->options(fn (LanguageService $languageService) => $languageService->getAvailableLanguages()),
|
||||
Hidden::make('skipValidation')
|
||||
->default(true),
|
||||
CheckboxList::make('roles')
|
||||
->disabled(fn (User $user) => $user->id === auth()->user()->id)
|
||||
->disableOptionWhen(fn (string $value): bool => $value == Role::getRootAdmin()->id)
|
||||
->relationship('roles', 'name')
|
||||
->label('Admin Roles')
|
||||
->label(trans('admin/user.admin_roles'))
|
||||
->columnSpanFull()
|
||||
->bulkToggleable(false),
|
||||
])
|
||||
@ -60,7 +56,7 @@ class EditUser extends EditRecord
|
||||
{
|
||||
return [
|
||||
DeleteAction::make()
|
||||
->label(fn (User $user) => auth()->user()->id === $user->id ? 'Can\'t Delete Yourself' : ($user->servers()->count() > 0 ? 'User Has Servers' : 'Delete'))
|
||||
->label(fn (User $user) => auth()->user()->id === $user->id ? trans('admin/user.self_delete') : ($user->servers()->count() > 0 ? trans('admin/user.has_servers') : trans('filament-actions::delete.single.modal.actions.delete.label')))
|
||||
->disabled(fn (User $user) => auth()->user()->id === $user->id || $user->servers()->count() > 0),
|
||||
$this->getSaveFormAction()->formId('form'),
|
||||
];
|
||||
|
@ -36,8 +36,10 @@ class ListUsers extends ListRecords
|
||||
->hidden()
|
||||
->searchable(),
|
||||
TextColumn::make('username')
|
||||
->label(trans('admin/user.username'))
|
||||
->searchable(),
|
||||
TextColumn::make('email')
|
||||
->label(trans('admin/user.email'))
|
||||
->searchable()
|
||||
->icon('tabler-mail'),
|
||||
IconColumn::make('use_totp')
|
||||
@ -47,17 +49,17 @@ class ListUsers extends ListRecords
|
||||
->boolean()
|
||||
->sortable(),
|
||||
TextColumn::make('roles.name')
|
||||
->label('Roles')
|
||||
->label(trans('admin/user.roles'))
|
||||
->badge()
|
||||
->icon('tabler-users-group')
|
||||
->placeholder('No roles'),
|
||||
->placeholder(trans('admin/user.no_roles')),
|
||||
TextColumn::make('servers_count')
|
||||
->counts('servers')
|
||||
->icon('tabler-server')
|
||||
->label('Servers'),
|
||||
->label(trans('admin/user.servers')),
|
||||
TextColumn::make('subusers_count')
|
||||
->visibleFrom('sm')
|
||||
->label('Subusers')
|
||||
->label(trans('admin/user.subusers'))
|
||||
->counts('subusers')
|
||||
->icon('tabler-users'),
|
||||
])
|
||||
@ -77,7 +79,7 @@ class ListUsers extends ListRecords
|
||||
{
|
||||
return [
|
||||
CreateAction::make()
|
||||
->label('Create User'),
|
||||
->label(trans('admin/user.create_action', ['action' => trans('filament-actions::create.single.modal.actions.create.label')])),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ class ServersRelationManager extends RelationManager
|
||||
|
||||
return $table
|
||||
->searchable(false)
|
||||
->heading(trans('admin/user.servers'))
|
||||
->headerActions([
|
||||
Actions\Action::make('toggleSuspend')
|
||||
->hidden(fn () => $user->servers()
|
||||
@ -31,7 +32,7 @@ class ServersRelationManager extends RelationManager
|
||||
->orWhereNull('status')
|
||||
->count() === 0
|
||||
)
|
||||
->label('Suspend All Servers')
|
||||
->label(trans('admin/server.suspend_all'))
|
||||
->color('warning')
|
||||
->action(function (SuspensionService $suspensionService) use ($user) {
|
||||
collect($user->servers)->filter(fn ($server) => !$server->isSuspended())
|
||||
@ -39,7 +40,7 @@ class ServersRelationManager extends RelationManager
|
||||
}),
|
||||
Actions\Action::make('toggleUnsuspend')
|
||||
->hidden(fn () => $user->servers()->where('status', ServerState::Suspended)->count() === 0)
|
||||
->label('Unsuspend All Servers')
|
||||
->label(trans('admin/server.unsuspend_all'))
|
||||
->color('primary')
|
||||
->action(function (SuspensionService $suspensionService) use ($user) {
|
||||
collect($user->servers()->get())->filter(fn ($server) => $server->isSuspended())
|
||||
@ -53,33 +54,35 @@ class ServersRelationManager extends RelationManager
|
||||
->searchable(),
|
||||
TextColumn::make('name')
|
||||
->icon('tabler-brand-docker')
|
||||
->label(trans('strings.name'))
|
||||
->label(trans('admin/server.name'))
|
||||
->url(fn (Server $server): string => route('filament.admin.resources.servers.edit', ['record' => $server]))
|
||||
->searchable()
|
||||
->sortable(),
|
||||
TextColumn::make('node.name')
|
||||
->label('admin/server.node')
|
||||
->icon('tabler-server-2')
|
||||
->url(fn (Server $server): string => route('filament.admin.resources.nodes.edit', ['record' => $server->node]))
|
||||
->sortable(),
|
||||
TextColumn::make('egg.name')
|
||||
->label(trans('admin/server.egg'))
|
||||
->icon('tabler-egg')
|
||||
->url(fn (Server $server): string => route('filament.admin.resources.eggs.edit', ['record' => $server->egg]))
|
||||
->sortable(),
|
||||
SelectColumn::make('allocation.id')
|
||||
->label('Primary Allocation')
|
||||
->label(trans('admin/server.primary_allocation'))
|
||||
->options(fn (Server $server) => [$server->allocation->id => $server->allocation->address])
|
||||
->selectablePlaceholder(false)
|
||||
->sortable(),
|
||||
TextColumn::make('image')->hidden(),
|
||||
TextColumn::make('databases_count')
|
||||
->counts('databases')
|
||||
->label('Databases')
|
||||
->label(trans('admin/server.databases'))
|
||||
->icon('tabler-database')
|
||||
->numeric()
|
||||
->sortable(),
|
||||
TextColumn::make('backups_count')
|
||||
->counts('backups')
|
||||
->label('Backups')
|
||||
->label(trans('admin/server.backups'))
|
||||
->icon('tabler-file-download')
|
||||
->numeric()
|
||||
->sortable(),
|
||||
|
@ -10,21 +10,35 @@ class WebhookResource extends Resource
|
||||
{
|
||||
protected static ?string $model = WebhookConfiguration::class;
|
||||
|
||||
protected static ?string $modelLabel = 'Webhook';
|
||||
|
||||
protected static ?string $pluralModelLabel = 'Webhooks';
|
||||
|
||||
protected static ?string $navigationIcon = 'tabler-webhook';
|
||||
|
||||
protected static ?string $navigationGroup = 'Advanced';
|
||||
|
||||
protected static ?string $recordTitleAttribute = 'description';
|
||||
|
||||
public static function getNavigationLabel(): string
|
||||
{
|
||||
return trans('admin/webhook.nav_title');
|
||||
}
|
||||
|
||||
public static function getModelLabel(): string
|
||||
{
|
||||
return trans('admin/webhook.model_label');
|
||||
}
|
||||
|
||||
public static function getPluralModelLabel(): string
|
||||
{
|
||||
return trans('admin/webhook.model_label_plural');
|
||||
}
|
||||
|
||||
public static function getNavigationBadge(): ?string
|
||||
{
|
||||
return static::getModel()::count() ?: null;
|
||||
}
|
||||
|
||||
public static function getNavigationGroup(): ?string
|
||||
{
|
||||
return trans('admin/dashboard.advanced');
|
||||
}
|
||||
|
||||
public static function getPages(): array
|
||||
{
|
||||
return [
|
||||
|
@ -32,11 +32,14 @@ class CreateWebhookConfiguration extends CreateRecord
|
||||
return $form
|
||||
->schema([
|
||||
TextInput::make('endpoint')
|
||||
->label(trans('admin/webhooks.endpoint'))
|
||||
->activeUrl()
|
||||
->required(),
|
||||
TextInput::make('description')
|
||||
->label(trans('admin/webhooks.description'))
|
||||
->required(),
|
||||
CheckboxList::make('events')
|
||||
->label(trans('admin/webhooks.events'))
|
||||
->lazy()
|
||||
->options(fn () => WebhookConfiguration::filamentCheckboxList())
|
||||
->searchable()
|
||||
|
@ -19,14 +19,14 @@ class EditWebhookConfiguration extends EditRecord
|
||||
return $form
|
||||
->schema([
|
||||
TextInput::make('endpoint')
|
||||
->label('Endpoint')
|
||||
->label(trans('admin/webhook.endpoint'))
|
||||
->activeUrl()
|
||||
->required(),
|
||||
TextInput::make('description')
|
||||
->label('Description')
|
||||
->label(trans('admin/webhook.description'))
|
||||
->required(),
|
||||
CheckboxList::make('events')
|
||||
->label('Events')
|
||||
->label(trans('admin/webhook.events'))
|
||||
->lazy()
|
||||
->options(fn () => WebhookConfiguration::filamentCheckboxList())
|
||||
->searchable()
|
||||
@ -46,11 +46,7 @@ class EditWebhookConfiguration extends EditRecord
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
Actions\DeleteAction::make()
|
||||
->label('Delete')
|
||||
->modalHeading('Are you sure you want to delete this?')
|
||||
->modalDescription('')
|
||||
->modalSubmitActionLabel('Delete'),
|
||||
Actions\DeleteAction::make(),
|
||||
$this->getSaveFormAction()->formId('form'),
|
||||
];
|
||||
}
|
||||
|
@ -21,22 +21,20 @@ class ListWebhookConfigurations extends ListRecords
|
||||
return $table
|
||||
->columns([
|
||||
TextColumn::make('description')
|
||||
->label('Description'),
|
||||
->label(trans('admin/webhook.table.description')),
|
||||
TextColumn::make('endpoint')
|
||||
->label('Endpoint'),
|
||||
->label(trans('admin/webhook.table.endpoint')),
|
||||
])
|
||||
->actions([
|
||||
DeleteAction::make()
|
||||
->label('Delete'),
|
||||
EditAction::make()
|
||||
->label('Edit'),
|
||||
DeleteAction::make(),
|
||||
EditAction::make(),
|
||||
])
|
||||
->emptyStateIcon('tabler-webhook')
|
||||
->emptyStateDescription('')
|
||||
->emptyStateHeading('No Webhooks')
|
||||
->emptyStateHeading(trans('admin/webhook.no_webhooks'))
|
||||
->emptyStateActions([
|
||||
CreateAction::make('create')
|
||||
->label('Create Webhook')
|
||||
->label(trans('admin/webhook.create_action', ['action' => trans('filament-actions::create.single.modal.actions.create.label')]))
|
||||
->button(),
|
||||
]);
|
||||
}
|
||||
@ -45,7 +43,7 @@ class ListWebhookConfigurations extends ListRecords
|
||||
{
|
||||
return [
|
||||
Actions\CreateAction::make()
|
||||
->label('Create Webhook')
|
||||
->label(trans('admin/webhook.create_action', ['action' => trans('filament-actions::create.single.modal.actions.create.label')]))
|
||||
->hidden(fn () => WebhookConfiguration::count() <= 0),
|
||||
];
|
||||
}
|
||||
|
@ -31,23 +31,23 @@ class ImportEggAction extends Action
|
||||
Tabs::make('Tabs')
|
||||
->contained(false)
|
||||
->tabs([
|
||||
Tab::make('From File')
|
||||
Tab::make(trans('admin/egg.import.file'))
|
||||
->icon('tabler-file-upload')
|
||||
->schema([
|
||||
FileUpload::make('egg')
|
||||
->label('Egg')
|
||||
->hint('This should be the json file ( egg-minecraft.json )')
|
||||
->hint(trans('admin/egg.import.egg_help'))
|
||||
->acceptedFileTypes(['application/json'])
|
||||
->storeFiles(false)
|
||||
->multiple(),
|
||||
]),
|
||||
Tab::make('From URL')
|
||||
Tab::make(trans('admin/egg.import.url'))
|
||||
->icon('tabler-world-upload')
|
||||
->schema([
|
||||
TextInput::make('url')
|
||||
->label('URL')
|
||||
->hint('This URL should point to a single json file')
|
||||
->default(fn (Egg $egg) => $egg->update_url)
|
||||
->label(trans('admin/egg.import.url'))
|
||||
->hint(trans('admin/egg.import.url_help'))
|
||||
->url(),
|
||||
]),
|
||||
]),
|
||||
@ -68,7 +68,7 @@ class ImportEggAction extends Action
|
||||
}
|
||||
} catch (Exception $exception) {
|
||||
Notification::make()
|
||||
->title('Import Failed')
|
||||
->title(trans('admin/egg.import.import_failed'))
|
||||
->body($exception->getMessage())
|
||||
->danger()
|
||||
->send();
|
||||
@ -79,7 +79,7 @@ class ImportEggAction extends Action
|
||||
}
|
||||
|
||||
Notification::make()
|
||||
->title('Import Success')
|
||||
->title(trans('admin/egg.import.import_success'))
|
||||
->success()
|
||||
->send();
|
||||
});
|
||||
|
@ -21,13 +21,13 @@ class RotateDatabasePasswordAction extends Action
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->label('Rotate');
|
||||
$this->label(trans('admin/databasehost.rotate'));
|
||||
|
||||
$this->icon('tabler-refresh');
|
||||
|
||||
$this->authorize(fn (Database $database) => auth()->user()->can('update database', $database));
|
||||
|
||||
$this->modalHeading('Rotate Password');
|
||||
$this->modalHeading(trans('admin/databasehost.rotate_password'));
|
||||
|
||||
$this->modalIconColor('warning');
|
||||
|
||||
@ -45,12 +45,12 @@ class RotateDatabasePasswordAction extends Action
|
||||
$set('jdbc', $database->jdbc);
|
||||
|
||||
Notification::make()
|
||||
->title('Password rotated')
|
||||
->title(trans('admin/databasehost.rotated'))
|
||||
->success()
|
||||
->send();
|
||||
} catch (Exception $exception) {
|
||||
Notification::make()
|
||||
->title('Password rotation failed')
|
||||
->title(trans('admin/databasehost.rotate_error'))
|
||||
->body($exception->getMessage())
|
||||
->danger()
|
||||
->send();
|
||||
|
@ -17,7 +17,7 @@ class ExportEggAction extends Action
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->label('Export');
|
||||
$this->label(trans('filament-actions::export.modal.actions.export.label'));
|
||||
|
||||
$this->icon('tabler-download');
|
||||
|
||||
|
@ -22,30 +22,30 @@ class ImportEggAction extends Action
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->label('Import');
|
||||
$this->label(trans('filament-actions::import.modal.actions.import.label'));
|
||||
|
||||
$this->authorize(fn () => auth()->user()->can('import egg'));
|
||||
|
||||
$this->form([
|
||||
Tabs::make('Tabs')
|
||||
Tabs::make()
|
||||
->contained(false)
|
||||
->tabs([
|
||||
Tab::make('From File')
|
||||
Tab::make(trans('admin/egg.import.file'))
|
||||
->icon('tabler-file-upload')
|
||||
->schema([
|
||||
FileUpload::make('egg')
|
||||
->label('Egg')
|
||||
->hint('This should be the json file ( egg-minecraft.json )')
|
||||
->label(trans('admin/egg.model_label'))
|
||||
->hint(trans('admin/egg.import.egg_help'))
|
||||
->acceptedFileTypes(['application/json'])
|
||||
->storeFiles(false)
|
||||
->multiple(),
|
||||
]),
|
||||
Tab::make('From URL')
|
||||
Tab::make(trans('admin/egg.import.url'))
|
||||
->icon('tabler-world-upload')
|
||||
->schema([
|
||||
TextInput::make('url')
|
||||
->label('URL')
|
||||
->hint('This URL should point to a single json file')
|
||||
->label(trans('admin/egg.import.url'))
|
||||
->hint(trans('admin/egg.import.url_help'))
|
||||
->url(),
|
||||
]),
|
||||
]),
|
||||
@ -66,7 +66,7 @@ class ImportEggAction extends Action
|
||||
}
|
||||
} catch (Exception $exception) {
|
||||
Notification::make()
|
||||
->title('Import Failed')
|
||||
->title(trans('admin/egg.import.import_failed'))
|
||||
->body($exception->getMessage())
|
||||
->danger()
|
||||
->send();
|
||||
@ -77,7 +77,7 @@ class ImportEggAction extends Action
|
||||
}
|
||||
|
||||
Notification::make()
|
||||
->title('Import Success')
|
||||
->title(trans('admin/egg.import.import_success'))
|
||||
->success()
|
||||
->send();
|
||||
});
|
||||
|
@ -20,7 +20,7 @@ class UpdateEggAction extends Action
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->label('Update');
|
||||
$this->label(trans('admin/egg.update'));
|
||||
|
||||
$this->icon('tabler-cloud-download');
|
||||
|
||||
@ -28,9 +28,9 @@ class UpdateEggAction extends Action
|
||||
|
||||
$this->requiresConfirmation();
|
||||
|
||||
$this->modalHeading('Are you sure you want to update this egg?');
|
||||
$this->modalHeading(trans('admin/egg.update_question'));
|
||||
|
||||
$this->modalDescription('If you made any changes to the egg they will be overwritten!');
|
||||
$this->modalDescription(trans('admin/egg.update_description'));
|
||||
|
||||
$this->modalIconColor('danger');
|
||||
|
||||
@ -43,7 +43,7 @@ class UpdateEggAction extends Action
|
||||
cache()->forget("eggs.$egg->uuid.update");
|
||||
} catch (Exception $exception) {
|
||||
Notification::make()
|
||||
->title('Egg Update failed')
|
||||
->title(trans('admin/egg.update_failed'))
|
||||
->body($exception->getMessage())
|
||||
->danger()
|
||||
->send();
|
||||
@ -54,7 +54,7 @@ class UpdateEggAction extends Action
|
||||
}
|
||||
|
||||
Notification::make()
|
||||
->title('Egg updated')
|
||||
->title(trans('admin/egg.updated'))
|
||||
->body($egg->name)
|
||||
->success()
|
||||
->send();
|
||||
|
@ -67,12 +67,11 @@ class EditProfile extends BaseEditProfile
|
||||
->schema([
|
||||
Tabs::make()->persistTabInQueryString()
|
||||
->schema([
|
||||
Tab::make('Account')
|
||||
->label(trans('strings.account'))
|
||||
Tab::make(trans('profile.tabs.account'))
|
||||
->icon('tabler-user')
|
||||
->schema([
|
||||
TextInput::make('username')
|
||||
->label(trans('strings.username'))
|
||||
->label(trans('profile.username'))
|
||||
->disabled()
|
||||
->readOnly()
|
||||
->dehydrated(false)
|
||||
@ -81,13 +80,13 @@ class EditProfile extends BaseEditProfile
|
||||
->autofocus(),
|
||||
TextInput::make('email')
|
||||
->prefixIcon('tabler-mail')
|
||||
->label(trans('strings.email'))
|
||||
->label(trans('profile.email'))
|
||||
->email()
|
||||
->required()
|
||||
->maxLength(255)
|
||||
->unique(ignoreRecord: true),
|
||||
TextInput::make('password')
|
||||
->label(trans('strings.password'))
|
||||
->label(trans('profile.password'))
|
||||
->password()
|
||||
->prefixIcon('tabler-password')
|
||||
->revealable(filament()->arePasswordsRevealable())
|
||||
@ -98,7 +97,7 @@ class EditProfile extends BaseEditProfile
|
||||
->live(debounce: 500)
|
||||
->same('passwordConfirmation'),
|
||||
TextInput::make('passwordConfirmation')
|
||||
->label(trans('strings.password_confirmation'))
|
||||
->label(trans('profile.password_confirmation'))
|
||||
->password()
|
||||
->prefixIcon('tabler-password-fingerprint')
|
||||
->revealable(filament()->arePasswordsRevealable())
|
||||
@ -106,25 +105,22 @@ class EditProfile extends BaseEditProfile
|
||||
->visible(fn (Get $get): bool => filled($get('password')))
|
||||
->dehydrated(false),
|
||||
Select::make('timezone')
|
||||
->label(trans('profile.timezone'))
|
||||
->required()
|
||||
->prefixIcon('tabler-clock-pin')
|
||||
->options(fn () => collect(DateTimeZone::listIdentifiers())->mapWithKeys(fn ($tz) => [$tz => $tz]))
|
||||
->searchable(),
|
||||
Select::make('language')
|
||||
->label(trans('strings.language'))
|
||||
->label(trans('profile.language'))
|
||||
->required()
|
||||
->prefixIcon('tabler-flag')
|
||||
->live()
|
||||
->default('en')
|
||||
->helperText(fn ($state, LanguageService $languageService) => new HtmlString($languageService->isLanguageTranslated($state) ? '' : "
|
||||
Your language ($state) has not been translated yet!
|
||||
But never fear, you can help fix that by
|
||||
<a style='color: rgb(56, 189, 248)' href='https://crowdin.com/project/pelican-dev'>contributing directly here</a>.
|
||||
"))
|
||||
->helperText(fn ($state, LanguageService $languageService) => new HtmlString($languageService->isLanguageTranslated($state) ? '' : trans('profile.language_helper', ['state' => $state])))
|
||||
->options(fn (LanguageService $languageService) => $languageService->getAvailableLanguages()),
|
||||
]),
|
||||
|
||||
Tab::make('OAuth')
|
||||
Tab::make(trans('profile.tabs.oauth'))
|
||||
->icon('tabler-brand-oauth')
|
||||
->visible(function () {
|
||||
$oauthProviders = OAuthProvider::get();
|
||||
@ -151,7 +147,7 @@ class EditProfile extends BaseEditProfile
|
||||
$unlink = array_key_exists($id, $this->getUser()->oauth ?? []);
|
||||
|
||||
$actions[] = Action::make("oauth_$id")
|
||||
->label(($unlink ? 'Unlink ' : 'Link ') . $name)
|
||||
->label(($unlink ? trans('profile.unlink') : trans('profile.link')) . $name)
|
||||
->icon($unlink ? 'tabler-unlink' : 'tabler-link')
|
||||
->color(Color::hex($oauthProvider->getHexColor()))
|
||||
->action(function (UserUpdateService $updateService) use ($id, $name, $unlink) {
|
||||
@ -164,7 +160,7 @@ class EditProfile extends BaseEditProfile
|
||||
$this->fillForm();
|
||||
|
||||
Notification::make()
|
||||
->title("OAuth provider '$name' unlinked")
|
||||
->title(trans('profile.unlinked', ['name' => $name]))
|
||||
->success()
|
||||
->send();
|
||||
} else {
|
||||
@ -176,24 +172,24 @@ class EditProfile extends BaseEditProfile
|
||||
return [Actions::make($actions)];
|
||||
}),
|
||||
|
||||
Tab::make('2FA')
|
||||
Tab::make(trans('profile.tabs.2fa'))
|
||||
->icon('tabler-shield-lock')
|
||||
->schema(function (TwoFactorSetupService $setupService) {
|
||||
if ($this->getUser()->use_totp) {
|
||||
return [
|
||||
Placeholder::make('2fa-already-enabled')
|
||||
->label('Two Factor Authentication is currently enabled!'),
|
||||
->label(trans('profile.2fa_enabled')),
|
||||
Textarea::make('backup-tokens')
|
||||
->hidden(fn () => !cache()->get("users.{$this->getUser()->id}.2fa.tokens"))
|
||||
->rows(10)
|
||||
->readOnly()
|
||||
->dehydrated(false)
|
||||
->formatStateUsing(fn () => cache()->get("users.{$this->getUser()->id}.2fa.tokens"))
|
||||
->helperText('These will not be shown again!')
|
||||
->label('Backup Tokens:'),
|
||||
->helperText(trans('profile.backup_help'))
|
||||
->label(trans('profile.backup_codes')),
|
||||
TextInput::make('2fa-disable-code')
|
||||
->label('Disable 2FA')
|
||||
->helperText('Enter your current 2FA code to disable Two Factor Authentication'),
|
||||
->label(trans('profile.disable_2fa'))
|
||||
->helperText(trans('profile.disable_2fa_help')),
|
||||
];
|
||||
}
|
||||
|
||||
@ -236,39 +232,40 @@ class EditProfile extends BaseEditProfile
|
||||
|
||||
return [
|
||||
Placeholder::make('qr')
|
||||
->label('Scan QR Code')
|
||||
->label(trans('profile.scan_qr'))
|
||||
->content(fn () => new HtmlString("
|
||||
<div style='width: 300px; background-color: rgb(24, 24, 27);'>$image</div>
|
||||
"))
|
||||
->helperText('Setup Key: ' . $secret),
|
||||
->helperText(trans('profile.setup_key') .': '. $secret),
|
||||
TextInput::make('2facode')
|
||||
->label('Code')
|
||||
->label(trans('profile.code'))
|
||||
->requiredWith('2fapassword')
|
||||
->helperText('Scan the QR code above using your two-step authentication app, then enter the code generated.'),
|
||||
->helperText(trans('profile.code_help')),
|
||||
TextInput::make('2fapassword')
|
||||
->label('Current Password')
|
||||
->label(trans('profile.current_password'))
|
||||
->requiredWith('2facode')
|
||||
->currentPassword()
|
||||
->password()
|
||||
->helperText('Enter your current password to verify.'),
|
||||
->password(),
|
||||
];
|
||||
}),
|
||||
Tab::make('API Keys')
|
||||
Tab::make(trans('profile.tabs.api_keys'))
|
||||
->icon('tabler-key')
|
||||
->schema([
|
||||
Grid::make('asdf')->columns(5)->schema([
|
||||
Section::make('Create API Key')->columnSpan(3)->schema([
|
||||
Grid::make('name')->columns(5)->schema([
|
||||
Section::make(trans('profile.create_key'))->columnSpan(3)->schema([
|
||||
TextInput::make('description')
|
||||
->label(trans('profile.description'))
|
||||
->live(),
|
||||
TagsInput::make('allowed_ips')
|
||||
->label(trans('profile.allowed_ips'))
|
||||
->live()
|
||||
->splitKeys([',', ' ', 'Tab'])
|
||||
->placeholder('Example: 127.0.0.1 or 192.168.1.1')
|
||||
->label('Whitelisted IP\'s')
|
||||
->helperText('Press enter to add a new IP address or leave blank to allow any IP address')
|
||||
->placeholder('127.0.0.1 or 192.168.1.1')
|
||||
->helperText(trans('profile.allowed_ips_help'))
|
||||
->columnSpanFull(),
|
||||
])->headerActions([
|
||||
Action::make('Create')
|
||||
->label(trans('filament-actions::create.single.modal.actions.create.label'))
|
||||
->disabled(fn (Get $get) => $get('description') === null)
|
||||
->successRedirectUrl(self::getUrl(['tab' => '-api-keys-tab']))
|
||||
->action(function (Get $get, Action $action, User $user) {
|
||||
@ -283,7 +280,7 @@ class EditProfile extends BaseEditProfile
|
||||
->log();
|
||||
|
||||
Notification::make()
|
||||
->title('API Key created')
|
||||
->title(trans('profile.key_created'))
|
||||
->body($token->accessToken->identifier . $token->plainTextToken)
|
||||
->persistent()
|
||||
->success()
|
||||
@ -292,7 +289,7 @@ class EditProfile extends BaseEditProfile
|
||||
$action->success();
|
||||
}),
|
||||
]),
|
||||
Section::make('Keys')->columnSpan(2)->schema([
|
||||
Section::make(trans('profile.keys'))->label(trans('profile.keys'))->columnSpan(2)->schema([
|
||||
Repeater::make('keys')
|
||||
->label('')
|
||||
->relationship('apiKeys')
|
||||
@ -317,15 +314,14 @@ class EditProfile extends BaseEditProfile
|
||||
]),
|
||||
]),
|
||||
]),
|
||||
Tab::make('SSH Keys')
|
||||
Tab::make(trans('profile.tabs.ssh_keys'))
|
||||
->icon('tabler-lock-code')
|
||||
->schema([
|
||||
Placeholder::make('Coming soon!'),
|
||||
]),
|
||||
Tab::make('Activity')
|
||||
->hidden(),
|
||||
Tab::make(trans('profile.tabs.activity'))
|
||||
->icon('tabler-history')
|
||||
->schema([
|
||||
Repeater::make('activity')
|
||||
->label('')
|
||||
->deletable(false)
|
||||
->addable(false)
|
||||
->relationship(null, function (Builder $query) {
|
||||
@ -363,7 +359,7 @@ class EditProfile extends BaseEditProfile
|
||||
$this->toggleTwoFactorService->handle($record, $token, false);
|
||||
} catch (TwoFactorAuthenticationTokenInvalid $exception) {
|
||||
Notification::make()
|
||||
->title('Invalid 2FA Code')
|
||||
->title(trans('profile.invalid_code'))
|
||||
->body($exception->getMessage())
|
||||
->color('danger')
|
||||
->icon('tabler-2fa')
|
||||
|
@ -32,11 +32,11 @@ use Illuminate\Support\Facades\URL;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Illuminate\Support\Str;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
use Spatie\Health\Checks\Checks\CacheCheck;
|
||||
use Spatie\Health\Checks\Checks\DatabaseCheck;
|
||||
use Spatie\Health\Checks\Checks\DebugModeCheck;
|
||||
use Spatie\Health\Checks\Checks\EnvironmentCheck;
|
||||
use Spatie\Health\Checks\Checks\ScheduleCheck;
|
||||
use App\Checks\CacheCheck;
|
||||
use App\Checks\DatabaseCheck;
|
||||
use App\Checks\DebugModeCheck;
|
||||
use App\Checks\EnvironmentCheck;
|
||||
use App\Checks\ScheduleCheck;
|
||||
use Spatie\Health\Facades\Health;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
|
@ -42,17 +42,17 @@ class AdminPanelProvider extends PanelProvider
|
||||
->login(Login::class)
|
||||
->userMenuItems([
|
||||
MenuItem::make()
|
||||
->label('Exit Admin')
|
||||
->label(trans('profile.exit_admin'))
|
||||
->url('/')
|
||||
->icon('tabler-arrow-back')
|
||||
->sort(24),
|
||||
])
|
||||
->navigationGroups([
|
||||
NavigationGroup::make('Server')
|
||||
NavigationGroup::make(trans('admin/dashboard.server'))
|
||||
->collapsible(false),
|
||||
NavigationGroup::make('User')
|
||||
NavigationGroup::make(trans('admin/dashboard.user'))
|
||||
->collapsible(false),
|
||||
NavigationGroup::make('Advanced'),
|
||||
NavigationGroup::make(trans('admin/dashboard.advanced')),
|
||||
])
|
||||
->sidebarCollapsibleOnDesktop()
|
||||
->discoverResources(in: app_path('Filament/Admin/Resources'), for: 'App\\Filament\\Admin\\Resources')
|
||||
|
@ -8,20 +8,7 @@ use Locale;
|
||||
class LanguageService
|
||||
{
|
||||
public const TRANSLATED_COMPLETELY = [
|
||||
'ar',
|
||||
'cz',
|
||||
'da',
|
||||
'de',
|
||||
'dk',
|
||||
'en',
|
||||
'es',
|
||||
'fi',
|
||||
'ja',
|
||||
'nl',
|
||||
'pl',
|
||||
'sk',
|
||||
'ru',
|
||||
'tr',
|
||||
];
|
||||
|
||||
public function isLanguageTranslated(string $countryCode = 'en'): bool
|
||||
|
@ -1,130 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Contains all of the translation strings for different activity log
|
||||
* events. These should be keyed by the value in front of the colon (:)
|
||||
* in the event name. If there is no colon present, they should live at
|
||||
* the top level.
|
||||
*/
|
||||
return [
|
||||
'auth' => [
|
||||
'fail' => 'Kon nie aanmeld nie',
|
||||
'success' => 'Aangemeld',
|
||||
'password-reset' => 'Wagwoord herstel',
|
||||
'reset-password' => 'Versoek wagwoordterugstelling',
|
||||
'checkpoint' => 'Twee-faktor-stawing versoek',
|
||||
'recovery-token' => 'Gebruik twee-faktor-hersteltoken',
|
||||
'token' => 'Twee-faktor uitdaging opgelos',
|
||||
'ip-blocked' => 'Geblokkeerde versoek van ongelyste IP-adres vir :identifier',
|
||||
'sftp' => [
|
||||
'fail' => 'Kon nie SFTP aanmeld nie',
|
||||
],
|
||||
],
|
||||
'user' => [
|
||||
'account' => [
|
||||
'email-changed' => 'E-pos verander van :oud na :nuut',
|
||||
'password-changed' => 'Verander wagwoord',
|
||||
],
|
||||
'api-key' => [
|
||||
'create' => 'Skep nuwe API-sleutel:identifiseerder',
|
||||
'delete' => 'Geskrap API-sleutel:identifiseerder',
|
||||
],
|
||||
'ssh-key' => [
|
||||
'create' => 'SSH-sleutel :vingerafdruk by rekening gevoeg',
|
||||
'delete' => 'SSH-sleutel :vingerafdruk van rekening verwyder',
|
||||
],
|
||||
'two-factor' => [
|
||||
'create' => 'Geaktiveerde twee-faktor-autagtiging',
|
||||
'delete' => 'Gedeaktiveerde twee-faktor-aut',
|
||||
],
|
||||
],
|
||||
'server' => [
|
||||
'reinstall' => 'Herinstalleer bediener',
|
||||
'console' => [
|
||||
'command' => '":opdrag" op die bediener uitgevoer',
|
||||
],
|
||||
'power' => [
|
||||
'start' => 'Het die bediener begin',
|
||||
'stop' => 'Het die bediener gestop',
|
||||
'restart' => 'Het die bediener herbegin',
|
||||
'kill' => 'Het die bedienerproses doodgemaak',
|
||||
],
|
||||
'backup' => [
|
||||
'download' => 'Het die :name rugsteun afgelaai',
|
||||
'delete' => 'Het die :name rugsteun uitgevee',
|
||||
'restore' => 'Het die :name-rugsteun herstel (geskrap lêers: :truncate)',
|
||||
'restore-complete' => 'Voltooide herstel van die :name rugsteun',
|
||||
'restore-failed' => 'Kon nie die herstel van die :name rugsteun voltooi nie',
|
||||
'start' => 'Het \'n nuwe rugsteun :name begin',
|
||||
'complete' => 'Het die :name-rugsteun as voltooi gemerk',
|
||||
'fail' => 'Het die :name-rugsteun as voltooi gemerk',
|
||||
'lock' => 'Het die :name rugsteun uitgevee',
|
||||
'unlock' => 'Het die :name rugsteun afgelaai',
|
||||
],
|
||||
'database' => [
|
||||
'create' => 'Create new database file',
|
||||
'rotate-password' => 'Wagwoord geroteer vir databasis :naam',
|
||||
'delete' => 'Geskrap databasis :naam',
|
||||
],
|
||||
'file' => [
|
||||
'compress_one' => 'Saamgeperste :directory:lêer',
|
||||
'compress_other' => 'Saamgeperste :count lêers in :directory',
|
||||
'read' => 'Het die inhoud van :file bekyk',
|
||||
'copy' => 'Het \'n kopie van :file geskep',
|
||||
'create-directory' => 'Geskep gids :gids:naam',
|
||||
'decompress' => 'Gedekomprimeerde :lêers in :directory',
|
||||
'delete_one' => 'Geskrap :gids:lêers.0',
|
||||
'delete_other' => 'Saamgeperste :count lêers in :directory',
|
||||
'download' => 'Afgelaai: lêer',
|
||||
'pull' => 'Het \'n afstandlêer afgelaai vanaf :url na :directory',
|
||||
'rename_one' => 'Hernoem :gids:lêers.0.van na :gids:lêers.0.na',
|
||||
'rename_other' => 'Hernoem :count lêers in :directory',
|
||||
'write' => 'Het nuwe inhoud na :file geskryf',
|
||||
'upload' => 'Het \'n lêeroplaai begin',
|
||||
'uploaded' => 'Uploaded :directory:file',
|
||||
],
|
||||
'sftp' => [
|
||||
'denied' => 'Blocked SFTP access due to permissions',
|
||||
'create_one' => 'Created :files.0',
|
||||
'create_other' => 'Created :count new files',
|
||||
'write_one' => 'Modified the contents of :files.0',
|
||||
'write_other' => 'Modified the contents of :count files',
|
||||
'delete_one' => 'Deleted :files.0',
|
||||
'delete_other' => 'Deleted :count files',
|
||||
'create-directory_one' => 'Created the :files.0 directory',
|
||||
'create-directory_other' => 'Created :count directories',
|
||||
'rename_one' => 'Renamed :files.0.from to :files.0.to',
|
||||
'rename_other' => 'Renamed or moved :count files',
|
||||
],
|
||||
'allocation' => [
|
||||
'create' => 'Added :allocation to the server',
|
||||
'notes' => 'Updated the notes for :allocation from ":old" to ":new"',
|
||||
'primary' => 'Set :allocation as the primary server allocation',
|
||||
'delete' => 'Deleted the :allocation allocation',
|
||||
],
|
||||
'schedule' => [
|
||||
'create' => 'Created the :name schedule',
|
||||
'update' => 'Updated the :name schedule',
|
||||
'execute' => 'Manually executed the :name schedule',
|
||||
'delete' => 'Deleted the :name schedule',
|
||||
],
|
||||
'task' => [
|
||||
'create' => 'Created a new ":action" task for the :name schedule',
|
||||
'update' => 'Updated the ":action" task for the :name schedule',
|
||||
'delete' => 'Deleted a task for the :name schedule',
|
||||
],
|
||||
'settings' => [
|
||||
'rename' => 'Renamed the server from :old to :new',
|
||||
'description' => 'Changed the server description from :old to :new',
|
||||
],
|
||||
'startup' => [
|
||||
'edit' => 'Changed the :variable variable from ":old" to ":new"',
|
||||
'image' => 'Updated the Docker Image for the server from :old to :new',
|
||||
],
|
||||
'subuser' => [
|
||||
'create' => 'Added :email as a subuser',
|
||||
'update' => 'Updated the subuser permissions for :email',
|
||||
'delete' => 'Removed :email as a subuser',
|
||||
],
|
||||
],
|
||||
];
|
@ -1,19 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'notices' => [
|
||||
'imported' => 'Successfully imported this Egg and its associated variables.',
|
||||
'updated_via_import' => 'This Egg has been updated using the file provided.',
|
||||
'deleted' => 'Successfully deleted the requested egg from the Panel.',
|
||||
'updated' => 'Egg configuration has been updated successfully.',
|
||||
'script_updated' => 'Egg install script has been updated and will run whenever servers are installed.',
|
||||
'egg_created' => 'A new egg was laid successfully. You will need to restart any running daemons to apply this new egg.',
|
||||
],
|
||||
'variables' => [
|
||||
'notices' => [
|
||||
'variable_deleted' => 'The variable ":variable" has been deleted and will no longer be available to servers once rebuilt.',
|
||||
'variable_updated' => 'The variable ":variable" has been updated. You will need to rebuild any servers using this variable in order to apply changes.',
|
||||
'variable_created' => 'New variable has successfully been created and assigned to this egg.',
|
||||
],
|
||||
],
|
||||
];
|
@ -1,15 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'validation' => [
|
||||
'fqdn_not_resolvable' => 'The FQDN or IP address provided does not resolve to a valid IP address.',
|
||||
'fqdn_required_for_ssl' => 'A fully qualified domain name that resolves to a public IP address is required in order to use SSL for this node.',
|
||||
],
|
||||
'notices' => [
|
||||
'allocations_added' => 'Allocations have successfully been added to this node.',
|
||||
'node_deleted' => 'Node has been successfully removed from the panel.',
|
||||
'node_created' => 'Successfully created new node. You can automatically configure the daemon on this machine by visiting the \'Configuration\' tab. <strong>Before you can add any servers you must first allocate at least one IP address and port.</strong>',
|
||||
'node_updated' => 'Node information has been updated. If any daemon settings were changed you will need to reboot it for those changes to take effect.',
|
||||
'unallocated_deleted' => 'Deleted all un-allocated ports for <code>:ip</code>.',
|
||||
],
|
||||
];
|
@ -1,27 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'exceptions' => [
|
||||
'no_new_default_allocation' => 'You are attempting to delete the default allocation for this server but there is no fallback allocation to use.',
|
||||
'marked_as_failed' => 'This server was marked as having failed a previous installation. Current status cannot be toggled in this state.',
|
||||
'bad_variable' => 'There was a validation error with the :name variable.',
|
||||
'daemon_exception' => 'There was an exception while attempting to communicate with the daemon resulting in a HTTP/:code response code. This exception has been logged. (request id: :request_id)',
|
||||
'default_allocation_not_found' => 'The requested default allocation was not found in this server\'s allocations.',
|
||||
],
|
||||
'alerts' => [
|
||||
'startup_changed' => 'The startup configuration for this server has been updated. If this server\'s egg was changed a reinstall will be occurring now.',
|
||||
'server_deleted' => 'Server has successfully been deleted from the system.',
|
||||
'server_created' => 'Server was successfully created on the panel. Please allow the daemon a few minutes to completely install this server.',
|
||||
'build_updated' => 'The build details for this server have been updated. Some changes may require a restart to take effect.',
|
||||
'suspension_toggled' => 'Server suspension status has been changed to :status.',
|
||||
'rebuild_on_boot' => 'This server has been marked as requiring a Docker Container rebuild. This will happen the next time the server is started.',
|
||||
'install_toggled' => 'The installation status for this server has been toggled.',
|
||||
'server_reinstalled' => 'This server has been queued for a reinstallation beginning now.',
|
||||
'details_updated' => 'Server details have been successfully updated.',
|
||||
'docker_image_updated' => 'Successfully changed the default Docker image to use for this server. A reboot is required to apply this change.',
|
||||
'node_required' => 'You must have at least one node configured before you can add a server to this panel.',
|
||||
'transfer_nodes_required' => 'You must have at least two nodes configured before you can transfer servers.',
|
||||
'transfer_started' => 'Server transfer has been started.',
|
||||
'transfer_not_viable' => 'The node you selected does not have the required disk space or memory available to accommodate this server.',
|
||||
],
|
||||
];
|
@ -1,12 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'exceptions' => [
|
||||
'user_has_servers' => 'Cannot delete a user with active servers attached to their account. Please delete their servers before continuing.',
|
||||
'user_is_self' => 'Cannot delete your own user account.',
|
||||
],
|
||||
'notices' => [
|
||||
'account_created' => 'Account has been created successfully.',
|
||||
'account_updated' => 'Account has been successfully updated.',
|
||||
],
|
||||
];
|
@ -1,27 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'sign_in' => 'Sign In',
|
||||
'go_to_login' => 'Go to Login',
|
||||
'failed' => 'No account matching those credentials could be found.',
|
||||
|
||||
'forgot_password' => [
|
||||
'label' => 'Forgot Password?',
|
||||
'label_help' => 'Enter your account email address to receive instructions on resetting your password.',
|
||||
'button' => 'Recover Account',
|
||||
],
|
||||
|
||||
'reset_password' => [
|
||||
'button' => 'Reset and Sign In',
|
||||
],
|
||||
|
||||
'two_factor' => [
|
||||
'label' => '2-Factor Token',
|
||||
'label_help' => 'This account requires a second layer of authentication in order to continue. Please enter the code generated by your device to complete this login.',
|
||||
'checkpoint_failed' => 'The two-factor authentication token was invalid.',
|
||||
],
|
||||
|
||||
'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',
|
||||
'password_requirements' => 'Password must be at least 8 characters in length and should be unique to this site.',
|
||||
'2fa_must_be_enabled' => 'The administrator has required that 2-Factor Authentication be enabled for your account in order to use the Panel.',
|
||||
];
|
@ -1,57 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'user' => [
|
||||
'search_users' => 'Enter a Username, User ID, or Email Address',
|
||||
'select_search_user' => 'ID of user to delete (Enter \'0\' to re-search)',
|
||||
'deleted' => 'User successfully deleted from the Panel.',
|
||||
'confirm_delete' => 'Are you sure you want to delete this user from the Panel?',
|
||||
'no_users_found' => 'No users were found for the search term provided.',
|
||||
'multiple_found' => 'Multiple accounts were found for the user provided, unable to delete a user because of the --no-interaction flag.',
|
||||
'ask_admin' => 'Is this user an administrator?',
|
||||
'ask_email' => 'Email Address',
|
||||
'ask_username' => 'Username',
|
||||
'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_help' => 'Passwords must be at least 8 characters in length and contain at least one capital letter and number.',
|
||||
'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.',
|
||||
],
|
||||
'2fa_disabled' => '2-Factor authentication has been disabled for :email.',
|
||||
],
|
||||
'schedule' => [
|
||||
'output_line' => 'Dispatching job for first task in `:schedule` (:hash).',
|
||||
],
|
||||
'maintenance' => [
|
||||
'deleting_service_backup' => 'Deleting service backup file :file.',
|
||||
],
|
||||
'server' => [
|
||||
'rebuild_failed' => 'Rebuild request for ":name" (#:id) on node ":node" failed with error: :message',
|
||||
'reinstall' => [
|
||||
'failed' => 'Reinstall request for ":name" (#:id) on node ":node" failed with error: :message',
|
||||
'confirm' => 'You are about to reinstall against a group of servers. Do you wish to continue?',
|
||||
],
|
||||
'power' => [
|
||||
'confirm' => 'You are about to perform a :action against :count servers. Do you wish to continue?',
|
||||
'action_failed' => 'Power action request for ":name" (#:id) on node ":node" failed with error: :message',
|
||||
],
|
||||
],
|
||||
'environment' => [
|
||||
'mail' => [
|
||||
'ask_smtp_host' => 'SMTP Host (e.g. smtp.gmail.com)',
|
||||
'ask_smtp_port' => 'SMTP Port',
|
||||
'ask_smtp_username' => 'SMTP Username',
|
||||
'ask_smtp_password' => 'SMTP Password',
|
||||
'ask_mailgun_domain' => 'Mailgun Domain',
|
||||
'ask_mailgun_endpoint' => 'Mailgun Endpoint',
|
||||
'ask_mailgun_secret' => 'Mailgun Secret',
|
||||
'ask_mandrill_secret' => 'Mandrill Secret',
|
||||
'ask_postmark_username' => 'Postmark API Key',
|
||||
'ask_driver' => 'Which driver should be used for sending emails?',
|
||||
'ask_mail_from' => 'Email address emails should originate from',
|
||||
'ask_mail_name' => 'Name that emails should appear from',
|
||||
'ask_encryption' => 'Encryption method to use',
|
||||
],
|
||||
],
|
||||
];
|
@ -1,28 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'email' => [
|
||||
'title' => 'Update your email',
|
||||
'updated' => 'Your email address has been updated.',
|
||||
],
|
||||
'password' => [
|
||||
'title' => 'Change your password',
|
||||
'requirements' => 'Your new password should be at least 8 characters in length.',
|
||||
'updated' => 'Your password has been updated.',
|
||||
],
|
||||
'two_factor' => [
|
||||
'button' => 'Configure 2-Factor Authentication',
|
||||
'disabled' => 'Two-factor authentication has been disabled on your account. You will no longer be prompted to provide a token when logging in.',
|
||||
'enabled' => 'Two-factor authentication has been enabled on your account! From now on, when logging in, you will be required to provide the code generated by your device.',
|
||||
'invalid' => 'The token provided was invalid.',
|
||||
'setup' => [
|
||||
'title' => 'Setup two-factor authentication',
|
||||
'help' => 'Can\'t scan the code? Enter the code below into your application:',
|
||||
'field' => 'Enter token',
|
||||
],
|
||||
'disable' => [
|
||||
'title' => 'Disable two-factor authentication',
|
||||
'field' => 'Enter token',
|
||||
],
|
||||
],
|
||||
];
|
@ -1,8 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'search' => 'Search for servers...',
|
||||
'no_matches' => 'There were no servers found matching the search criteria provided.',
|
||||
'cpu_title' => 'CPU',
|
||||
'memory_title' => 'Memory',
|
||||
];
|
@ -1,55 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'daemon_connection_failed' => 'There was an exception while attempting to communicate with the daemon resulting in a HTTP/:code response code. This exception has been logged.',
|
||||
'node' => [
|
||||
'servers_attached' => 'A node must have no servers linked to it in order to be deleted.',
|
||||
'daemon_off_config_updated' => 'The daemon configuration <strong>has been updated</strong>, however there was an error encountered while attempting to automatically update the configuration file on the Daemon. You will need to manually update the configuration file (config.yml) for the daemon to apply these changes.',
|
||||
],
|
||||
'allocations' => [
|
||||
'server_using' => 'A server is currently assigned to this allocation. An allocation can only be deleted if no server is currently assigned.',
|
||||
'too_many_ports' => 'Adding more than 1000 ports in a single range at once is not supported.',
|
||||
'invalid_mapping' => 'The mapping provided for :port was invalid and could not be processed.',
|
||||
'cidr_out_of_range' => 'CIDR notation only allows masks between /25 and /32.',
|
||||
'port_out_of_range' => 'Ports in an allocation must be greater than 1024 and less than or equal to 65535.',
|
||||
],
|
||||
'egg' => [
|
||||
'delete_has_servers' => 'An Egg with active servers attached to it cannot be deleted from the Panel.',
|
||||
'invalid_copy_id' => 'The Egg selected for copying a script from either does not exist, or is copying a script itself.',
|
||||
'has_children' => 'This Egg is a parent to one or more other Eggs. Please delete those Eggs before deleting this Egg.',
|
||||
],
|
||||
'variables' => [
|
||||
'env_not_unique' => 'The environment variable :name must be unique to this Egg.',
|
||||
'reserved_name' => 'The environment variable :name is protected and cannot be assigned to a variable.',
|
||||
'bad_validation_rule' => 'The validation rule ":rule" is not a valid rule for this application.',
|
||||
],
|
||||
'importer' => [
|
||||
'json_error' => 'There was an error while attempting to parse the JSON file: :error.',
|
||||
'file_error' => 'The JSON file provided was not valid.',
|
||||
'invalid_json_provided' => 'The JSON file provided is not in a format that can be recognized.',
|
||||
],
|
||||
'subusers' => [
|
||||
'editing_self' => 'Editing your own subuser account is not permitted.',
|
||||
'user_is_owner' => 'You cannot add the server owner as a subuser for this server.',
|
||||
'subuser_exists' => 'A user with that email address is already assigned as a subuser for this server.',
|
||||
],
|
||||
'databases' => [
|
||||
'delete_has_databases' => 'Cannot delete a database host server that has active databases linked to it.',
|
||||
],
|
||||
'tasks' => [
|
||||
'chain_interval_too_long' => 'The maximum interval time for a chained task is 15 minutes.',
|
||||
],
|
||||
'locations' => [
|
||||
'has_nodes' => 'Cannot delete a location that has active nodes attached to it.',
|
||||
],
|
||||
'users' => [
|
||||
'node_revocation_failed' => 'Failed to revoke keys on <a href=":link">Node #:node</a>. :error',
|
||||
],
|
||||
'deployment' => [
|
||||
'no_viable_nodes' => 'No nodes satisfying the requirements specified for automatic deployment could be found.',
|
||||
'no_viable_allocations' => 'No allocations satisfying the requirements for automatic deployment were found.',
|
||||
],
|
||||
'api' => [
|
||||
'resource_not_found' => 'The requested resource does not exist on this server.',
|
||||
],
|
||||
];
|
@ -1,17 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Pagination Language Lines
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following language lines are used by the paginator library to build
|
||||
| the simple pagination links. You are free to change them to anything
|
||||
| you want to customize your views to better match your application.
|
||||
|
|
||||
*/
|
||||
|
||||
'previous' => '« Previous',
|
||||
'next' => 'Next »',
|
||||
];
|
@ -1,19 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Password Reset Language Lines
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following language lines are the default lines which match reasons
|
||||
| that are given by the password broker for a password update attempt
|
||||
| has failed, such as for an invalid token or invalid new password.
|
||||
|
|
||||
*/
|
||||
'password' => 'Passwords must be at least six characters and match the confirmation.',
|
||||
'reset' => 'Your password has been reset!',
|
||||
'sent' => 'We have e-mailed your password reset link!',
|
||||
'token' => 'This password reset token is invalid.',
|
||||
'user' => 'We can\'t find a user with that e-mail address.',
|
||||
];
|
@ -1,33 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'permissions' => [
|
||||
'websocket_*' => 'Allows access to the websocket for this server.',
|
||||
'control_console' => 'Allows the user to send data to the server console.',
|
||||
'control_start' => 'Allows the user to start the server instance.',
|
||||
'control_stop' => 'Allows the user to stop the server instance.',
|
||||
'control_restart' => 'Allows the user to restart the server instance.',
|
||||
'control_kill' => 'Allows the user to kill the server instance.',
|
||||
'user_create' => 'Allows the user to create new user accounts for the server.',
|
||||
'user_read' => 'Allows the user permission to view users associated with this server.',
|
||||
'user_update' => 'Allows the user to modify other users associated with this server.',
|
||||
'user_delete' => 'Allows the user to delete other users associated with this server.',
|
||||
'file_create' => 'Allows the user permission to create new files and directories.',
|
||||
'file_read' => 'Allows the user to see files and folders associated with this server instance, as well as view their contents.',
|
||||
'file_update' => 'Allows the user to update files and folders associated with the server.',
|
||||
'file_delete' => 'Allows the user to delete files and directories.',
|
||||
'file_archive' => 'Allows the user to create file archives and decompress existing archives.',
|
||||
'file_sftp' => 'Allows the user to perform the above file actions using a SFTP client.',
|
||||
'allocation_read' => 'Allows access to the server allocation management pages.',
|
||||
'allocation_update' => 'Allows user permission to make modifications to the server\'s allocations.',
|
||||
'database_create' => 'Allows user permission to create a new database for the server.',
|
||||
'database_read' => 'Allows user permission to view the server databases.',
|
||||
'database_update' => 'Allows a user permission to make modifications to a database. If the user does not have the "View Password" permission as well they will not be able to modify the password.',
|
||||
'database_delete' => 'Allows a user permission to delete a database instance.',
|
||||
'database_view_password' => 'Allows a user permission to view a database password in the system.',
|
||||
'schedule_create' => 'Allows a user to create a new schedule for the server.',
|
||||
'schedule_read' => 'Allows a user permission to view schedules for a server.',
|
||||
'schedule_update' => 'Allows a user permission to make modifications to an existing server schedule.',
|
||||
'schedule_delete' => 'Allows a user to delete a schedule for the server.',
|
||||
],
|
||||
];
|
@ -1,95 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'email' => 'Email',
|
||||
'email_address' => 'Email address',
|
||||
'user_identifier' => 'Username or Email',
|
||||
'password' => 'Password',
|
||||
'new_password' => 'New password',
|
||||
'confirm_password' => 'Confirm new password',
|
||||
'login' => 'Login',
|
||||
'home' => 'Home',
|
||||
'servers' => 'Servers',
|
||||
'id' => 'ID',
|
||||
'name' => 'Name',
|
||||
'node' => 'Node',
|
||||
'connection' => 'Connection',
|
||||
'memory' => 'Memory',
|
||||
'cpu' => 'CPU',
|
||||
'disk' => 'Disk',
|
||||
'status' => 'Status',
|
||||
'search' => 'Search',
|
||||
'suspended' => 'Suspended',
|
||||
'account' => 'Account',
|
||||
'security' => 'Security',
|
||||
'ip' => 'IP Address',
|
||||
'last_activity' => 'Last Activity',
|
||||
'revoke' => 'Revoke',
|
||||
'2fa_token' => 'Authentication Token',
|
||||
'submit' => 'Submit',
|
||||
'close' => 'Close',
|
||||
'settings' => 'Settings',
|
||||
'configuration' => 'Configuration',
|
||||
'sftp' => 'SFTP',
|
||||
'databases' => 'Databases',
|
||||
'memo' => 'Memo',
|
||||
'created' => 'Created',
|
||||
'expires' => 'Expires',
|
||||
'public_key' => 'Token',
|
||||
'api_access' => 'Api Access',
|
||||
'never' => 'never',
|
||||
'sign_out' => 'Sign out',
|
||||
'admin_control' => 'Admin Control',
|
||||
'required' => 'Required',
|
||||
'port' => 'Port',
|
||||
'username' => 'Username',
|
||||
'database' => 'Database',
|
||||
'new' => 'New',
|
||||
'danger' => 'Danger',
|
||||
'create' => 'Create',
|
||||
'select_all' => 'Select All',
|
||||
'select_none' => 'Select None',
|
||||
'alias' => 'Alias',
|
||||
'primary' => 'Primary',
|
||||
'make_primary' => 'Make Primary',
|
||||
'none' => 'None',
|
||||
'cancel' => 'Cancel',
|
||||
'created_at' => 'Created At',
|
||||
'action' => 'Action',
|
||||
'data' => 'Data',
|
||||
'queued' => 'Queued',
|
||||
'last_run' => 'Last Run',
|
||||
'next_run' => 'Next Run',
|
||||
'not_run_yet' => 'Not Run Yet',
|
||||
'yes' => 'Yes',
|
||||
'no' => 'No',
|
||||
'delete' => 'Delete',
|
||||
'2fa' => '2FA',
|
||||
'logout' => 'Logout',
|
||||
'admin_cp' => 'Admin Control Panel',
|
||||
'optional' => 'Optional',
|
||||
'read_only' => 'Read Only',
|
||||
'relation' => 'Relation',
|
||||
'owner' => 'Owner',
|
||||
'admin' => 'Admin',
|
||||
'subuser' => 'Subuser',
|
||||
'captcha_invalid' => 'The provided captcha is invalid.',
|
||||
'tasks' => 'Tasks',
|
||||
'seconds' => 'Seconds',
|
||||
'minutes' => 'Minutes',
|
||||
'under_maintenance' => 'Under Maintenance',
|
||||
'days' => [
|
||||
'sun' => 'Sunday',
|
||||
'mon' => 'Monday',
|
||||
'tues' => 'Tuesday',
|
||||
'wed' => 'Wednesday',
|
||||
'thurs' => 'Thursday',
|
||||
'fri' => 'Friday',
|
||||
'sat' => 'Saturday',
|
||||
],
|
||||
'last_used' => 'Last Used',
|
||||
'enable' => 'Enable',
|
||||
'disable' => 'Disable',
|
||||
'save' => 'Save',
|
||||
'copyright' => '® 2024 - :year Pelican',
|
||||
];
|
@ -1,106 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Validation Language Lines
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following language lines contain the default error messages used by
|
||||
| the validator class. Some of these rules have multiple versions such
|
||||
| as the size rules. Feel free to tweak each of these messages here.
|
||||
|
|
||||
*/
|
||||
|
||||
'accepted' => 'The :attribute must be accepted.',
|
||||
'active_url' => 'The :attribute is not a valid URL.',
|
||||
'after' => 'The :attribute must be a date after :date.',
|
||||
'after_or_equal' => 'The :attribute must be a date after or equal to :date.',
|
||||
'alpha' => 'The :attribute may only contain letters.',
|
||||
'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.',
|
||||
'alpha_num' => 'The :attribute may only contain letters and numbers.',
|
||||
'array' => 'The :attribute must be an array.',
|
||||
'before' => 'The :attribute must be a date before :date.',
|
||||
'before_or_equal' => 'The :attribute must be a date before or equal to :date.',
|
||||
'between' => [
|
||||
'numeric' => 'The :attribute must be between :min and :max.',
|
||||
'file' => 'The :attribute must be between :min and :max kilobytes.',
|
||||
'string' => 'The :attribute must be between :min and :max characters.',
|
||||
'array' => 'The :attribute must have between :min and :max items.',
|
||||
],
|
||||
'boolean' => 'The :attribute field must be true or false.',
|
||||
'confirmed' => 'The :attribute confirmation does not match.',
|
||||
'date' => 'The :attribute is not a valid date.',
|
||||
'date_format' => 'The :attribute does not match the format :format.',
|
||||
'different' => 'The :attribute and :other must be different.',
|
||||
'digits' => 'The :attribute must be :digits digits.',
|
||||
'digits_between' => 'The :attribute must be between :min and :max digits.',
|
||||
'dimensions' => 'The :attribute has invalid image dimensions.',
|
||||
'distinct' => 'The :attribute field has a duplicate value.',
|
||||
'email' => 'The :attribute must be a valid email address.',
|
||||
'exists' => 'The selected :attribute is invalid.',
|
||||
'file' => 'The :attribute must be a file.',
|
||||
'filled' => 'The :attribute field is required.',
|
||||
'image' => 'The :attribute must be an image.',
|
||||
'in' => 'The selected :attribute is invalid.',
|
||||
'in_array' => 'The :attribute field does not exist in :other.',
|
||||
'integer' => 'The :attribute must be an integer.',
|
||||
'ip' => 'The :attribute must be a valid IP address.',
|
||||
'json' => 'The :attribute must be a valid JSON string.',
|
||||
'max' => [
|
||||
'numeric' => 'The :attribute may not be greater than :max.',
|
||||
'file' => 'The :attribute may not be greater than :max kilobytes.',
|
||||
'string' => 'The :attribute may not be greater than :max characters.',
|
||||
'array' => 'The :attribute may not have more than :max items.',
|
||||
],
|
||||
'mimes' => 'The :attribute must be a file of type: :values.',
|
||||
'mimetypes' => 'The :attribute must be a file of type: :values.',
|
||||
'min' => [
|
||||
'numeric' => 'The :attribute must be at least :min.',
|
||||
'file' => 'The :attribute must be at least :min kilobytes.',
|
||||
'string' => 'The :attribute must be at least :min characters.',
|
||||
'array' => 'The :attribute must have at least :min items.',
|
||||
],
|
||||
'not_in' => 'The selected :attribute is invalid.',
|
||||
'numeric' => 'The :attribute must be a number.',
|
||||
'present' => 'The :attribute field must be present.',
|
||||
'regex' => 'The :attribute format is invalid.',
|
||||
'required' => 'The :attribute field is required.',
|
||||
'required_if' => 'The :attribute field is required when :other is :value.',
|
||||
'required_unless' => 'The :attribute field is required unless :other is in :values.',
|
||||
'required_with' => 'The :attribute field is required when :values is present.',
|
||||
'required_with_all' => 'The :attribute field is required when :values is present.',
|
||||
'required_without' => 'The :attribute field is required when :values is not present.',
|
||||
'required_without_all' => 'The :attribute field is required when none of :values are present.',
|
||||
'same' => 'The :attribute and :other must match.',
|
||||
'size' => [
|
||||
'numeric' => 'The :attribute must be :size.',
|
||||
'file' => 'The :attribute must be :size kilobytes.',
|
||||
'string' => 'The :attribute must be :size characters.',
|
||||
'array' => 'The :attribute must contain :size items.',
|
||||
],
|
||||
'string' => 'The :attribute must be a string.',
|
||||
'timezone' => 'The :attribute must be a valid zone.',
|
||||
'unique' => 'The :attribute has already been taken.',
|
||||
'uploaded' => 'The :attribute failed to upload.',
|
||||
'url' => 'The :attribute format is invalid.',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Custom Validation Attributes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following language lines are used to swap attribute place-holders
|
||||
| with something more reader friendly such as E-Mail Address instead
|
||||
| of "email". This simply helps us make messages a little cleaner.
|
||||
|
|
||||
*/
|
||||
|
||||
'attributes' => [],
|
||||
|
||||
// Internal validation logic for Panel
|
||||
'internal' => [
|
||||
'variable_value' => ':env variable',
|
||||
'invalid_password' => 'The password provided was invalid for this account.',
|
||||
],
|
||||
];
|
@ -1,130 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Contains all of the translation strings for different activity log
|
||||
* events. These should be keyed by the value in front of the colon (:)
|
||||
* in the event name. If there is no colon present, they should live at
|
||||
* the top level.
|
||||
*/
|
||||
return [
|
||||
'auth' => [
|
||||
'fail' => 'فشل تسجيل الدخول',
|
||||
'success' => 'تم تسجيل الدخول',
|
||||
'password-reset' => 'تم إعادة تعيين كلمة المرور',
|
||||
'reset-password' => 'طلب إعادة تعيين كلمة المرور',
|
||||
'checkpoint' => 'طلب التحقق ذو العاملين',
|
||||
'recovery-token' => 'استخدم رمز الاسترداد ذو العاملين',
|
||||
'token' => 'تم حل تحدي ذو العاملين',
|
||||
'ip-blocked' => 'تم حظر الطلب من عنوان IP غير مدرج لـ :identifier',
|
||||
'sftp' => [
|
||||
'fail' => 'فشل تسجيل الدخول عبر SFTP',
|
||||
],
|
||||
],
|
||||
'user' => [
|
||||
'account' => [
|
||||
'email-changed' => 'تغيير البريد الإلكتروني من :old إلى :new',
|
||||
'password-changed' => 'تم تغيير كلمة المرور',
|
||||
],
|
||||
'api-key' => [
|
||||
'create' => 'تم إنشاء مفتاح API جديد :identifier',
|
||||
'delete' => 'تم حذف مفتاح API :identifier',
|
||||
],
|
||||
'ssh-key' => [
|
||||
'create' => 'تم إضافة مفتاح SSH :fingerprint إلى الحساب',
|
||||
'delete' => 'تم إزالة مفتاح SSH :fingerprint من الحساب',
|
||||
],
|
||||
'two-factor' => [
|
||||
'create' => 'تم تفعيل التحقق ذو العاملين',
|
||||
'delete' => 'تم تعطيل التحقق ذو العاملين',
|
||||
],
|
||||
],
|
||||
'server' => [
|
||||
'reinstall' => 'تم إعادة تثبيت الخادم',
|
||||
'console' => [
|
||||
'command' => 'تنفيذ الأمر ":command" على الخادم',
|
||||
],
|
||||
'power' => [
|
||||
'start' => 'تم تشغيل الخادم',
|
||||
'stop' => 'تم إيقاف الخادم',
|
||||
'restart' => 'تم إعادة تشغيل الخادم',
|
||||
'kill' => 'تم إنهاء عملية الخادم',
|
||||
],
|
||||
'backup' => [
|
||||
'download' => 'تم تنزيل النسخة الاحتياطية :name',
|
||||
'delete' => 'تم حذف النسخة الاحتياطية :name',
|
||||
'restore' => 'تم استعادة النسخة الاحتياطية :name (تم حذف الملفات: :truncate)',
|
||||
'restore-complete' => 'تم إكمال استعادة النسخة الاحتياطية :name',
|
||||
'restore-failed' => 'فشل في إكمال استعادة النسخة الاحتياطية :name',
|
||||
'start' => 'تم بدء نسخة احتياطية جديدة :name',
|
||||
'complete' => 'تم وضع علامة على النسخة الاحتياطية :name كمكتملة',
|
||||
'fail' => 'تم وضع علامة على النسخة الاحتياطية :name كفاشلة',
|
||||
'lock' => 'تم قفل النسخة الاحتياطية :name',
|
||||
'unlock' => 'تم فتح قفل النسخة الاحتياطية :name',
|
||||
],
|
||||
'database' => [
|
||||
'create' => 'تم إنشاء قاعدة بيانات جديدة :name',
|
||||
'rotate-password' => 'تم تغيير كلمة المرور لقاعدة البيانات :name',
|
||||
'delete' => 'تم حذف قاعدة البيانات :name',
|
||||
],
|
||||
'file' => [
|
||||
'compress_one' => 'تم ضغط :directory:file',
|
||||
'compress_other' => 'تم ضغط :count ملف في :directory',
|
||||
'read' => 'تم عرض محتويات :file',
|
||||
'copy' => 'تم إنشاء نسخة من :file',
|
||||
'create-directory' => 'تم إنشاء الدليل :directory:name',
|
||||
'decompress' => 'تم فك ضغط :files في :directory',
|
||||
'delete_one' => 'تم حذف :directory:files.0',
|
||||
'delete_other' => 'تم حذف :count ملف في :directory',
|
||||
'download' => 'تم تنزيل :file',
|
||||
'pull' => 'تم تنزيل ملف من بعد من :url إلى :directory',
|
||||
'rename_one' => 'تم تغيير اسم :directory:files.0.from إلى :directory:files.0.to',
|
||||
'rename_other' => 'تم تغيير اسم :count ملف في :directory',
|
||||
'write' => 'تم كتابة محتوى جديد في :file',
|
||||
'upload' => 'بدء تحميل ملف',
|
||||
'uploaded' => 'تم رفع :directory:file',
|
||||
],
|
||||
'sftp' => [
|
||||
'denied' => 'تم حظر الوصول عبر SFTP بسبب الأذونات',
|
||||
'create_one' => 'تم إنشاء :files.0',
|
||||
'create_other' => 'تم إنشاء :count ملف جديد',
|
||||
'write_one' => 'تم تعديل محتويات :files.0',
|
||||
'write_other' => 'تم تعديل محتويات :count ملف',
|
||||
'delete_one' => 'تم حذف :files.0',
|
||||
'delete_other' => 'تم حذف :count ملف',
|
||||
'create-directory_one' => 'تم إنشاء دليل :files.0',
|
||||
'create-directory_other' => 'تم إنشاء :count مجلد',
|
||||
'rename_one' => 'تم تغيير اسم :files.0.from إلى :files.0.to',
|
||||
'rename_other' => 'تم تغيير اسم أو نقل :count ملف',
|
||||
],
|
||||
'allocation' => [
|
||||
'create' => 'تم إضافة :allocation إلى الخادم',
|
||||
'notes' => 'تم تحديث الملاحظات لـ :allocation من ":old" إلى ":new"',
|
||||
'primary' => 'تم تعيين :allocation كتخصيص أساسي للخادم',
|
||||
'delete' => 'تم حذف التخصيص :allocation',
|
||||
],
|
||||
'schedule' => [
|
||||
'create' => 'تم إنشاء جدول :name',
|
||||
'update' => 'تم تحديث جدول :name',
|
||||
'execute' => 'تم تنفيذ جدول :name يدويًا',
|
||||
'delete' => 'تم حذف جدول :name',
|
||||
],
|
||||
'task' => [
|
||||
'create' => 'تم إنشاء مهمة ":action" جديدة لجدول :name',
|
||||
'update' => 'تم تحديث مهمة ":action" لجدول :name',
|
||||
'delete' => 'تم حذف مهمة لجدول :name',
|
||||
],
|
||||
'settings' => [
|
||||
'rename' => 'تم تغيير اسم الخادم من :old إلى :new',
|
||||
'description' => 'تم تغيير وصف الخادم من :old إلى :new',
|
||||
],
|
||||
'startup' => [
|
||||
'edit' => 'تم تغيير متغير :variable من ":old" إلى ":new"',
|
||||
'image' => 'تم تحديث صورة Docker للخادم من :old إلى :new',
|
||||
],
|
||||
'subuser' => [
|
||||
'create' => 'تم إضافة :email كمستخدم فرعي',
|
||||
'update' => 'تم تحديث أذونات المستخدم الفرعي لـ :email',
|
||||
'delete' => 'تم إزالة :email كمستخدم فرعي',
|
||||
],
|
||||
],
|
||||
];
|
@ -1,19 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'notices' => [
|
||||
'imported' => 'تم استيراد هذا البيض والمتغيرات المرتبطة به بنجاح.',
|
||||
'updated_via_import' => 'تم تحديث هذا البيض باستخدام الملف المقدم.',
|
||||
'deleted' => 'تم حذف البيض المطلوب بنجاح من اللوحة.',
|
||||
'updated' => 'تم تحديث تكوين البيض بنجاح.',
|
||||
'script_updated' => 'تم تحديث سكريبت تثبيت البيض وسيتم تشغيله كلما تم تثبيت خوادم.',
|
||||
'egg_created' => 'تم وضع بيضة جديدة بنجاح. ستحتاج إلى إعادة تشغيل أي دايمونات جارية لتطبيق هذا البيض الجديد.',
|
||||
],
|
||||
'variables' => [
|
||||
'notices' => [
|
||||
'variable_deleted' => 'تم حذف المتغير ":variable" ولن يكون متاحًا بعد الآن للخوادم بمجرد إعادة بنائها.',
|
||||
'variable_updated' => 'تم تحديث المتغير ":variable". ستحتاج إلى إعادة بناء أي خوادم تستخدم هذا المتغير لتطبيق التغييرات.',
|
||||
'variable_created' => 'تم إنشاء متغير جديد بنجاح وتعيينه لهذا البيض.',
|
||||
],
|
||||
],
|
||||
];
|
@ -1,15 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'validation' => [
|
||||
'fqdn_not_resolvable' => 'النطاق (FQDN) أو عنوان IP المقدم لا يُحل إلى عنوان IP صالح.',
|
||||
'fqdn_required_for_ssl' => 'يتطلب اسم نطاق كامل يُحل إلى عنوان IP عام لاستخدام SSL لهذه العقدة.',
|
||||
],
|
||||
'notices' => [
|
||||
'allocations_added' => 'تم إضافة التخصيصات بنجاح إلى هذه العقدة.',
|
||||
'node_deleted' => 'تم إزالة العقدة بنجاح من اللوحة.',
|
||||
'node_created' => 'تم إنشاء عقدة جديدة بنجاح. يمكنك تكوين الدايمون تلقائيًا على هذه الآلة بزيارة علامة التبويب "التكوين". <strong>قبل أن تتمكن من إضافة أي خوادم يجب عليك أولاً تخصيص عنوان IP واحد على الأقل ومنفذ.</strong>',
|
||||
'node_updated' => 'تم تحديث معلومات العقدة. إذا تم تغيير أي إعدادات دايمون ستحتاج إلى إعادة تشغيله لكي تصبح هذه التغييرات فعالة.',
|
||||
'unallocated_deleted' => 'تم حذف جميع المنافذ غير المخصصة لـ <code>:ip</code>.',
|
||||
],
|
||||
];
|
@ -1,27 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'exceptions' => [
|
||||
'no_new_default_allocation' => 'أنت تحاول حذف التخصيص الافتراضي لهذا الخادم ولكن لا يوجد تخصيص بديل لاستخدامه.',
|
||||
'marked_as_failed' => 'تم تعليم هذا الخادم على أنه فشل في تثبيت سابق. لا يمكن تغيير الحالة الحالية في هذه الحالة.',
|
||||
'bad_variable' => 'كان هناك خطأ في التحقق من المتغير :name.',
|
||||
'daemon_exception' => 'حدث استثناء أثناء محاولة التواصل مع الدايمون مما أدى إلى رمز استجابة HTTP/:code. تم تسجيل هذا الاستثناء. (معرف الطلب: :request_id)',
|
||||
'default_allocation_not_found' => 'لم يتم العثور على التخصيص الافتراضي المطلوب في تخصيصات هذا الخادم.',
|
||||
],
|
||||
'alerts' => [
|
||||
'startup_changed' => 'تم تحديث تكوين البدء لهذا الخادم. إذا تم تغيير بيضة هذا الخادم، فسيحدث إعادة تثبيت الآن.',
|
||||
'server_deleted' => 'تم حذف الخادم بنجاح من النظام.',
|
||||
'server_created' => 'تم إنشاء الخادم بنجاح على اللوحة. الرجاء السماح للدايمون ببضع دقائق لإكمال تثبيت هذا الخادم.',
|
||||
'build_updated' => 'تم تحديث تفاصيل بناء هذا الخادم. قد تتطلب بعض التغييرات إعادة التشغيل لتصبح فعالة.',
|
||||
'suspension_toggled' => 'تم تغيير حالة تعليق الخادم إلى :status.',
|
||||
'rebuild_on_boot' => 'تم تعليم هذا الخادم على أنه يتطلب إعادة بناء حاوية Docker. سيحدث هذا عند التشغيل التالي للخادم.',
|
||||
'install_toggled' => 'تم تغيير حالة التثبيت لهذا الخادم.',
|
||||
'server_reinstalled' => 'تم وضع هذا الخادم في قائمة الانتظار لإعادة التثبيت التي تبدأ الآن.',
|
||||
'details_updated' => 'تم تحديث تفاصيل الخادم بنجاح.',
|
||||
'docker_image_updated' => 'تم تغيير صورة Docker الافتراضية المستخدمة لهذا الخادم بنجاح. يلزم إعادة التشغيل لتطبيق هذا التغيير.',
|
||||
'node_required' => 'يجب أن يكون لديك عقدة واحدة على الأقل مكونة قبل أن تتمكن من إضافة خادم إلى هذه اللوحة.',
|
||||
'transfer_nodes_required' => 'يجب أن يكون لديك عقدتين على الأقل مكونتين قبل أن تتمكن من نقل الخوادم.',
|
||||
'transfer_started' => 'تم بدء نقل الخادم.',
|
||||
'transfer_not_viable' => 'العقدة التي اخترتها لا تملك مساحة القرص أو الذاكرة المطلوبة لاستيعاب هذا الخادم.',
|
||||
],
|
||||
];
|
@ -1,12 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'exceptions' => [
|
||||
'user_has_servers' => 'لا يمكن حذف مستخدم لديه خوادم نشطة مرتبطة بحسابه. يرجى حذف خوادمهم قبل المتابعة.',
|
||||
'user_is_self' => 'لا يمكنك حذف حساب المستخدم الخاص بك.',
|
||||
],
|
||||
'notices' => [
|
||||
'account_created' => 'تم إنشاء الحساب بنجاح.',
|
||||
'account_updated' => 'تم تحديث الحساب بنجاح.',
|
||||
],
|
||||
];
|
@ -1,27 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'sign_in' => 'تسجيل الدخول',
|
||||
'go_to_login' => 'الذهاب إلى صفحة الدخول',
|
||||
'failed' => 'لم يتم العثور على حساب يتطابق مع هذه البيانات.',
|
||||
|
||||
'forgot_password' => [
|
||||
'label' => 'نسيت كلمة المرور؟',
|
||||
'label_help' => 'أدخل عنوان بريدك الإلكتروني لتتلقى تعليمات حول إعادة تعيين كلمة المرور.',
|
||||
'button' => 'استعادة الحساب',
|
||||
],
|
||||
|
||||
'reset_password' => [
|
||||
'button' => 'إعادة تعيين وتسجيل الدخول',
|
||||
],
|
||||
|
||||
'two_factor' => [
|
||||
'label' => 'رمز التحقق ذو العاملين',
|
||||
'label_help' => 'هذا الحساب يتطلب طبقة ثانية من التحقق للمتابعة. الرجاء إدخال الرمز المولد على جهازك لإكمال هذا التسجيل.',
|
||||
'checkpoint_failed' => 'رمز التحقق ذو العاملين كان غير صالح.',
|
||||
],
|
||||
|
||||
'throttle' => 'عدد محاولات تسجيل الدخول كثيرة جداً. يرجى المحاولة مجدداً بعد :seconds ثوانٍ.',
|
||||
'password_requirements' => 'يجب أن تكون كلمة المرور بطول 8 أحرف على الأقل وأن تكون فريدة لهذا الموقع.',
|
||||
'2fa_must_be_enabled' => 'يتطلب المدير تفعيل التحقق ذو العاملين لحسابك لاستخدام اللوحة.',
|
||||
];
|
@ -1,57 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'user' => [
|
||||
'search_users' => 'أدخل اسم المستخدم، معرّف المستخدم، أو عنوان البريد الإلكتروني',
|
||||
'select_search_user' => 'معرّف المستخدم الذي سيتم حذفه (أدخل \'0\' لإعادة البحث)',
|
||||
'deleted' => 'تم حذف المستخدم بنجاح من اللوحة.',
|
||||
'confirm_delete' => 'هل أنت متأكد من أنك تريد حذف هذا المستخدم من اللوحة؟',
|
||||
'no_users_found' => 'لم يتم العثور على مستخدمين لمصطلح البحث المقدم.',
|
||||
'multiple_found' => 'تم العثور على عدة حسابات للمستخدم المقدم، لا يمكن حذف المستخدم بسبب علامة --no-interaction.',
|
||||
'ask_admin' => 'هل هذا المستخدم مدير؟',
|
||||
'ask_email' => 'عنوان البريد الإلكتروني',
|
||||
'ask_username' => 'اسم المستخدم',
|
||||
'ask_password' => 'كلمة المرور',
|
||||
'ask_password_tip' => 'إذا كنت ترغب في إنشاء حساب بكلمة مرور عشوائية يتم إرسالها بالبريد الإلكتروني للمستخدم، أعد تشغيل هذا الأمر (CTRL+C) ومرر علامة `--no-password`.',
|
||||
'ask_password_help' => 'يجب أن تكون كلمات المرور بطول 8 أحرف على الأقل وتحتوي على حرف كبير ورقم على الأقل.',
|
||||
'2fa_help_text' => [
|
||||
'هذا الأمر سيعطل التوثيق الثنائي لحساب المستخدم إذا كان مفعلاً. يجب استخدام هذا فقط كأمر استرداد حساب إذا كان المستخدم محظورًا من حسابه.',
|
||||
'إذا لم يكن هذا ما تريد القيام به، اضغط CTRL+C للخروج من هذه العملية.',
|
||||
],
|
||||
'2fa_disabled' => 'تم تعطيل التوثيق الثنائي لـ :email.',
|
||||
],
|
||||
'schedule' => [
|
||||
'output_line' => 'جاري إرسال العمل للمهمة الأولى في `:schedule` (:hash).',
|
||||
],
|
||||
'maintenance' => [
|
||||
'deleting_service_backup' => 'جاري حذف ملف النسخ الاحتياطي للخدمة :file.',
|
||||
],
|
||||
'server' => [
|
||||
'rebuild_failed' => 'فشل طلب إعادة بناء ":name" (#:id) على العقدة ":node" مع الخطأ: :message',
|
||||
'reinstall' => [
|
||||
'failed' => 'فشل طلب إعادة تثبيت ":name" (#:id) على العقدة ":node" مع الخطأ: :message',
|
||||
'confirm' => 'أنت على وشك إعادة تثبيت مجموعة من الخوادم. هل ترغب في المتابعة؟',
|
||||
],
|
||||
'power' => [
|
||||
'confirm' => 'أنت على وشك تنفيذ :action ضد :count خوادم. هل ترغب في المتابعة؟',
|
||||
'action_failed' => 'فشل طلب تنفيذ الطاقة لـ ":name" (#:id) على العقدة ":node" مع الخطأ: :message',
|
||||
],
|
||||
],
|
||||
'environment' => [
|
||||
'mail' => [
|
||||
'ask_smtp_host' => 'مضيف SMTP (مثل smtp.gmail.com)',
|
||||
'ask_smtp_port' => 'منفذ SMTP',
|
||||
'ask_smtp_username' => 'اسم مستخدم SMTP',
|
||||
'ask_smtp_password' => 'كلمة مرور SMTP',
|
||||
'ask_mailgun_domain' => 'نطاق Mailgun',
|
||||
'ask_mailgun_endpoint' => 'نقطة نهاية Mailgun',
|
||||
'ask_mailgun_secret' => 'سر Mailgun',
|
||||
'ask_mandrill_secret' => 'سر Mandrill',
|
||||
'ask_postmark_username' => 'مفتاح API Postmark',
|
||||
'ask_driver' => 'أي برنامج يجب استخدامه لإرسال الرسائل البريدية؟',
|
||||
'ask_mail_from' => 'عنوان البريد الإلكتروني الذي يجب أن تنشأ منه الرسائل',
|
||||
'ask_mail_name' => 'الاسم الذي يجب أن تظهر منه الرسائل',
|
||||
'ask_encryption' => 'طريقة التشفير المستخدمة',
|
||||
],
|
||||
],
|
||||
];
|
@ -1,28 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'email' => [
|
||||
'title' => 'تحديث بريدك الإلكتروني',
|
||||
'updated' => 'تم تحديث عنوان بريدك الإلكتروني.',
|
||||
],
|
||||
'password' => [
|
||||
'title' => 'تغيير كلمة مرورك',
|
||||
'requirements' => 'يجب أن تكون كلمة المرور الجديدة مكونة من 8 أحرف على الأقل.',
|
||||
'updated' => 'تم تحديث كلمة المرور الخاصة بك.',
|
||||
],
|
||||
'two_factor' => [
|
||||
'button' => 'إعداد التوثيق الثنائي',
|
||||
'disabled' => 'تم تعطيل التوثيق الثنائي في حسابك. لن يُطلب منك تقديم رمز عند تسجيل الدخول.',
|
||||
'enabled' => 'تم تفعيل التوثيق الثنائي في حسابك! من الآن فصاعدًا، عند تسجيل الدخول، سيُطلب منك تقديم الرمز الذي يُنتجه جهازك.',
|
||||
'invalid' => 'الرمز المقدم غير صالح.',
|
||||
'setup' => [
|
||||
'title' => 'إعداد التوثيق الثنائي',
|
||||
'help' => 'لا يمكن مسح الرمز؟ أدخل الرمز أدناه في تطبيقك:',
|
||||
'field' => 'أدخل الرمز',
|
||||
],
|
||||
'disable' => [
|
||||
'title' => 'تعطيل التوثيق الثنائي',
|
||||
'field' => 'أدخل الرمز',
|
||||
],
|
||||
],
|
||||
];
|
@ -1,8 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'search' => 'ابحث عن الخوادم...',
|
||||
'no_matches' => 'لم يتم العثور على خوادم تطابق معايير البحث المقدمة.',
|
||||
'cpu_title' => 'المعالج',
|
||||
'memory_title' => 'الذاكرة',
|
||||
];
|
@ -1,55 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'daemon_connection_failed' => 'حدث استثناء أثناء محاولة التواصل مع الدايمون مما أدى إلى رمز استجابة HTTP/:code. تم تسجيل هذا الاستثناء.',
|
||||
'node' => [
|
||||
'servers_attached' => 'يجب ألا يكون هناك أي خوادم مرتبطة بالعقدة لكي يتم حذفها.',
|
||||
'daemon_off_config_updated' => 'تم تحديث تكوين الدايمون <strong>لكن</strong>، واجهت مشكلة أثناء محاولة تحديث ملف التكوين تلقائيًا على الدايمون. ستحتاج إلى تحديث ملف التكوين (config.yml) يدويًا لتطبيق هذه التغييرات.',
|
||||
],
|
||||
'allocations' => [
|
||||
'server_using' => 'تم تعيين خادم حاليًا لهذا التخصيص. لا يمكن حذف التخصيص إلا إذا لم يكن هناك خادم معين حاليًا.',
|
||||
'too_many_ports' => 'لا يتم دعم إضافة أكثر من 1000 منفذ في نطاق واحد دفعة واحدة.',
|
||||
'invalid_mapping' => 'التعيين المقدم للمنفذ :port كان غير صالح ولا يمكن معالجته.',
|
||||
'cidr_out_of_range' => 'تسمح ترميزات CIDR فقط بالأقنعة بين /25 و /32.',
|
||||
'port_out_of_range' => 'يجب أن تكون المنافذ في التخصيص أكبر من 1024 وأقل من أو يساوي 65535.',
|
||||
],
|
||||
'egg' => [
|
||||
'delete_has_servers' => 'لا يمكن حذف بيضة تحتوي على خوادم نشطة مرتبطة بها من اللوحة.',
|
||||
'invalid_copy_id' => 'البيضة المختارة لنسخ سكربت منها إما أنها غير موجودة، أو أنها تقوم بنسخ سكربت نفسها.',
|
||||
'has_children' => 'هذه البيضة هي الوالد لواحدة أو أكثر من البيض الأخرى. يرجى حذف تلك البيض قبل حذف هذه البيضة.',
|
||||
],
|
||||
'variables' => [
|
||||
'env_not_unique' => 'يجب أن تكون المتغيرات البيئية :name فريدة لهذه البيضة.',
|
||||
'reserved_name' => 'المتغير البيئي :name محمي ولا يمكن تخصيصه لمتغير.',
|
||||
'bad_validation_rule' => 'قاعدة التحقق ":rule" ليست صالحة لهذا التطبيق.',
|
||||
],
|
||||
'importer' => [
|
||||
'json_error' => 'حدث خطأ أثناء محاولة تحليل ملف JSON: :error.',
|
||||
'file_error' => 'ملف JSON المقدم لم يكن صالحًا.',
|
||||
'invalid_json_provided' => 'الملف JSON المقدم ليس بتنسيق يمكن التعرف عليه.',
|
||||
],
|
||||
'subusers' => [
|
||||
'editing_self' => 'لا يُسمح بتعديل حساب المستخدم الفرعي الخاص بك.',
|
||||
'user_is_owner' => 'لا يمكنك إضافة مالك الخادم كمستخدم فرعي لهذا الخادم.',
|
||||
'subuser_exists' => 'المستخدم ذو البريد الإلكتروني هذا مُعين بالفعل كمستخدم فرعي لهذا الخادم.',
|
||||
],
|
||||
'databases' => [
|
||||
'delete_has_databases' => 'لا يمكن حذف مضيف قاعدة البيانات الذي يحتوي على قواعد بيانات نشطة مرتبطة به.',
|
||||
],
|
||||
'tasks' => [
|
||||
'chain_interval_too_long' => 'أقصى فترة زمنية لمهمة متسلسلة هي 15 دقيقة.',
|
||||
],
|
||||
'locations' => [
|
||||
'has_nodes' => 'لا يمكن حذف موقع يحتوي على عقد نشطة مرتبطة به.',
|
||||
],
|
||||
'users' => [
|
||||
'node_revocation_failed' => 'فشل في إلغاء المفاتيح على <a href=":link">العقدة #:node</a>. :error',
|
||||
],
|
||||
'deployment' => [
|
||||
'no_viable_nodes' => 'لم يتم العثور على عقد تلبي المتطلبات المحددة للنشر التلقائي.',
|
||||
'no_viable_allocations' => 'لم يتم العثور على تخصيصات تلبي المتطلبات للنشر التلقائي.',
|
||||
],
|
||||
'api' => [
|
||||
'resource_not_found' => 'المورد المطلوب غير موجود على هذا الخادم.',
|
||||
],
|
||||
];
|
@ -1,17 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Pagination Language Lines
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following language lines are used by the paginator library to build
|
||||
| the simple pagination links. You are free to change them to anything
|
||||
| you want to customize your views to better match your application.
|
||||
|
|
||||
*/
|
||||
|
||||
'previous' => '« السابق',
|
||||
'next' => 'التالي »',
|
||||
];
|
@ -1,19 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Password Reset Language Lines
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following language lines are the default lines which match reasons
|
||||
| that are given by the password broker for a password update attempt
|
||||
| has failed, such as for an invalid token or invalid new password.
|
||||
|
|
||||
*/
|
||||
'password' => 'يجب أن تكون كلمات المرور ستة أحرف على الأقل وأن تتطابق مع التأكيد.',
|
||||
'reset' => 'تم إعادة تعيين كلمة مرورك!',
|
||||
'sent' => 'لقد أرسلنا رابط إعادة تعيين كلمة المرور إلى بريدك الإلكتروني!',
|
||||
'token' => 'رمز إعادة تعيين كلمة المرور هذا غير صالح.',
|
||||
'user' => 'لا يمكننا العثور على مستخدم بهذا العنوان البريدي الإلكتروني.',
|
||||
];
|
@ -1,33 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'permissions' => [
|
||||
'websocket_*' => 'يتيح الوصول إلى الويب سوكيت لهذا الخادم.',
|
||||
'control_console' => 'يسمح للمستخدم بإرسال بيانات إلى وحدة تحكم الخادم.',
|
||||
'control_start' => 'يسمح للمستخدم بتشغيل نموذج الخادم.',
|
||||
'control_stop' => 'يسمح للمستخدم بإيقاف نموذج الخادم.',
|
||||
'control_restart' => 'يسمح للمستخدم بإعادة تشغيل نموذج الخادم.',
|
||||
'control_kill' => 'يسمح للمستخدم بإنهاء نموذج الخادم.',
|
||||
'user_create' => 'يسمح للمستخدم بإنشاء حسابات مستخدمين جديدة للخادم.',
|
||||
'user_read' => 'يمنح المستخدم إذنًا لعرض المستخدمين المرتبطين بهذا الخادم.',
|
||||
'user_update' => 'يسمح للمستخدم بتعديل المستخدمين الآخرين المرتبطين بهذا الخادم.',
|
||||
'user_delete' => 'يسمح للمستخدم بحذف المستخدمين الآخرين المرتبطين بهذا الخادم.',
|
||||
'file_create' => 'يمنح المستخدم إذنًا بإنشاء ملفات ودلائل جديدة.',
|
||||
'file_read' => 'يسمح للمستخدم برؤية الملفات والمجلدات المرتبطة بهذا نموذج الخادم، بالإضافة إلى عرض محتوياتها.',
|
||||
'file_update' => 'يسمح للمستخدم بتحديث الملفات والمجلدات المرتبطة بالخادم.',
|
||||
'file_delete' => 'يسمح للمستخدم بحذف الملفات والدلائل.',
|
||||
'file_archive' => 'يسمح للمستخدم بإنشاء أرشيفات الملفات وفك ضغط الأرشيفات الموجودة.',
|
||||
'file_sftp' => 'يسمح للمستخدم بتنفيذ الإجراءات المذكورة أعلاه للملفات باستخدام عميل SFTP.',
|
||||
'allocation_read' => 'يتيح الوصول إلى صفحات إدارة تخصيص الخادم.',
|
||||
'allocation_update' => 'يمنح المستخدم إذنًا بإجراء تعديلات على تخصيصات الخادم.',
|
||||
'database_create' => 'يمنح المستخدم إذنًا لإنشاء قاعدة بيانات جديدة للخادم.',
|
||||
'database_read' => 'يمنح المستخدم إذنًا لعرض قواعد البيانات الخاصة بالخادم.',
|
||||
'database_update' => 'يمنح المستخدم إذنًا لإجراء تعديلات على قاعدة بيانات. إذا لم يمتلك المستخدم إذن "عرض كلمة المرور" أيضًا، فلن يتمكن من تعديل كلمة المرور.',
|
||||
'database_delete' => 'يمنح المستخدم إذنًا بحذف نموذج قاعدة البيانات.',
|
||||
'database_view_password' => 'يمنح المستخدم إذنًا لعرض كلمة مرور قاعدة البيانات في النظام.',
|
||||
'schedule_create' => 'يسمح للمستخدم بإنشاء جدول زمني جديد للخادم.',
|
||||
'schedule_read' => 'يمنح المستخدم إذنًا لعرض جداول الخادم.',
|
||||
'schedule_update' => 'يمنح المستخدم إذنًا لإجراء تعديلات على جدول الخادم الحالي.',
|
||||
'schedule_delete' => 'يسمح للمستخدم بحذف جدول الخادم.',
|
||||
],
|
||||
];
|
@ -1,95 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'email' => 'البريد الإلكتروني',
|
||||
'email_address' => 'عنوان البريد الإلكتروني',
|
||||
'user_identifier' => 'اسم المستخدم أو البريد الإلكتروني',
|
||||
'password' => 'كلمة المرور',
|
||||
'new_password' => 'كلمة المرور الجديدة',
|
||||
'confirm_password' => 'تأكيد كلمة المرور الجديدة',
|
||||
'login' => 'تسجيل الدخول',
|
||||
'home' => 'الرئيسية',
|
||||
'servers' => 'الخوادم',
|
||||
'id' => 'الهوية',
|
||||
'name' => 'الاسم',
|
||||
'node' => 'العقدة',
|
||||
'connection' => 'الاتصال',
|
||||
'memory' => 'الذاكرة',
|
||||
'cpu' => 'المعالج',
|
||||
'disk' => 'القرص',
|
||||
'status' => 'الحالة',
|
||||
'search' => 'بحث',
|
||||
'suspended' => 'معلق',
|
||||
'account' => 'الحساب',
|
||||
'security' => 'الأمان',
|
||||
'ip' => 'عنوان IP',
|
||||
'last_activity' => 'آخر نشاط',
|
||||
'revoke' => 'سحب',
|
||||
'2fa_token' => 'رمز التوثيق',
|
||||
'submit' => 'إرسال',
|
||||
'close' => 'إغلاق',
|
||||
'settings' => 'الإعدادات',
|
||||
'configuration' => 'التكوين',
|
||||
'sftp' => 'اتصال FTP محمى',
|
||||
'databases' => 'قواعد البيانات',
|
||||
'memo' => 'مذكرة',
|
||||
'created' => 'تم إنشاؤه',
|
||||
'expires' => 'تنتهي',
|
||||
'public_key' => 'مفتاح عام',
|
||||
'api_access' => 'وصول API',
|
||||
'never' => 'أبداً',
|
||||
'sign_out' => 'تسجيل الخروج',
|
||||
'admin_control' => 'التحكم الإداري',
|
||||
'required' => 'مطلوب',
|
||||
'port' => 'المنفذ',
|
||||
'username' => 'اسم المستخدم',
|
||||
'database' => 'قاعدة البيانات',
|
||||
'new' => 'جديد',
|
||||
'danger' => 'خطر',
|
||||
'create' => 'إنشاء',
|
||||
'select_all' => 'تحديد الكل',
|
||||
'select_none' => 'إلغاء تحديد الكل',
|
||||
'alias' => 'الاسم المستعار',
|
||||
'primary' => 'أساسي',
|
||||
'make_primary' => 'جعله أساسي',
|
||||
'none' => 'لا شيء',
|
||||
'cancel' => 'إلغاء',
|
||||
'created_at' => 'أُنشئ في',
|
||||
'action' => 'عمل',
|
||||
'data' => 'بيانات',
|
||||
'queued' => 'في قائمة الانتظار',
|
||||
'last_run' => 'آخر تشغيل',
|
||||
'next_run' => 'التشغيل التالي',
|
||||
'not_run_yet' => 'لم يتم التشغيل بعد',
|
||||
'yes' => 'نعم',
|
||||
'no' => 'لا',
|
||||
'delete' => 'حذف',
|
||||
'2fa' => 'المصادقة الثنائية',
|
||||
'logout' => 'تسجيل الخروج',
|
||||
'admin_cp' => 'لوحة التحكم الإدارية',
|
||||
'optional' => 'اختياري',
|
||||
'read_only' => 'للقراءة فقط',
|
||||
'relation' => 'علاقة',
|
||||
'owner' => 'المالك',
|
||||
'admin' => 'المدير',
|
||||
'subuser' => 'المستخدم الفرعي',
|
||||
'captcha_invalid' => 'الكابتشا المقدمة غير صالحة.',
|
||||
'tasks' => 'المهام',
|
||||
'seconds' => 'ثواني',
|
||||
'minutes' => 'دقائق',
|
||||
'under_maintenance' => 'تحت الصيانة',
|
||||
'days' => [
|
||||
'sun' => 'الأحد',
|
||||
'mon' => 'الاثنين',
|
||||
'tues' => 'الثلاثاء',
|
||||
'wed' => 'الأربعاء',
|
||||
'thurs' => 'الخميس',
|
||||
'fri' => 'الجمعة',
|
||||
'sat' => 'السبت',
|
||||
],
|
||||
'last_used' => 'آخر استخدام',
|
||||
'enable' => 'تمكين',
|
||||
'disable' => 'تعطيل',
|
||||
'save' => 'حفظ',
|
||||
'copyright' => '® 2024 - بيليكان سنة',
|
||||
];
|
@ -1,106 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Validation Language Lines
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following language lines contain the default error messages used by
|
||||
| the validator class. Some of these rules have multiple versions such
|
||||
| as the size rules. Feel free to tweak each of these messages here.
|
||||
|
|
||||
*/
|
||||
|
||||
'accepted' => 'يجب قبول :attribute.',
|
||||
'active_url' => ':attribute ليس عنوان URL صالحًا.',
|
||||
'after' => 'يجب أن يكون :attribute تاريخًا بعد :date.',
|
||||
'after_or_equal' => 'يجب أن يكون :attribute تاريخًا لاحقًا أو مساويًا لتاريخ :date.',
|
||||
'alpha' => 'يجب أن يحتوي :attribute على حروف فقط.',
|
||||
'alpha_dash' => 'يجب أن يحتوي :attribute على حروف، أرقام، وشرطات.',
|
||||
'alpha_num' => 'يجب أن يحتوي :attribute على حروف وأرقام فقط.',
|
||||
'array' => 'يجب أن يكون :attribute مصفوفة.',
|
||||
'before' => 'يجب أن يكون :attribute تاريخًا قبل :date.',
|
||||
'before_or_equal' => 'يجب أن يكون :attribute تاريخًا قبل أو يساوي :date.',
|
||||
'between' => [
|
||||
'numeric' => 'يجب أن يكون :attribute بين :min و :max.',
|
||||
'file' => 'يجب أن يكون حجم :attribute بين :min و :max كيلوبايت.',
|
||||
'string' => 'يجب أن يكون طول :attribute بين :min و :max حرفًا.',
|
||||
'array' => 'يجب أن يحتوي :attribute على :min إلى :max عناصر.',
|
||||
],
|
||||
'boolean' => 'يجب أن يكون :attribute صحيحًا أو خاطئًا.',
|
||||
'confirmed' => 'تأكيد :attribute غير متطابق.',
|
||||
'date' => ':attribute ليس تاريخًا صالحًا.',
|
||||
'date_format' => ':attribute لا يتطابق مع الشكل :format.',
|
||||
'different' => 'يجب أن يكون :attribute و :other مختلفين.',
|
||||
'digits' => 'يجب أن يكون :attribute :digits أرقام.',
|
||||
'digits_between' => 'يجب أن يكون :attribute بين :min و :max رقمًا.',
|
||||
'dimensions' => ':attribute يحتوي على أبعاد صورة غير صالحة.',
|
||||
'distinct' => 'الحقل :attribute يحتوي على قيمة مكررة.',
|
||||
'email' => 'يجب أن يكون :attribute عنوان بريد إلكتروني صالحًا.',
|
||||
'exists' => 'ال:attribute المحدد غير صالح.',
|
||||
'file' => 'يجب أن يكون :attribute ملفًا.',
|
||||
'filled' => 'حقل :attribute إلزامي.',
|
||||
'image' => 'يجب أن يكون :attribute صورة.',
|
||||
'in' => ':attribute المحدد غير صالح.',
|
||||
'in_array' => 'حقل :attribute غير موجود في :other.',
|
||||
'integer' => 'يجب أن يكون :attribute عددًا صحيحًا.',
|
||||
'ip' => 'يجب أن يكون :attribute عنوان IP صالحًا.',
|
||||
'json' => 'يجب أن يكون :attribute نصًا من نوع JSON صالحًا.',
|
||||
'max' => [
|
||||
'numeric' => 'قد لا يكون :attribute أكبر من :max.',
|
||||
'file' => 'قد لا يكون حجم :attribute أكبر من :max كيلوبايت.',
|
||||
'string' => 'قد لا يكون طول :attribute أكثر من :max حرفًا.',
|
||||
'array' => 'قد لا يحتوي :attribute على أكثر من :max عناصر.',
|
||||
],
|
||||
'mimes' => 'يجب أن يكون :attribute ملفًا من نوع: :values.',
|
||||
'mimetypes' => 'يجب أن يكون :attribute ملفًا من نوع: :values.',
|
||||
'min' => [
|
||||
'numeric' => 'يجب أن يكون :attribute على الأقل :min.',
|
||||
'file' => 'يجب أن يكون حجم :attribute على الأقل :min كيلوبايت.',
|
||||
'string' => 'يجب أن يكون طول :attribute على الأقل :min حرفًا.',
|
||||
'array' => 'يجب أن يحتوي :attribute على الأقل :min عناصر.',
|
||||
],
|
||||
'not_in' => ':attribute المحدد غير صالح.',
|
||||
'numeric' => 'يجب أن يكون :attribute رقمًا.',
|
||||
'present' => 'يجب تقديم حقل :attribute.',
|
||||
'regex' => 'تنسيق :attribute غير صالح.',
|
||||
'required' => 'حقل :attribute مطلوب.',
|
||||
'required_if' => 'حقل :attribute مطلوب عندما يكون :other هو :value.',
|
||||
'required_unless' => 'حقل :attribute مطلوب ما لم يكن :other في :values.',
|
||||
'required_with' => 'حقل :attribute مطلوب عند توفر :values.',
|
||||
'required_with_all' => 'حقل :attribute مطلوب عند توفر كل من :values.',
|
||||
'required_without' => 'حقل :attribute مطلوب عند عدم توفر :values.',
|
||||
'required_without_all' => 'حقل :attribute مطلوب عند عدم توفر أي من :values.',
|
||||
'same' => 'يجب أن يتطابق :attribute و :other.',
|
||||
'size' => [
|
||||
'numeric' => 'يجب أن يكون :attribute :size.',
|
||||
'file' => 'يجب أن يكون حجم :attribute :size كيلوبايت.',
|
||||
'string' => 'يجب أن يكون طول :attribute :size حرفًا.',
|
||||
'array' => 'يجب أن يحتوي :attribute على :size عناصر.',
|
||||
],
|
||||
'string' => 'يجب أن يكون :attribute نصًا.',
|
||||
'timezone' => 'يجب أن تكون :attribute منطقة زمنية صالحة.',
|
||||
'unique' => 'تم أخذ :attribute بالفعل.',
|
||||
'uploaded' => 'فشل في تحميل :attribute.',
|
||||
'url' => 'تنسيق :attribute غير صالح.',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Custom Validation Attributes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following language lines are used to swap attribute place-holders
|
||||
| with something more reader friendly such as E-Mail Address instead
|
||||
| of "email". This simply helps us make messages a little cleaner.
|
||||
|
|
||||
*/
|
||||
|
||||
'attributes' => [],
|
||||
|
||||
// Internal validation logic for Panel
|
||||
'internal' => [
|
||||
'variable_value' => 'متغير :env',
|
||||
'invalid_password' => 'كلمة المرور التي تم تقديمها غير صالحة لهذا الحساب.',
|
||||
],
|
||||
];
|
@ -1,130 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Contains all of the translation strings for different activity log
|
||||
* events. These should be keyed by the value in front of the colon (:)
|
||||
* in the event name. If there is no colon present, they should live at
|
||||
* the top level.
|
||||
*/
|
||||
return [
|
||||
'auth' => [
|
||||
'fail' => 'Не атрымалася аўтарызавацца',
|
||||
'success' => 'Увайшоў',
|
||||
'password-reset' => 'Скінуць пароль',
|
||||
'reset-password' => 'Запытаць скіданне пароля',
|
||||
'checkpoint' => 'Двухфактарная аўтэнтыфікацыя ўключана',
|
||||
'recovery-token' => 'Использован резервный код 2FA',
|
||||
'token' => 'Пройдена двухфакторная проверка',
|
||||
'ip-blocked' => 'Заблокирован запрос с IP адреса не внесенного в список для :identifier',
|
||||
'sftp' => [
|
||||
'fail' => 'Не атрымалася аўтарызавацца',
|
||||
],
|
||||
],
|
||||
'user' => [
|
||||
'account' => [
|
||||
'email-changed' => 'Изменена эл. почта с :old на :new',
|
||||
'password-changed' => 'Змяніць пароль',
|
||||
],
|
||||
'api-key' => [
|
||||
'create' => 'Создан новый API ключ :identifier',
|
||||
'delete' => 'Создан новый API ключ :identifier',
|
||||
],
|
||||
'ssh-key' => [
|
||||
'create' => 'Добавлен SSH ключ :fingerprint в аккаунт',
|
||||
'delete' => 'Добавлен SSH ключ :fingerprint в аккаунт',
|
||||
],
|
||||
'two-factor' => [
|
||||
'create' => 'Включена двухфакторная авторизация',
|
||||
'delete' => 'Включена двухфакторная авторизация',
|
||||
],
|
||||
],
|
||||
'server' => [
|
||||
'reinstall' => 'Сервер переустановлен',
|
||||
'console' => [
|
||||
'command' => 'Executed ":command" on the server',
|
||||
],
|
||||
'power' => [
|
||||
'start' => 'Started the server',
|
||||
'stop' => 'Stopped the server',
|
||||
'restart' => 'Restarted the server',
|
||||
'kill' => 'Killed the server process',
|
||||
],
|
||||
'backup' => [
|
||||
'download' => 'Downloaded the :name backup',
|
||||
'delete' => 'Deleted the :name backup',
|
||||
'restore' => 'Restored the :name backup (deleted files: :truncate)',
|
||||
'restore-complete' => 'Completed restoration of the :name backup',
|
||||
'restore-failed' => 'Failed to complete restoration of the :name backup',
|
||||
'start' => 'Started a new backup :name',
|
||||
'complete' => 'Marked the :name backup as complete',
|
||||
'fail' => 'Marked the :name backup as failed',
|
||||
'lock' => 'Locked the :name backup',
|
||||
'unlock' => 'Unlocked the :name backup',
|
||||
],
|
||||
'database' => [
|
||||
'create' => 'Created new database :name',
|
||||
'rotate-password' => 'Password rotated for database :name',
|
||||
'delete' => 'Deleted database :name',
|
||||
],
|
||||
'file' => [
|
||||
'compress_one' => 'Compressed :directory:file',
|
||||
'compress_other' => 'Compressed :count files in :directory',
|
||||
'read' => 'Viewed the contents of :file',
|
||||
'copy' => 'Created a copy of :file',
|
||||
'create-directory' => 'Created directory :directory:name',
|
||||
'decompress' => 'Decompressed :files in :directory',
|
||||
'delete_one' => 'Deleted :directory:files.0',
|
||||
'delete_other' => 'Deleted :count files in :directory',
|
||||
'download' => 'Downloaded :file',
|
||||
'pull' => 'Downloaded a remote file from :url to :directory',
|
||||
'rename_one' => 'Renamed :directory:files.0.from to :directory:files.0.to',
|
||||
'rename_other' => 'Renamed :count files in :directory',
|
||||
'write' => 'Wrote new content to :file',
|
||||
'upload' => 'Began a file upload',
|
||||
'uploaded' => 'Uploaded :directory:file',
|
||||
],
|
||||
'sftp' => [
|
||||
'denied' => 'Blocked SFTP access due to permissions',
|
||||
'create_one' => 'Created :files.0',
|
||||
'create_other' => 'Created :count new files',
|
||||
'write_one' => 'Modified the contents of :files.0',
|
||||
'write_other' => 'Modified the contents of :count files',
|
||||
'delete_one' => 'Deleted :files.0',
|
||||
'delete_other' => 'Deleted :count files',
|
||||
'create-directory_one' => 'Created the :files.0 directory',
|
||||
'create-directory_other' => 'Created :count directories',
|
||||
'rename_one' => 'Renamed :files.0.from to :files.0.to',
|
||||
'rename_other' => 'Renamed or moved :count files',
|
||||
],
|
||||
'allocation' => [
|
||||
'create' => 'Added :allocation to the server',
|
||||
'notes' => 'Updated the notes for :allocation from ":old" to ":new"',
|
||||
'primary' => 'Set :allocation as the primary server allocation',
|
||||
'delete' => 'Deleted the :allocation allocation',
|
||||
],
|
||||
'schedule' => [
|
||||
'create' => 'Created the :name schedule',
|
||||
'update' => 'Updated the :name schedule',
|
||||
'execute' => 'Manually executed the :name schedule',
|
||||
'delete' => 'Deleted the :name schedule',
|
||||
],
|
||||
'task' => [
|
||||
'create' => 'Created a new ":action" task for the :name schedule',
|
||||
'update' => 'Updated the ":action" task for the :name schedule',
|
||||
'delete' => 'Deleted a task for the :name schedule',
|
||||
],
|
||||
'settings' => [
|
||||
'rename' => 'Renamed the server from :old to :new',
|
||||
'description' => 'Changed the server description from :old to :new',
|
||||
],
|
||||
'startup' => [
|
||||
'edit' => 'Changed the :variable variable from ":old" to ":new"',
|
||||
'image' => 'Updated the Docker Image for the server from :old to :new',
|
||||
],
|
||||
'subuser' => [
|
||||
'create' => 'Added :email as a subuser',
|
||||
'update' => 'Updated the subuser permissions for :email',
|
||||
'delete' => 'Removed :email as a subuser',
|
||||
],
|
||||
],
|
||||
];
|
@ -1,19 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'notices' => [
|
||||
'imported' => 'Successfully imported this Egg and its associated variables.',
|
||||
'updated_via_import' => 'This Egg has been updated using the file provided.',
|
||||
'deleted' => 'Successfully deleted the requested egg from the Panel.',
|
||||
'updated' => 'Egg configuration has been updated successfully.',
|
||||
'script_updated' => 'Egg install script has been updated and will run whenever servers are installed.',
|
||||
'egg_created' => 'A new egg was laid successfully. You will need to restart any running daemons to apply this new egg.',
|
||||
],
|
||||
'variables' => [
|
||||
'notices' => [
|
||||
'variable_deleted' => 'The variable ":variable" has been deleted and will no longer be available to servers once rebuilt.',
|
||||
'variable_updated' => 'The variable ":variable" has been updated. You will need to rebuild any servers using this variable in order to apply changes.',
|
||||
'variable_created' => 'New variable has successfully been created and assigned to this egg.',
|
||||
],
|
||||
],
|
||||
];
|
@ -1,15 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'validation' => [
|
||||
'fqdn_not_resolvable' => 'The FQDN or IP address provided does not resolve to a valid IP address.',
|
||||
'fqdn_required_for_ssl' => 'A fully qualified domain name that resolves to a public IP address is required in order to use SSL for this node.',
|
||||
],
|
||||
'notices' => [
|
||||
'allocations_added' => 'Allocations have successfully been added to this node.',
|
||||
'node_deleted' => 'Node has been successfully removed from the panel.',
|
||||
'node_created' => 'Successfully created new node. You can automatically configure the daemon on this machine by visiting the \'Configuration\' tab. <strong>Before you can add any servers you must first allocate at least one IP address and port.</strong>',
|
||||
'node_updated' => 'Node information has been updated. If any daemon settings were changed you will need to reboot it for those changes to take effect.',
|
||||
'unallocated_deleted' => 'Deleted all un-allocated ports for <code>:ip</code>.',
|
||||
],
|
||||
];
|
@ -1,27 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'exceptions' => [
|
||||
'no_new_default_allocation' => 'You are attempting to delete the default allocation for this server but there is no fallback allocation to use.',
|
||||
'marked_as_failed' => 'This server was marked as having failed a previous installation. Current status cannot be toggled in this state.',
|
||||
'bad_variable' => 'There was a validation error with the :name variable.',
|
||||
'daemon_exception' => 'There was an exception while attempting to communicate with the daemon resulting in a HTTP/:code response code. This exception has been logged. (request id: :request_id)',
|
||||
'default_allocation_not_found' => 'The requested default allocation was not found in this server\'s allocations.',
|
||||
],
|
||||
'alerts' => [
|
||||
'startup_changed' => 'The startup configuration for this server has been updated. If this server\'s egg was changed a reinstall will be occurring now.',
|
||||
'server_deleted' => 'Server has successfully been deleted from the system.',
|
||||
'server_created' => 'Server was successfully created on the panel. Please allow the daemon a few minutes to completely install this server.',
|
||||
'build_updated' => 'The build details for this server have been updated. Some changes may require a restart to take effect.',
|
||||
'suspension_toggled' => 'Server suspension status has been changed to :status.',
|
||||
'rebuild_on_boot' => 'This server has been marked as requiring a Docker Container rebuild. This will happen the next time the server is started.',
|
||||
'install_toggled' => 'The installation status for this server has been toggled.',
|
||||
'server_reinstalled' => 'This server has been queued for a reinstallation beginning now.',
|
||||
'details_updated' => 'Server details have been successfully updated.',
|
||||
'docker_image_updated' => 'Successfully changed the default Docker image to use for this server. A reboot is required to apply this change.',
|
||||
'node_required' => 'You must have at least one node configured before you can add a server to this panel.',
|
||||
'transfer_nodes_required' => 'You must have at least two nodes configured before you can transfer servers.',
|
||||
'transfer_started' => 'Server transfer has been started.',
|
||||
'transfer_not_viable' => 'The node you selected does not have the required disk space or memory available to accommodate this server.',
|
||||
],
|
||||
];
|
@ -1,12 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'exceptions' => [
|
||||
'user_has_servers' => 'Cannot delete a user with active servers attached to their account. Please delete their servers before continuing.',
|
||||
'user_is_self' => 'Cannot delete your own user account.',
|
||||
],
|
||||
'notices' => [
|
||||
'account_created' => 'Account has been created successfully.',
|
||||
'account_updated' => 'Account has been successfully updated.',
|
||||
],
|
||||
];
|
@ -1,27 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'sign_in' => 'Sign In',
|
||||
'go_to_login' => 'Go to Login',
|
||||
'failed' => 'No account matching those credentials could be found.',
|
||||
|
||||
'forgot_password' => [
|
||||
'label' => 'Forgot Password?',
|
||||
'label_help' => 'Enter your account email address to receive instructions on resetting your password.',
|
||||
'button' => 'Recover Account',
|
||||
],
|
||||
|
||||
'reset_password' => [
|
||||
'button' => 'Reset and Sign In',
|
||||
],
|
||||
|
||||
'two_factor' => [
|
||||
'label' => '2-Factor Token',
|
||||
'label_help' => 'This account requires a second layer of authentication in order to continue. Please enter the code generated by your device to complete this login.',
|
||||
'checkpoint_failed' => 'The two-factor authentication token was invalid.',
|
||||
],
|
||||
|
||||
'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',
|
||||
'password_requirements' => 'Password must be at least 8 characters in length and should be unique to this site.',
|
||||
'2fa_must_be_enabled' => 'The administrator has required that 2-Factor Authentication be enabled for your account in order to use the Panel.',
|
||||
];
|
@ -1,57 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'user' => [
|
||||
'search_users' => 'Enter a Username, User ID, or Email Address',
|
||||
'select_search_user' => 'ID of user to delete (Enter \'0\' to re-search)',
|
||||
'deleted' => 'User successfully deleted from the Panel.',
|
||||
'confirm_delete' => 'Are you sure you want to delete this user from the Panel?',
|
||||
'no_users_found' => 'No users were found for the search term provided.',
|
||||
'multiple_found' => 'Multiple accounts were found for the user provided, unable to delete a user because of the --no-interaction flag.',
|
||||
'ask_admin' => 'Is this user an administrator?',
|
||||
'ask_email' => 'Email Address',
|
||||
'ask_username' => 'Username',
|
||||
'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_help' => 'Passwords must be at least 8 characters in length and contain at least one capital letter and number.',
|
||||
'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.',
|
||||
],
|
||||
'2fa_disabled' => '2-Factor authentication has been disabled for :email.',
|
||||
],
|
||||
'schedule' => [
|
||||
'output_line' => 'Dispatching job for first task in `:schedule` (:hash).',
|
||||
],
|
||||
'maintenance' => [
|
||||
'deleting_service_backup' => 'Deleting service backup file :file.',
|
||||
],
|
||||
'server' => [
|
||||
'rebuild_failed' => 'Rebuild request for ":name" (#:id) on node ":node" failed with error: :message',
|
||||
'reinstall' => [
|
||||
'failed' => 'Reinstall request for ":name" (#:id) on node ":node" failed with error: :message',
|
||||
'confirm' => 'You are about to reinstall against a group of servers. Do you wish to continue?',
|
||||
],
|
||||
'power' => [
|
||||
'confirm' => 'You are about to perform a :action against :count servers. Do you wish to continue?',
|
||||
'action_failed' => 'Power action request for ":name" (#:id) on node ":node" failed with error: :message',
|
||||
],
|
||||
],
|
||||
'environment' => [
|
||||
'mail' => [
|
||||
'ask_smtp_host' => 'SMTP Host (e.g. smtp.gmail.com)',
|
||||
'ask_smtp_port' => 'SMTP Port',
|
||||
'ask_smtp_username' => 'SMTP Username',
|
||||
'ask_smtp_password' => 'SMTP Password',
|
||||
'ask_mailgun_domain' => 'Mailgun Domain',
|
||||
'ask_mailgun_endpoint' => 'Mailgun Endpoint',
|
||||
'ask_mailgun_secret' => 'Mailgun Secret',
|
||||
'ask_mandrill_secret' => 'Mandrill Secret',
|
||||
'ask_postmark_username' => 'Postmark API Key',
|
||||
'ask_driver' => 'Which driver should be used for sending emails?',
|
||||
'ask_mail_from' => 'Email address emails should originate from',
|
||||
'ask_mail_name' => 'Name that emails should appear from',
|
||||
'ask_encryption' => 'Encryption method to use',
|
||||
],
|
||||
],
|
||||
];
|
@ -1,28 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'email' => [
|
||||
'title' => 'Update your email',
|
||||
'updated' => 'Your email address has been updated.',
|
||||
],
|
||||
'password' => [
|
||||
'title' => 'Change your password',
|
||||
'requirements' => 'Your new password should be at least 8 characters in length.',
|
||||
'updated' => 'Your password has been updated.',
|
||||
],
|
||||
'two_factor' => [
|
||||
'button' => 'Configure 2-Factor Authentication',
|
||||
'disabled' => 'Two-factor authentication has been disabled on your account. You will no longer be prompted to provide a token when logging in.',
|
||||
'enabled' => 'Two-factor authentication has been enabled on your account! From now on, when logging in, you will be required to provide the code generated by your device.',
|
||||
'invalid' => 'The token provided was invalid.',
|
||||
'setup' => [
|
||||
'title' => 'Setup two-factor authentication',
|
||||
'help' => 'Can\'t scan the code? Enter the code below into your application:',
|
||||
'field' => 'Enter token',
|
||||
],
|
||||
'disable' => [
|
||||
'title' => 'Disable two-factor authentication',
|
||||
'field' => 'Enter token',
|
||||
],
|
||||
],
|
||||
];
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user