Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,17 @@ protected function mutateFormDataBeforeCreate(array $data): array
$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']
$data['cron_day_of_week'],
$timezone
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,16 @@ protected function afterSave(): void

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']
$data['cron_day_of_week'],
$timezone
);

return $data;
Expand Down
17 changes: 13 additions & 4 deletions app/Filament/Server/Resources/Schedules/ScheduleResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,15 @@ public static function defaultForm(Schema $schema): Schema
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(user()->timezone ?? 'UTC');
$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);
} catch (Exception) {
$nextRun = trans('server/schedule.invalid');
}

return new HtmlString(trans('server/schedule.cron_body') . '<br>' . trans('server/schedule.cron_timezone', ['timezone' => user()->timezone ?? 'UTC', 'next_run' => $nextRun]));
return new HtmlString(trans('server/schedule.cron_body', ['timezone' => $timezone]) . '<br>' . trans('server/schedule.cron_timezone', ['timezone' => $timezone, 'next_run' => $nextRun]));
})
->schema([
Actions::make([
Expand Down Expand Up @@ -295,6 +297,13 @@ public static function defaultForm(Schema $schema): Schema
'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'),
Comment on lines +300 to +306
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Apply the same null-safe fix to the default value.

Same issue as above - use the null-safe operator for consistency and safety.

🛡️ Proposed fix
-                            ->default(user()->timezone ?? 'UTC')
+                            ->default(user()?->timezone ?? 'UTC')
🤖 Prompt for AI Agents
In `@app/Filament/Server/Resources/Schedules/ScheduleResource.php` around lines
300 - 306, The Select field for 'timezone' uses user()->timezone in
->default(...) which can throw if user() is null; change the default call in the
Select::make('timezone') chain to use the null-safe operator (user()?->timezone
?? 'UTC') so it safely falls back to 'UTC' when no user exists, keeping the rest
of the chain (options, searchable, live, hiddenOn) unchanged.

])
->columnSpanFull(),
]);
Expand Down Expand Up @@ -379,10 +388,10 @@ public static function getDefaultPages(): array
];
}

public static function getNextRun(string $minute, string $hour, string $dayOfMonth, string $month, string $dayOfWeek): Carbon
public static function getNextRun(string $minute, string $hour, string $dayOfMonth, string $month, string $dayOfWeek, string $timezone = 'UTC'): Carbon
{
try {
return Utilities::getScheduleNextRunDate($minute, $hour, $dayOfMonth, $month, $dayOfWeek);
return Utilities::getScheduleNextRunDate($minute, $hour, $dayOfMonth, $month, $dayOfWeek, $timezone);
} catch (Exception) {
Notification::make()
->title(trans('server/schedule.notification_invalid_cron'))
Expand Down
4 changes: 2 additions & 2 deletions app/Helpers/Utilities.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,11 @@ public static function randomStringWithSpecialCharacters(int $length = 16): stri
*
* @throws Exception
*/
public static function getScheduleNextRunDate(string $minute, string $hour, string $dayOfMonth, string $month, string $dayOfWeek): Carbon
public static function getScheduleNextRunDate(string $minute, string $hour, string $dayOfMonth, string $month, string $dayOfWeek, string $timezone = 'UTC'): Carbon
{
return Carbon::instance((new CronExpression(
sprintf('%s %s %s %s %s', $minute, $hour, $dayOfMonth, $month, $dayOfWeek)
))->getNextRunDate(now('UTC')));
))->getNextRunDate(now($timezone)))->setTimezone('UTC');
}

public static function checked(string $name, mixed $default): string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public function store(StoreScheduleRequest $request, Server $server): array
'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),
'next_run_at' => $this->getNextRunAt($request, $request->user()->timezone ?? 'UTC'),
]);

Activity::event('server:schedule.create')
Expand Down Expand Up @@ -131,7 +131,7 @@ public function update(UpdateScheduleRequest $request, Server $server, Schedule
'cron_minute' => $request->input('minute'),
'is_active' => $active,
'only_when_online' => (bool) $request->input('only_when_online'),
'next_run_at' => $this->getNextRunAt($request),
'next_run_at' => $this->getNextRunAt($request, $request->user()->timezone ?? 'UTC'),
];

// Toggle the processing state of the scheduled task when it is enabled or disabled so that an
Expand Down Expand Up @@ -188,15 +188,16 @@ public function delete(DeleteScheduleRequest $request, Server $server, Schedule
*
* @throws DisplayException
*/
protected function getNextRunAt(Request $request): Carbon
protected function getNextRunAt(Request $request, string $timezone = 'UTC'): Carbon
{
try {
return Utilities::getScheduleNextRunDate(
$request->input('minute'),
$request->input('hour'),
$request->input('day_of_month'),
$request->input('month'),
$request->input('day_of_week')
$request->input('day_of_week'),
$timezone
);
} catch (Exception) {
throw new DisplayException('The cron data provided does not evaluate to a valid expression.');
Expand Down
3 changes: 2 additions & 1 deletion lang/en/server/schedule.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
'enabled' => 'Enable Schedule?',
'enabled_hint' => 'This schedule will be executed automatically if enabled.',

'cron_body' => 'Please keep in mind that the cron inputs below always assume UTC.',
'timezone' => 'Timezone',
'cron_body' => 'The cron inputs below use your timezone (:timezone).',
'cron_timezone' => 'Next run in your timezone (:timezone): <b> :next_run </b>',

'invalid' => 'Invalid',
Expand Down