diff --git a/app/Actions/CronJob/CreateCronJob.php b/app/Actions/CronJob/CreateCronJob.php index c5816a44c..cb3336460 100755 --- a/app/Actions/CronJob/CreateCronJob.php +++ b/app/Actions/CronJob/CreateCronJob.php @@ -29,6 +29,7 @@ public function create(Server $server, array $input, ?Site $site = null): CronJo } $cronJob = new CronJob([ + 'name' => $input['name'] ?? null, 'server_id' => $server->id, 'site_id' => $siteId, 'user' => $input['user'], @@ -59,6 +60,11 @@ private function validate(array $input, Server $server, ?Site $site = null): voi 'required', new CronRule(acceptCustom: true), ], + 'name' => [ + 'nullable', + 'string', + 'max:255', + ], ]; // Add site_id validation if provided in input diff --git a/app/Actions/CronJob/EditCronJob.php b/app/Actions/CronJob/EditCronJob.php index 235971566..ccab33a92 100755 --- a/app/Actions/CronJob/EditCronJob.php +++ b/app/Actions/CronJob/EditCronJob.php @@ -38,6 +38,7 @@ public function edit(Server $server, CronJob $cronJob, array $input, ?Site $site $cronJob->update([ 'site_id' => $siteId, + 'name' => $input['name'] ?? null, 'user' => $input['user'], 'command' => $input['command'], 'frequency' => $input['frequency'] == 'custom' ? $input['custom'] : $input['frequency'], @@ -72,6 +73,11 @@ private function validate(array $input, Server $server, ?Site $site = null): voi 'required', new CronRule(acceptCustom: true), ], + 'name' => [ + 'nullable', + 'string', + 'max:255', + ], ]; // Add site_id validation if provided in input diff --git a/app/Http/Resources/CronJobResource.php b/app/Http/Resources/CronJobResource.php index 444224a46..a2084657a 100644 --- a/app/Http/Resources/CronJobResource.php +++ b/app/Http/Resources/CronJobResource.php @@ -16,6 +16,7 @@ public function toArray(Request $request): array { return [ 'id' => $this->id, + 'name' => $this->name, 'server_id' => $this->server_id, 'site_id' => $this->site_id, 'command' => $this->command, diff --git a/app/Models/CronJob.php b/app/Models/CronJob.php index 87cf4366d..d82c470b9 100755 --- a/app/Models/CronJob.php +++ b/app/Models/CronJob.php @@ -14,6 +14,7 @@ * @property string $user * @property string $frequency * @property bool $hidden + * @property string|null $name * @property CronjobStatus $status * @property string $crontab * @property Server $server @@ -32,6 +33,7 @@ class CronJob extends AbstractModel 'frequency', 'hidden', 'status', + 'name', ]; protected $casts = [ diff --git a/database/factories/CronJobFactory.php b/database/factories/CronJobFactory.php index 21801710b..aaf42c6d8 100644 --- a/database/factories/CronJobFactory.php +++ b/database/factories/CronJobFactory.php @@ -16,6 +16,7 @@ class CronJobFactory extends Factory public function definition(): array { return [ + 'name' => $this->faker->optional()->sentence(3), 'server_id' => 1, 'site_id' => null, 'command' => 'ls -la', diff --git a/database/migrations/2026_01_09_170832_add_name_to_cron_jobs_table.php b/database/migrations/2026_01_09_170832_add_name_to_cron_jobs_table.php new file mode 100644 index 000000000..f979f263b --- /dev/null +++ b/database/migrations/2026_01_09_170832_add_name_to_cron_jobs_table.php @@ -0,0 +1,28 @@ +string('name')->nullable()->index(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('cron_jobs', function (Blueprint $table) { + $table->dropColumn('name'); + }); + } +}; diff --git a/resources/js/pages/cronjobs/components/columns.tsx b/resources/js/pages/cronjobs/components/columns.tsx index da5d332f4..23f3e3610 100644 --- a/resources/js/pages/cronjobs/components/columns.tsx +++ b/resources/js/pages/cronjobs/components/columns.tsx @@ -96,6 +96,15 @@ function Delete({ cronJob, site }: { cronJob: CronJob; site?: Site }) { function getColumns(site?: Site, sites?: Array<{ id: number; domain: string }>): ColumnDef[] { return [ + { + accessorKey: 'name', + header: 'Name', + enableColumnFilter: true, + enableSorting: true, + cell: ({ row }) => { + return {row.original.name || No name}; + }, + }, { accessorKey: 'command', header: 'Command', diff --git a/resources/js/pages/cronjobs/components/form.tsx b/resources/js/pages/cronjobs/components/form.tsx index 445812a50..12abe8075 100644 --- a/resources/js/pages/cronjobs/components/form.tsx +++ b/resources/js/pages/cronjobs/components/form.tsx @@ -36,12 +36,14 @@ export default function CronJobForm({ const page = usePage }>(); const [open, setOpen] = useState(false); const form = useForm<{ + name: string; command: string; user: string; frequency: string; custom: string; site_id: string; }>({ + name: cronJob?.name || '', command: cronJob?.command || '', user: cronJob?.user || '', frequency: cronJob ? (page.props.configs.cronjob_intervals[cronJob.frequency] ? cronJob.frequency : 'custom') : '', @@ -84,6 +86,20 @@ export default function CronJobForm({
+ {/* Name */} + + + form.setData('name', e.target.value)} + placeholder="Optional name for the cron job" + /> + + + + {/* Command */} form.setData('command', e.target.value)} /> diff --git a/resources/js/types/cronjob.d.ts b/resources/js/types/cronjob.d.ts index 6dab828ae..cf3db040e 100644 --- a/resources/js/types/cronjob.d.ts +++ b/resources/js/types/cronjob.d.ts @@ -1,5 +1,6 @@ export interface CronJob { id: number; + name: string | null; server_id: number; site_id: number | null; command: string; diff --git a/tests/Feature/API/SiteCronjobTest.php b/tests/Feature/API/SiteCronjobTest.php index db2d2bf12..96c5ac574 100644 --- a/tests/Feature/API/SiteCronjobTest.php +++ b/tests/Feature/API/SiteCronjobTest.php @@ -74,6 +74,7 @@ public function test_create_site_cronjob(): void 'command' => 'ls -la', 'user' => 'vito', 'frequency' => '* * * * *', + 'name' => 'My Site Cronjob', ]) ->assertSuccessful() ->assertJsonFragment([ @@ -91,6 +92,7 @@ public function test_create_site_cronjob(): void 'user' => 'vito', 'frequency' => '* * * * *', 'status' => CronjobStatus::READY, + 'name' => 'My Site Cronjob', ]); } diff --git a/tests/Feature/CronjobTest.php b/tests/Feature/CronjobTest.php index 2831b85b4..ff8fb8d01 100644 --- a/tests/Feature/CronjobTest.php +++ b/tests/Feature/CronjobTest.php @@ -26,7 +26,6 @@ public function test_see_cronjobs_list(): void $this->get(route('cronjobs', $this->server)) ->assertSuccessful() ->assertInertia(fn (AssertableInertia $page) => $page->component('cronjobs/index')); - } public function test_delete_cronjob(): void @@ -64,6 +63,7 @@ public function test_create_cronjob(): void 'command' => 'ls -la', 'user' => 'vito', 'frequency' => '* * * * *', + 'name' => 'My Cronjob', ]) ->assertSessionDoesntHaveErrors(); @@ -73,6 +73,7 @@ public function test_create_cronjob(): void 'user' => 'vito', 'frequency' => '* * * * *', 'status' => CronjobStatus::READY, + 'name' => 'My Cronjob', ]); SSH::assertExecutedContains("echo '* * * * * ls -la' | sudo -u vito crontab -"); @@ -326,6 +327,7 @@ public function test_edit_cronjob_with_valid_site_id(): void 'user' => 'vito', 'frequency' => '* * * * *', 'site_id' => $site->id, + 'name' => 'Updated Cronjob', ]) ->assertSessionDoesntHaveErrors(); @@ -333,6 +335,7 @@ public function test_edit_cronjob_with_valid_site_id(): void $this->assertEquals($site->id, $cronjob->site_id); $this->assertEquals('updated command', $cronjob->command); + $this->assertEquals('Updated Cronjob', $cronjob->name); } public function test_cannot_edit_cronjob_with_invalid_site_id(): void