diff --git a/dashboard/src/components/BackupSiteScheduleDialog.vue b/dashboard/src/components/BackupSiteScheduleDialog.vue index 928bff0e1..68655c1dd 100644 --- a/dashboard/src/components/BackupSiteScheduleDialog.vue +++ b/dashboard/src/components/BackupSiteScheduleDialog.vue @@ -3,7 +3,7 @@ import { ref, useTemplateRef, computed } from 'vue'; import { Radiobutton, Dialog, FormGroup, SingleSelect, MultiSelect } from '@cloudron/pankow'; import BackupSitesModel from '../models/BackupSitesModel.js'; -import { cronDays, cronHours } from '../utils.js'; +import { cronDays, cronHours, parseSchedule } from '../utils.js'; const emit = defineEmits([ 'success' ]); @@ -76,16 +76,9 @@ defineExpose({ scheduleType.value = 'never'; } else { scheduleType.value = 'pattern'; - - const tmp = site.value.schedule.split(' '); - const tmpHours = tmp[2].split(','); - const tmpDays = tmp[5].split(','); - - if (tmpDays[0] === '*') days.value = cronDays.map((day) => { return day.id; }); - else days.value = tmpDays.map((day) => { return parseInt(day, 10); }); - - if (tmpHours[0] === '*') hours.value = cronHours.map(h => h.id); - else hours.value = tmpHours.map((hour) => { return parseInt(hour, 10); }); + const result = parseSchedule(site.value.schedule); + days.value = result.days; // Array of cronDays.id + hours.value = result.hours; // Array of cronHours.id } dialog.value.open(); diff --git a/dashboard/src/components/SystemUpdate.vue b/dashboard/src/components/SystemUpdate.vue index fa6e47e5a..37009c519 100644 --- a/dashboard/src/components/SystemUpdate.vue +++ b/dashboard/src/components/SystemUpdate.vue @@ -15,32 +15,13 @@ import AppsModel from '../models/AppsModel.js'; import UpdaterModel from '../models/UpdaterModel.js'; import TasksModel from '../models/TasksModel.js'; import DashboardModel from '../models/DashboardModel.js'; -import { cronDays, cronHours } from '../utils.js'; +import { cronDays, cronHours, prettySchedule, parseSchedule } from '../utils.js'; const appsModel = AppsModel.create(); const tasksModel = TasksModel.create(); const updaterModel = UpdaterModel.create(); const dashboardModel = DashboardModel.create(); -function prettyAutoUpdateSchedule(pattern) { - if (!pattern) return ''; - const tmp = pattern.split(' '); - - if (tmp.length === 1) return tmp[0]; - - const hours = tmp[2].split(','); - const days = tmp[5].split(','); - const prettyDay = (days.length === 7 || days[0] === '*') ? 'Every day' : days.map((day) => { return cronDays[parseInt(day, 10)].name.substr(0, 3); }).join(', '); - - try { - const prettyHour = hours.map((hour) => { return cronHours[parseInt(hour, 10)]; }).sort((a,b) => a.value - b.value).map(h => h.name).join(', '); - return prettyDay + ' at ' + prettyHour; - } catch (error) { - console.error('Unable to build pattern.', error); - return 'Custom pattern'; - } -} - const inputDialog = useTemplateRef('inputDialog'); const updateDialog = useTemplateRef('updateDialog'); @@ -106,19 +87,13 @@ async function refreshPendingUpdateInfo() { } function onShowConfigure() { - configureType.value = configurePattern.value === 'never' ? 'never' : 'pattern'; - - const tmp = currentPattern.value.split(' '); - const hours = tmp[2] ? tmp[2].split(',') : []; - const days = tmp[5] ? tmp[5].split(',') : []; - - if (days[0] === '*') configureDays.value = cronDays.map(day => { return day.id; }); - else configureDays.value = days.map(day => { return parseInt(day, 10); }); - - try { - configureHours.value = hours.map(hour => { return parseInt(hour, 10); }); - } catch (error) { - console.error('Error parsing hour', error); + if (currentPattern.value === 'never') { + configureType.value = 'never'; + } else { + configureType.value = 'pattern'; + const result = parseSchedule(currentPattern.value); + configureDays.value = result.days; // Array of cronDays.id + configureHours.value = result.hours; // Array of cronHours.id } configureDialog.value.open(); @@ -347,7 +322,7 @@ onMounted(async () => {
- {{ prettyAutoUpdateSchedule(currentPattern) || '-' }} + {{ prettySchedule(currentPattern) }} {{ $t('settings.updates.disabled') }}
diff --git a/dashboard/src/utils.js b/dashboard/src/utils.js index 59f3e49a0..45ddb1048 100644 --- a/dashboard/src/utils.js +++ b/dashboard/src/utils.js @@ -671,6 +671,50 @@ const cronDays = [ // generates 24h time sets (instead of american 12h) to avoid having to translate everything to locales eg. 12:00 const cronHours = Array.from({ length: 24 }).map(function (v, i) { return { id: i, name: (i < 10 ? '0' : '') + i + ':00' }; }); +function prettySchedule(pattern) { + if (!pattern) return ''; + + const tmp = pattern.trim().split(/\s+/); // remove extra spaces between tokens, which is valid cron + if (tmp.length === 1) return pattern.charAt(0).toUpperCase() + pattern.slice(1); // case for 'never' - capitalize + + if (tmp.length === 5) tmp.unshift('0'); // if seconds is missing, add it + + if (tmp.length !== 6) return `Unrecognized pattern - ${pattern}`; + + const hours = tmp[2].split(',').sort((a, b) => Number(a) - Number(b)); + const days = tmp[5].split(',').sort((a, b) => Number(a) - Number(b)); + + try { + const prettyDay = (days.length === 7 || days[0] === '*') ? 'Every day' : days.map((day) => { return cronDays[parseInt(day, 10)].name.substr(0, 3); }).join(', '); + const prettyHour = (hours.length === 24 || hours[0] === '*') ? 'hourly' : hours.map((hour) => { return cronHours[parseInt(hour, 10)]; }).sort((a,b) => a.id - b.id).map(h => h.name).join(', '); + return `${prettyDay} @ ${prettyHour}`; + } catch (error) { + console.error('Unable to build pattern.', error); + return `Unrecognized pattern - ${pattern}`; + } +}; + +function parseSchedule(pattern) { + const tmp = pattern.trim().split(/\s+/); // remove extra spaces between tokens, which is valid cron + if (tmp.length === 1) return console.error(`Never pattern should not be passed here - ${pattern}`); + + if (tmp.length === 5) tmp.unshift('0'); // if seconds is missing, add it + + if (tmp.length !== 6) return console.error(`Unrecognized pattern - ${pattern}`); + + const tmpHours = tmp[2].split(','); + const tmpDays = tmp[5].split(','); + + let days, hours; + if (tmpDays[0] === '*') days = cronDays.map((day) => { return day.id; }); + else days = tmpDays.map((day) => { return parseInt(day, 10); }); + + if (tmpHours[0] === '*') hours = cronHours.map(h => h.id); + else hours = tmpHours.map((hour) => { return parseInt(hour, 10); }); + + return { days, hours }; +} + function getColor(numOfSteps, step) { const deg = 360/numOfSteps; return `hsl(${deg*step} 70% 50%)`; @@ -693,6 +737,8 @@ export { cronDays, cronHours, getColor, + prettySchedule, + parseSchedule }; // default export @@ -712,4 +758,6 @@ export default { cronDays, cronHours, getColor, + prettySchedule, + parseSchedule }; diff --git a/dashboard/src/views/BackupSitesView.vue b/dashboard/src/views/BackupSitesView.vue index 2b5bddde2..9376b38e6 100644 --- a/dashboard/src/views/BackupSitesView.vue +++ b/dashboard/src/views/BackupSitesView.vue @@ -17,7 +17,7 @@ import SystemBackupList from '../components/SystemBackupList.vue'; import { TASK_TYPES } from '../constants.js'; import BackupSitesModel from '../models/BackupSitesModel.js'; import TasksModel from '../models/TasksModel.js'; -import { cronDays, cronHours, regionName } from '../utils.js'; +import { prettySchedule, regionName } from '../utils.js'; const profile = inject('profile'); @@ -50,30 +50,6 @@ function onEditConfig(site) { backupSiteConfigDialog.value.open(site); } -function prettyBackupSchedule(pattern) { - if (!pattern) return ''; - - const tmp = pattern.split(' '); - if (tmp.length === 1) return pattern.charAt(0).toUpperCase() + pattern.slice(1); // case for 'never' - capitalize - - const hours = tmp[2].split(',').sort((a, b) => Number(a) - Number(b)); - const days = tmp[5].split(',').sort((a, b) => Number(a) - Number(b)); - let prettyDay; - if (days.length === 7 || days[0] === '*') { - prettyDay = 'Everyday'; - } else { - prettyDay = days.map(function (day) { return cronDays[parseInt(day, 10)].name.substr(0, 3); }).join(','); - } - - let prettyHour; - if (hours.length === 24 || hours[0] === '*') { - prettyHour = 'hourly'; - } else { - prettyHour = hours.map(function (hour) { return cronHours[parseInt(hour, 10)].name; }).join(','); - } - return prettyDay + ' @ ' + prettyHour; -}; - function prettyBackupRetention(retention) { function stableStringify(obj) { return JSON.stringify(obj, Object.keys(obj).sort()); } const tmp = BackupSitesModel.backupRetentions.find(function (p) { return stableStringify(p.id) === stableStringify(retention); }); @@ -326,7 +302,7 @@ onMounted(async () => {
- {{ $t('backups.schedule.schedule') }}: {{ prettyBackupSchedule(site.schedule) }} + {{ $t('backups.schedule.schedule') }}: {{ prettySchedule(site.schedule) }}
{{ $t('backups.schedule.retentionPolicy') }}: {{ prettyBackupRetention(site.retention) }}