Compare commits

..

1 Commits

Author SHA1 Message Date
notCharles
a4fb2bb8ad spotlight 2026-02-01 19:26:23 -05:00
20 changed files with 187 additions and 122 deletions

View File

@@ -22,7 +22,6 @@ use Filament\Forms\Components\ToggleButtons;
use Filament\Resources\Pages\PageRegistration;
use Filament\Resources\Resource;
use Filament\Schemas\Components\Fieldset;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Schema;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
@@ -114,44 +113,12 @@ class ApiKeyResource extends Resource
*/
public static function defaultForm(Schema $schema): Schema
{
$permissionList = ApiKey::getPermissionList();
return $schema
->components([
Section::make(trans('admin/apikey.permissions.all'))
->description(trans('admin/apikey.permissions.all_description'))
->columnSpanFull()
->schema([
ToggleButtons::make('permissions_all')
->hiddenLabel()
->inline()
->options([
0 => trans('admin/apikey.permissions.none'),
1 => trans('admin/apikey.permissions.read'),
3 => trans('admin/apikey.permissions.read_write'),
])
->icons([
0 => TablerIcon::BookOff,
1 => TablerIcon::Book,
3 => TablerIcon::Writing,
])
->colors([
0 => 'success',
1 => 'warning',
3 => 'danger',
])
->live()
->afterStateUpdated(function ($state, callable $set) use ($permissionList) {
foreach ($permissionList as $resource) {
$set('permissions_' . $resource, $state);
}
})
->default(0),
]),
Fieldset::make('Permissions')
->columnSpanFull()
->schema(
collect($permissionList)->map(fn ($resource) => ToggleButtons::make('permissions_' . $resource)
collect(ApiKey::getPermissionList())->map(fn ($resource) => ToggleButtons::make('permissions_' . $resource)
->label(str($resource)->replace('_', ' ')->title())->inline()
->options([
0 => trans('admin/apikey.permissions.none'),

View File

@@ -450,7 +450,17 @@ class EditEgg extends EditRecord
return [
DeleteAction::make()
->disabled(fn (Egg $egg): bool => $egg->servers()->count() > 0)
->tooltip(fn (Egg $egg): string => $egg->servers()->count() <= 0 ? trans('filament-actions::delete.single.label') : trans('admin/egg.in_use')),
->tooltip(fn (Egg $egg): string => $egg->servers()->count() <= 0 ? trans('filament-actions::delete.single.label') : trans('admin/egg.in_use'))
->successNotification(fn (Egg $egg) => Notification::make()
->success()
->title(trans('admin/egg.delete_success'))
->body(trans('admin/egg.deleted', ['egg' => $egg->name]))
)
->failureNotification(fn (Egg $egg) => Notification::make()
->danger()
->title(trans('admin/egg.delete_failed'))
->body(trans('admin/egg.could_not_delete', ['egg' => $egg->name]))
),
ExportEggAction::make(),
ImportEggAction::make()
->multiple(false),

View File

@@ -278,14 +278,6 @@ class CreateNode extends CreateRecord
->default(256)
->minValue(1)
->suffix(config('panel.use_binary_prefix') ? 'MiB' : 'MB'),
TextInput::make('daemon_base')
->label(trans('admin/node.daemon_base'))
->placeholder('/var/lib/pelican/volumes')
->hintIcon(TablerIcon::QuestionMark, trans('admin/node.daemon_base_help'))
->columnSpan(1)
->required()
->default('/var/lib/pelican/volumes')
->rule('regex:/^([\/][\d\w.\-\/]+)$/'),
TextInput::make('daemon_sftp')
->columnSpan(1)
->label(trans('admin/node.sftp_port'))
@@ -295,7 +287,7 @@ class CreateNode extends CreateRecord
->required()
->integer(),
TextInput::make('daemon_sftp_alias')
->columnSpan(1)
->columnSpan(2)
->label(trans('admin/node.sftp_alias'))
->helperText(trans('admin/node.sftp_alias_help')),
Grid::make()

View File

@@ -314,7 +314,7 @@ class EditNode extends EditRecord
'default' => 1,
'sm' => 1,
'md' => 2,
'lg' => 3,
'lg' => 2,
]),
TextInput::make('upload_size')
->columnSpan([
@@ -329,24 +329,12 @@ class EditNode extends EditRecord
->required()
->minValue(1)
->suffix(config('panel.use_binary_prefix') ? 'MiB' : 'MB'),
TextInput::make('daemon_base')
->label(trans('admin/node.daemon_base'))
->placeholder('/var/lib/pelican/volumes')
->hintIcon(TablerIcon::QuestionMark, trans('admin/node.daemon_base_help'))
->columnSpan([
'default' => 1,
'sm' => 1,
'md' => 2,
'lg' => 2,
])
->required()
->rule('regex:/^([\/][\d\w.\-\/]+)$/'),
TextInput::make('daemon_sftp')
->columnSpan([
'default' => 1,
'sm' => 1,
'md' => 2,
'lg' => 1,
'md' => 1,
'lg' => 3,
])
->label(trans('admin/node.sftp_port'))
->minValue(1)
@@ -358,8 +346,8 @@ class EditNode extends EditRecord
->columnSpan([
'default' => 1,
'sm' => 1,
'md' => 2,
'lg' => 2,
'md' => 1,
'lg' => 3,
])
->label(trans('admin/node.sftp_alias'))
->helperText(trans('admin/node.sftp_alias_help')),
@@ -368,7 +356,7 @@ class EditNode extends EditRecord
'default' => 1,
'sm' => 1,
'md' => 1,
'lg' => 2,
'lg' => 3,
])
->label(trans('admin/node.use_for_deploy'))
->inline()
@@ -386,7 +374,7 @@ class EditNode extends EditRecord
'default' => 1,
'sm' => 1,
'md' => 1,
'lg' => 2,
'lg' => 3,
])
->label(trans('admin/node.maintenance_mode'))
->inline()
@@ -584,7 +572,7 @@ class EditNode extends EditRecord
->columnSpanFull()
->schema([
Actions::make([
Action::make('exclude_autoDeploy')
Action::make('autoDeploy')
->label(trans('admin/node.auto_deploy'))
->color('primary')
->modalHeading(trans('admin/node.auto_deploy'))
@@ -622,7 +610,7 @@ class EditNode extends EditRecord
}),
])->fullWidth(),
Actions::make([
Action::make('exclude_resetKey')
Action::make('resetKey')
->label(trans('admin/node.reset_token'))
->color('danger')
->requiresConfirmation()

View File

@@ -66,14 +66,6 @@ class Login extends BaseLogin
->extraInputAttributes(['tabindex' => 1]);
}
protected function getPasswordFormComponent(): Component
{
/** @var TextInput $component */
$component = parent::getPasswordFormComponent();
return $component->extraInputAttributes(['tabindex' => 2]);
}
protected function getOAuthFormComponent(): Component
{
$actions = [];

View File

@@ -39,17 +39,13 @@ class CreateSchedule extends CreateRecord
$data['server_id'] = $server->id;
}
$timezone = $data['timezone'] ?? user()->timezone ?? 'UTC';
unset($data['timezone']);
if (!isset($data['next_run_at'])) {
$data['next_run_at'] = ScheduleResource::getNextRun(
$data['cron_minute'],
$data['cron_hour'],
$data['cron_day_of_month'],
$data['cron_month'],
$data['cron_day_of_week'],
$timezone
$data['cron_day_of_week']
);
}

View File

@@ -37,16 +37,12 @@ class EditSchedule extends EditRecord
protected function mutateFormDataBeforeSave(array $data): array
{
$timezone = $data['timezone'] ?? user()->timezone ?? 'UTC';
unset($data['timezone']);
$data['next_run_at'] = ScheduleResource::getNextRun(
$data['cron_minute'],
$data['cron_hour'],
$data['cron_day_of_month'],
$data['cron_month'],
$data['cron_day_of_week'],
$timezone
$data['cron_day_of_week']
);
return $data;

View File

@@ -100,15 +100,13 @@ class ScheduleResource extends Resource
Section::make('Cron')
->label(trans('server/schedule.cron'))
->description(function (Get $get) {
$timezone = $get('timezone') ?? user()->timezone ?? 'UTC';
try {
$nextRun = Utilities::getScheduleNextRunDate($get('cron_minute'), $get('cron_hour'), $get('cron_day_of_month'), $get('cron_month'), $get('cron_day_of_week'), $timezone)->timezone($timezone);
$nextRun = Utilities::getScheduleNextRunDate($get('cron_minute'), $get('cron_hour'), $get('cron_day_of_month'), $get('cron_month'), $get('cron_day_of_week'))->timezone(user()->timezone ?? 'UTC');
} catch (Exception) {
$nextRun = trans('server/schedule.invalid');
}
return new HtmlString(trans('server/schedule.cron_body', ['timezone' => $timezone]) . '<br>' . trans('server/schedule.cron_timezone', ['timezone' => $timezone, 'next_run' => $nextRun]));
return new HtmlString(trans('server/schedule.cron_body') . '<br>' . trans('server/schedule.cron_timezone', ['timezone' => user()->timezone ?? 'UTC', 'next_run' => $nextRun]));
})
->schema([
Actions::make([
@@ -297,13 +295,6 @@ class ScheduleResource extends Resource
'default' => 4,
'lg' => 5,
]),
Select::make('timezone')
->label(trans('server/schedule.timezone'))
->options(fn () => array_combine(timezone_identifiers_list(), timezone_identifiers_list()))
->default(user()->timezone ?? 'UTC')
->searchable()
->live()
->hiddenOn('view'),
])
->columnSpanFull(),
]);
@@ -388,10 +379,10 @@ class ScheduleResource extends Resource
];
}
public static function getNextRun(string $minute, string $hour, string $dayOfMonth, string $month, string $dayOfWeek, string $timezone = 'UTC'): Carbon
public static function getNextRun(string $minute, string $hour, string $dayOfMonth, string $month, string $dayOfWeek): Carbon
{
try {
return Utilities::getScheduleNextRunDate($minute, $hour, $dayOfMonth, $month, $dayOfWeek, $timezone);
return Utilities::getScheduleNextRunDate($minute, $hour, $dayOfMonth, $month, $dayOfWeek);
} catch (Exception) {
Notification::make()
->title(trans('server/schedule.notification_invalid_cron'))

View File

@@ -38,11 +38,11 @@ class Utilities
*
* @throws Exception
*/
public static function getScheduleNextRunDate(string $minute, string $hour, string $dayOfMonth, string $month, string $dayOfWeek, string $timezone = 'UTC'): Carbon
public static function getScheduleNextRunDate(string $minute, string $hour, string $dayOfMonth, string $month, string $dayOfWeek): Carbon
{
return Carbon::instance((new CronExpression(
sprintf('%s %s %s %s %s', $minute, $hour, $dayOfMonth, $month, $dayOfWeek)
))->getNextRunDate(now($timezone)))->setTimezone('UTC');
))->getNextRunDate(now('UTC')));
}
public static function checked(string $name, mixed $default): string

View File

@@ -75,7 +75,7 @@ class ScheduleController extends ClientApiController
'cron_minute' => $request->input('minute'),
'is_active' => (bool) $request->input('is_active'),
'only_when_online' => (bool) $request->input('only_when_online'),
'next_run_at' => $this->getNextRunAt($request, $request->user()->timezone ?? 'UTC'),
'next_run_at' => $this->getNextRunAt($request),
]);
Activity::event('server:schedule.create')
@@ -131,7 +131,7 @@ class ScheduleController extends ClientApiController
'cron_minute' => $request->input('minute'),
'is_active' => $active,
'only_when_online' => (bool) $request->input('only_when_online'),
'next_run_at' => $this->getNextRunAt($request, $request->user()->timezone ?? 'UTC'),
'next_run_at' => $this->getNextRunAt($request),
];
// Toggle the processing state of the scheduled task when it is enabled or disabled so that an
@@ -188,7 +188,7 @@ class ScheduleController extends ClientApiController
*
* @throws DisplayException
*/
protected function getNextRunAt(Request $request, string $timezone = 'UTC'): Carbon
protected function getNextRunAt(Request $request): Carbon
{
try {
return Utilities::getScheduleNextRunDate(
@@ -196,8 +196,7 @@ class ScheduleController extends ClientApiController
$request->input('hour'),
$request->input('day_of_month'),
$request->input('month'),
$request->input('day_of_week'),
$timezone
$request->input('day_of_week')
);
} catch (Exception) {
throw new DisplayException('The cron data provided does not evaluate to a valid expression.');

View File

@@ -22,6 +22,7 @@ use Illuminate\Routing\Middleware\SubstituteBindings;
use Illuminate\Session\Middleware\AuthenticateSession;
use Illuminate\Session\Middleware\StartSession;
use Illuminate\View\Middleware\ShareErrorsFromSession;
use pxlrbt\FilamentSpotlight\SpotlightPlugin;
abstract class PanelProvider extends BasePanelProvider
{
@@ -71,6 +72,9 @@ abstract class PanelProvider extends BasePanelProvider
->authMiddleware([
Authenticate::class,
RequireTwoFactorAuthentication::class,
])
->plugins([
SpotlightPlugin::make(),
]);
}
}

View File

@@ -27,6 +27,7 @@
"phiki/phiki": "^2.0",
"phpseclib/phpseclib": "~3.0.18",
"predis/predis": "^2.3",
"pxlrbt/filament-spotlight": "^2.0",
"s1lentium/iptools": "~1.2.0",
"secondnetwork/blade-tabler-icons": "^3.26",
"socialiteproviders/authentik": "^5.2",

142
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "15f89930db77693b2d692dbadf22fb9f",
"content-hash": "b237f8d4615d4112d48a3bb424fd5358",
"packages": [
{
"name": "anourvalar/eloquent-serialize",
@@ -6603,6 +6603,72 @@
},
"time": "2026-01-30T17:33:13+00:00"
},
{
"name": "pxlrbt/filament-spotlight",
"version": "v2.0.4",
"source": {
"type": "git",
"url": "https://github.com/pxlrbt/filament-spotlight.git",
"reference": "6f76af3b14304aff00d5ae65d16f5d46916b89f5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pxlrbt/filament-spotlight/zipball/6f76af3b14304aff00d5ae65d16f5d46916b89f5",
"reference": "6f76af3b14304aff00d5ae65d16f5d46916b89f5",
"shasum": ""
},
"require": {
"filament/filament": "^3.0|^4.0",
"php": "^8.0",
"wire-elements/spotlight": "^2.0"
},
"require-dev": {
"laravel/pint": "^1.10"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"pxlrbt\\FilamentSpotlight\\SpotlightServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"pxlrbt\\FilamentSpotlight\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Dennis Koch",
"email": "info@pixelarbeit.de"
}
],
"description": "Spotlight for Filament Admin",
"keywords": [
"alfred",
"filament",
"laravel",
"laravel-filament",
"spotlight",
"wire-elements"
],
"support": {
"issues": "https://github.com/pxlrbt/filament-spotlight/issues",
"source": "https://github.com/pxlrbt/filament-spotlight/tree/v2.0.4"
},
"funding": [
{
"url": "https://github.com/pxlrbt",
"type": "github"
}
],
"time": "2025-11-20T22:43:31+00:00"
},
{
"name": "ralouphie/getallheaders",
"version": "3.0.3",
@@ -11622,6 +11688,80 @@
"source": "https://github.com/webmozarts/assert/tree/1.11.0"
},
"time": "2022-06-03T18:03:27+00:00"
},
{
"name": "wire-elements/spotlight",
"version": "2.0.2",
"source": {
"type": "git",
"url": "https://github.com/wire-elements/spotlight.git",
"reference": "69839f33d082c49306161946dbaedc69e525695e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/wire-elements/spotlight/zipball/69839f33d082c49306161946dbaedc69e525695e",
"reference": "69839f33d082c49306161946dbaedc69e525695e",
"shasum": ""
},
"require": {
"illuminate/contracts": "^8.0|^9.0|^10.0|^11.0|^12.0",
"livewire/livewire": "^3.0",
"php": "^8.1",
"spatie/laravel-package-tools": "^1.4.3"
},
"require-dev": {
"brianium/paratest": "^6.2|^7.4",
"nunomaduro/collision": "^5.3|^8.0",
"orchestra/testbench": "^6.15|^7.0|^8.0|^9.0|^10.0",
"phpunit/phpunit": "^9.3|^10.5|^11.5.3",
"vimeo/psalm": "^4.4|^5.22|^6.5"
},
"type": "library",
"extra": {
"laravel": {
"aliases": {
"Spotlight": "LivewireUI\\Spotlight\\SpotlightFacade"
},
"providers": [
"LivewireUI\\Spotlight\\SpotlightServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"LivewireUI\\Spotlight\\": "src",
"LivewireUI\\Spotlight\\Database\\Factories\\": "database/factories"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Philo Hermans",
"email": "support@wire-elements.dev",
"role": "Developer"
}
],
"description": "Livewire component that provides Spotlight/Alfred-like functionality to your Laravel application.",
"homepage": "https://github.com/wire-elements/spotlight",
"keywords": [
"laravel",
"livewire-ui",
"spotlight"
],
"support": {
"issues": "https://github.com/wire-elements/spotlight/issues",
"source": "https://github.com/wire-elements/spotlight/tree/2.0.2"
},
"funding": [
{
"url": "https://github.com/PhiloNL",
"type": "github"
}
],
"time": "2025-02-26T07:06:17+00:00"
}
],
"packages-dev": [

View File

@@ -20,8 +20,6 @@ return [
'never_used' => 'Never Used',
],
'permissions' => [
'all' => 'Set All Permissions',
'all_description' => 'Quickly set all permissions below to the same level.',
'none' => 'None',
'read' => 'Read',
'read_write' => 'Read & Write',

View File

@@ -115,6 +115,10 @@ return [
'no_update_url' => 'The following eggs do not have a working update URL set: :eggs',
'cannot_delete' => 'Cannot delete :count egg(s)',
'eggs_have_servers' => 'The following eggs have servers and cannot be deleted: :eggs',
'delete_success' => 'Egg deleted successfully',
'deleted' => 'Deleted: :egg',
'delete_failed' => 'Failed to delete egg',
'could_not_delete' => 'Could not delete: :egg',
'updated_from' => 'Successfully updated from: :url',
'update_error' => 'Error: :error',
'updated_eggs' => 'Updated: :eggs',

View File

@@ -65,8 +65,6 @@ return [
'sftp_port' => 'SFTP Port',
'sftp_alias' => 'SFTP Alias',
'sftp_alias_help' => 'Display alias for the SFTP address. Leave empty to use the Node FQDN.',
'daemon_base' => 'Daemon Base Directory',
'daemon_base_help' => 'The directory where server data will be stored.',
'use_for_deploy' => 'Use for Deployments?',
'maintenance_mode' => 'Maintenance Mode',
'maintenance_mode_help' => 'If the node is marked \'Under Maintenance\' users won\'t be able to access servers that are on that node',

View File

@@ -29,8 +29,7 @@ return [
'enabled' => 'Enable Schedule?',
'enabled_hint' => 'This schedule will be executed automatically if enabled.',
'timezone' => 'Timezone',
'cron_body' => 'The cron inputs below use your timezone (:timezone).',
'cron_body' => 'Please keep in mind that the cron inputs below always assume UTC.',
'cron_timezone' => 'Next run in your timezone (:timezone): <b> :next_run </b>',
'invalid' => 'Invalid',

File diff suppressed because one or more lines are too long

View File

@@ -25,5 +25,6 @@
@import '../../vendor/filament/widgets/resources/css/index.css';
@source '../../vendor/gboquizosanchez/filament-log-viewer/resources/views/**/*.blade.php';
@source '../../vendor/wire-elements/**/*.blade.php';
@variant dark (&:where(.dark, .dark *));

View File

@@ -1,16 +1,4 @@
<x-filament-panels::page>
@once
<style>
.files-selection-merged .fi-ta-header-ctn {
position: sticky;
top: 0;
z-index: 1;
-webkit-backdrop-filter: blur(8px);
backdrop-filter: blur(8px);
}
</style>
@endonce
<div
x-data="
{