Skip to content

Commit

Permalink
feat: Added cron preset modal
Browse files Browse the repository at this point in the history
  • Loading branch information
lewislarsen committed Jul 27, 2024
1 parent d08fcb4 commit 62d952a
Show file tree
Hide file tree
Showing 3 changed files with 310 additions and 5 deletions.
189 changes: 187 additions & 2 deletions app/Livewire/BackupTasks/Forms/CreateBackupTaskForm.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
use App\Models\NotificationStream;
use App\Models\RemoteServer;
use App\Models\Tag;
use App\Models\User;
use App\Rules\UniqueScheduledTimePerRemoteServer;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Collection;
Expand Down Expand Up @@ -90,6 +89,13 @@ class CreateBackupTaskForm extends Component
/** @var array<int>|null */
public ?array $selectedStreams = [];

public bool $showCronPresets = false;
public string $cronPresetSearch = '';
/**
* @var array<string, string>
*/
public array $cronPresets = [];

/** @var array<string, string> */
protected array $validationAttributes = [
'label' => 'Label',
Expand All @@ -108,6 +114,60 @@ class CreateBackupTaskForm extends Component
'cronExpression' => 'Cron Expression',
];

/**
* Open the cron presets modal.
*/
public function openCronPresets(): void
{
$this->showCronPresets = true;
}

/**
* Close the cron presets modal.
*/
public function closeCronPresets(): void
{
$this->showCronPresets = false;
}

/**
* Set the cron expression from a preset.
*/
public function setPreset(string $preset): void
{
$this->cronExpression = $preset;
$this->dispatch('close-modal', 'cron-presets');
$this->cronPresetSearch = '';
}

/**
* Get filtered and grouped cron presets based on the current search term.
*
* @return array<string, array<string, string>>
*/
public function getFilteredCronPresets(): array
{
$groupedPresets = [
$this->ensureString(__('Daily Backups')) => [],
$this->ensureString(__('Weekly Backups')) => [],
$this->ensureString(__('Monthly Backups')) => [],
$this->ensureString(__('Custom Intervals')) => [],
$this->ensureString(__('Business Hours')) => [],
];

foreach ($this->cronPresets as $expression => $description) {
if (! $this->matchesSearch($description)) {
continue;
}

$translatedDescription = $this->ensureString(__($description));
$group = $this->determinePresetGroup($translatedDescription);
$groupedPresets[$group][$expression] = $translatedDescription;
}

return $groupedPresets;
}

/**
* Initialize the component state.
*
Expand All @@ -120,6 +180,7 @@ public function mount(): void
$this->initializeBackupTimes();
$this->updatedBackupType();
$this->updatedUseCustomCron();
$this->initializeCronPresets();
}

/**
Expand Down Expand Up @@ -239,6 +300,13 @@ public function render(): View
*/
public function rules(): array
{
$cronRegex = '/^(\*|(\*\/)?([0-5]?[0-9])([-,]([0-5]?[0-9]))*)' // minute
. '\s+(\*|(\*\/)?([0-1]?[0-9]|2[0-3])([-,]([0-1]?[0-9]|2[0-3]))*)' // hour
. '\s+(\*|(\*\/)?([1-2]?[0-9]|3[0-1])([-,]([1-2]?[0-9]|3[0-1]))*)' // day of month
. '\s+(\*|(\*\/)?([1-9]|1[0-2])([-,]([1-9]|1[0-2]))*)' // month
. '\s+(\*|(\*\/)?([0-7])([-,]([0-7]))*)' // day of week
. '$/';

$baseRules = [
'isolatedUsername' => ['nullable', 'string'],
'isolatedPassword' => ['nullable', 'string'],
Expand All @@ -263,7 +331,7 @@ public function rules(): array
'cronExpression' => [
'nullable',
'string',
'regex:/^(\*|([0-5]?\d)) (\*|([01]?\d|2[0-3])) (\*|([0-2]?\d|3[01])) (\*|([1-9]|1[0-2])) (\*|([0-7]))$/',
'regex:' . $cronRegex,
'required_if:useCustomCron,true',
],
];
Expand Down Expand Up @@ -338,6 +406,123 @@ public function getSummary(): array
);
}

/**
* Ensure the given value is a string.
*
* @param string|array<string, string> $value
*/
private function ensureString($value): string
{
if (is_array($value)) {
return implode(', ', $value);
}

return $value;
}

/**
* Determine the group for a given cron preset description.
*/
private function determinePresetGroup(string $description): string
{
$lowercaseDescription = strtolower($description);

if (str_contains($lowercaseDescription, strtolower($this->ensureString(__('Every day'))))) {
return $this->ensureString(__('Daily Backups'));
}

if (str_contains($lowercaseDescription, strtolower($this->ensureString(__('Every week'))))) {
return $this->ensureString(__('Weekly Backups'));
}

if (str_contains($lowercaseDescription, strtolower($this->ensureString(__('Every month')))) ||
str_contains($lowercaseDescription, strtolower($this->ensureString(__('Every 3 months'))))) {
return $this->ensureString(__('Monthly Backups'));
}

if (str_contains($lowercaseDescription, strtolower($this->ensureString(__('Monday to Friday')))) ||
str_contains($lowercaseDescription, strtolower($this->ensureString(__('weekday'))))) {
return $this->ensureString(__('Business Hours'));
}

return $this->ensureString(__('Custom Intervals'));
}

/**
* Check if the description matches the current search term.
*/
private function matchesSearch(string $description): bool
{
if ($this->cronPresetSearch === '' || $this->cronPresetSearch === '0') {
return true;
}

return str_contains(strtolower($description), strtolower($this->cronPresetSearch));
}

/**
* Initialize the cron presets with their translated descriptions.
*/
private function initializeCronPresets(): void
{
$this->cronPresets = [
// Daily backups
'0 0 * * *' => __('Every day at midnight'),
'0 2 * * *' => __('Every day at 2 AM'),
'0 4 * * *' => __('Every day at 4 AM'),
'0 1 * * *' => __('Every day at 1 AM (off-peak hours)'),
'0 23 * * *' => __('Every day at 11 PM'),

// Multiple times per day
'0 */6 * * *' => __('Every 6 hours'),
'0 */12 * * *' => __('Every 12 hours'),
'0 */4 * * *' => __('Every 4 hours'),
'0 */8 * * *' => __('Every 8 hours'),

// Specific days of the week
'0 0 * * 5' => __('Every Friday at midnight'),
'0 0 * * 1' => __('Every Monday at midnight'),
'0 2 * * 6' => __('Every Saturday at 2 AM'),

// Multiple days per week
'0 3 * * 1,4' => __('Every Monday and Thursday at 3 AM'),
'0 2 * * 2,5' => __('Every Tuesday and Friday at 2 AM'),

// Weekly backups
'0 0 * * 0' => __('Every week on Sunday at midnight'),
'0 1 * * 1' => __('Every week on Monday at 1 AM'),

// Monthly backups
'0 0 1 * *' => __('Every month on the 1st at midnight'),
'0 2 1 * *' => __('Every month on the 1st at 2 AM'),
'0 3 15 * *' => __('Every month on the 15th at 3 AM'),

// Quarterly backups
'0 0 1 */3 *' => __('Every 3 months on the 1st at midnight'),

// Yearly backup
'0 0 1 1 *' => __('Every year on Jan 1st at midnight'),

// Less frequent backups
'0 0 */3 * *' => __('Every 3 days at midnight'),
'0 0 */7 * *' => __('Every 7 days at midnight'),
'0 1 */5 * *' => __('Every 5 days at 1 AM'),

// Business hours
'0 9-17 * * 1-5' => __('Every hour from 9 AM to 5 PM, Monday to Friday'),
'0 8,18 * * 1-5' => __('Twice daily at 8 AM and 6 PM, Monday to Friday'),

// End of business day
'0 18 * * 1-5' => __('Every weekday at 6 PM'),

// First and last day of the month
'0 1 1,L * *' => __('On the first and last day of every month at 1 AM'),

// Every weekend
'0 2 * * 6,0' => __('Every Saturday and Sunday at 2 AM'),
];
}

/**
* Initialize default values for the form.
*/
Expand Down
47 changes: 47 additions & 0 deletions lang/da.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
"been run today.": "kørt i dag.",
"Before removing your account, please take a moment to download any data or information that you wish to retain.": "Før du fjerner din konto, bør du tage et øjeblik til at downloade eventuelle data eller oplysninger, du ønsker at beholde.",
"Bucket Name": "Bucket-navn",
"Business Hours": "Arbejdstimer",
"Cancel": "Annuller",
"Cancel Setup": "Annuller opsætning",
"Checking": "Kontrollerer",
Expand All @@ -75,6 +76,7 @@
"Click to run this task": "Klik for at køre denne opgave",
"Click to view this log": "Klik for at se denne log",
"Close": "Luk",
"Common Cron Job Presets": "Almindelige Cron Job Forudindstillinger",
"Configuration": "Konfiguration",
"Configure Backup Destination": "Konfigurér backupdestination",
"Configured Notification streams for your backup tasks.": "Konfigurerede notifikationskanaler til dine backup-opgaver.",
Expand All @@ -96,8 +98,10 @@
"Cron Expression": "Cron-udtryk",
"Current Password": "Nuværende adgangskode",
"Custom Cron Expression": "Brugerdefineret Cron-udtryk",
"Custom Intervals": "Tilpassede Intervaller",
"Custom S3": "Tilpasset S3",
"Daily": "Dagligt",
"Daily Backups": "Daglige Backups",
"Dark": "Mørk",
"Database": "Database",
"database": "database",
Expand All @@ -122,6 +126,37 @@
"Ensure your account is using a long, random password to stay secure.": "Sørg for, at din konto bruger en lang, tilfældig adgangskode for at forblive sikker.",
"Enter an alternative email address to use for your Gravatar picture. If left blank, your primary email will be used.": "Indtast en alternativ e-mailadresse til brug for dit Gravatar-billede. Hvis feltet er tomt, vil din primære e-mail blive brugt.",
"Error! Unable to locate an SSH Key.": "Fejl! Kan ikke finde en SSH-nøgle.",
"Every 12 hours": "Hver 12. time",
"Every 3 days at midnight": "Hver 3. dag ved midnat",
"Every 3 months": "Hver 3. måned",
"Every 3 months on the 1st at midnight": "Hver 3. måned den 1. ved midnat",
"Every 4 hours": "Hver 4. time",
"Every 5 days at 1 AM": "Hver 5. dag klokken 1 om natten",
"Every 6 hours": "Hver 6. time",
"Every 7 days at midnight": "Hver 7. dag ved midnat",
"Every 8 hours": "Hver 8. time",
"Every day": "Hver dag",
"Every day at 1 AM (off-peak hours)": "Hver dag klokken 1 om natten (uden for spidsbelastning)",
"Every day at 11 PM": "Hver dag klokken 23",
"Every day at 2 AM": "Hver dag klokken 2 om natten",
"Every day at 4 AM": "Hver dag klokken 4 om morgenen",
"Every day at midnight": "Hver dag ved midnat",
"Every Friday at midnight": "Hver fredag ved midnat",
"Every hour from 9 AM to 5 PM, Monday to Friday": "Hver time fra 9 til 17, mandag til fredag",
"Every Monday and Thursday at 3 AM": "Hver mandag og torsdag klokken 3 om natten",
"Every Monday at midnight": "Hver mandag ved midnat",
"Every month": "Hver måned",
"Every month on the 15th at 3 AM": "Hver måned den 15. klokken 3 om natten",
"Every month on the 1st at 2 AM": "Hver måned den 1. klokken 2 om natten",
"Every month on the 1st at midnight": "Hver måned den 1. ved midnat",
"Every Saturday and Sunday at 2 AM": "Hver lørdag og søndag klokken 2 om natten",
"Every Saturday at 2 AM": "Hver lørdag klokken 2 om natten",
"Every Tuesday and Friday at 2 AM": "Hver tirsdag og fredag klokken 2 om natten",
"Every week": "Hver uge",
"Every week on Monday at 1 AM": "Hver uge mandag klokken 1 om natten",
"Every week on Sunday at midnight": "Hver uge søndag ved midnat",
"Every weekday at 6 PM": "Hver hverdag klokken 18",
"Every year on Jan 1st at midnight": "Hvert år den 1. januar ved midnat",
"Excluded Database Tables": "Ekskluderede databasetabeller",
"Failed": "Mislykkedes",
"Failed Backups": "Mislykkede backups",
Expand Down Expand Up @@ -160,13 +195,16 @@
"Make your first Backup Task": "Opret din første sikkerhedskopieringsopgave",
"Maximum Backups to Keep": "Maksimalt antal sikkerhedskopier, der skal opbevares",
"MIT License": "MIT-licensen",
"Monday to Friday": "Mandag til fredag",
"Monthly Backup Task Activity": "Månedlig aktivitet for sikkerhedskopieringsopgaver",
"Monthly Backups": "Månedlige Backups",
"Name": "Navn",
"Never": "Aldrig",
"New Password": "Ny adgangskode",
"Next": "Næste",
"No": "Nej",
"No log available": "Ingen log tilgængelig",
"No matching presets found.": "Ingen matchende forudindstillinger fundet.",
"No Notification Streams": "Ingen notifikationskanaler",
"None": "Ingen",
"Not Set": "Ikke indstillet",
Expand All @@ -178,6 +216,7 @@
"Notifications": "Notifikationer",
"Notifications about this backup task will be sent on the notification streams you choose.": "Notifikationer om denne backup-opgave vil blive sendt via de notifikationskanaler, du vælger.",
"Offline": "Offline",
"On the first and last day of every month at 1 AM": "På den første og sidste dag i hver måned klokken 1 om natten",
"Once": "Én gang",
"Once your account is removed, all of its resources and data will be permanently removed. Additionally, all backup tasks, backup destinations, and linked servers will be removed from our systems.": "Når din konto er fjernet, vil alle dens ressourcer og data blive permanent fjernet. Derudover vil alle sikkerhedskopieringsopgaver, sikkerhedskopieringsdestinationer og tilknyttede servere blive fjernet fra vores systemer.",
"One or more of the selected tags do not exist.": "En eller flere af de valgte tags findes ikke.",
Expand Down Expand Up @@ -235,6 +274,7 @@
"Please select your preferred language from the dropdown list. This will change the language used throughout the application.": "Vælg venligst dit foretrukne sprog fra rullelisten. Dette vil ændre sproget, der bruges i hele applikationen.",
"Please specify a language for your account.": "Angiv venligst et sprog for din konto.",
"Please specify a timezone.": "Angiv venligst en tidszone.",
"Presets": "Forudindstillinger",
"Previous": "Forrige",
"Previously Executed Backup Tasks": "Tidligere udførte sikkerhedskopieringsopgaver",
"Proceed": "Fortsæt",
Expand Down Expand Up @@ -279,7 +319,9 @@
"Scheduled": "Planlagt",
"Scheduled backup tasks that are set to run soon.": "Planlagte sikkerhedskopieringsopgaver, der skal køres snart.",
"Scheduled for": "Planlagt til",
"Search Presets": "Søg Forudindstillinger",
"Secret Key": "Hemmelig nøgle",
"Select a preset to quickly set up common backup schedules. The cron expression will be automatically filled in for you.": "Vælg en forudindstilling for hurtigt at opsætte almindelige backup-planer. Cron-udtrykket vil automatisk blive udfyldt for dig.",
"Server & Destination": "Server & Destination",
"Server Label": "Servernavn",
"Servers": "Servere",
Expand Down Expand Up @@ -358,7 +400,9 @@
"to create your SSH key.": "for at oprette din SSH-nøgle.",
"to help you generate a valid cron expression.": "til at hjælpe dig med at generere en gyldig cron-udtryk.",
"To set the SSH passphrase:": "For at indstille SSH-adgangssætningen:",
"Twice daily at 8 AM and 6 PM, Monday to Friday": "To gange dagligt klokken 8 og 18, mandag til fredag",
"Type": "Type",
"Type to search...": "Skriv for at søge...",
"Unfortunately :app was not able to connect. Find the error message below.": "Desværre kunne :app ikke oprette forbindelse. Find fejlmeddelelsen nedenfor.",
"Unknown": "Ukendt",
"Unreachable": "Utilgængelig",
Expand All @@ -370,6 +414,7 @@
"Update Tag": "Opdater mærke",
"Update your account's profile information and email address.": "Opdater din kontos profiloplysninger og e-mailadresse.",
"Update your avatar on Gravatar": "Opdater din avatar på Gravatar",
"Use": "Brug",
"Use Custom Cron": "Brug brugerdefineret cron",
"Use Path Style Endpoint": "Brug sti-baseret endpoint",
"Used": "Brugt",
Expand All @@ -387,8 +432,10 @@
"We recommend using a tool such as": "Vi anbefaler at bruge et værktøj som f.eks",
"We support Ubuntu and Debian distributions primarily.": "Vi understøtter primært Ubuntu- og Debian-distributioner.",
"Website": "Hjemmeside",
"weekday": "hverdag",
"Weekly": "Ugentligt",
"Weekly Backup Summary Emails": "Ugentlige Backup Resumé Emails",
"Weekly Backups": "Ugentlige Backups",
"When your account is removed, all the data we hold on you will be permanently erased. This includes any backup tasks, backup destinations you have configured with us, and servers you have linked.": "Når din konto er fjernet, vil alle de data, vi har om dig, blive permanent slettet. Dette inkluderer eventuelle sikkerhedskopieringsopgaver, sikkerhedskopieringsdestinationer du har konfigureret hos os, og servere du har tilknyttet.",
"Yes": "Ja",
"You are welcome to re-join at any time.": "Du er velkommen til at tilmelde dig igen når som helst.",
Expand Down
Loading

0 comments on commit 62d952a

Please sign in to comment.