Files
cloudron-box/dashboard/src/components/BackupScheduleDialog.vue
2025-10-07 14:53:44 +02:00

132 lines
4.6 KiB
Vue

<script setup>
import { ref, useTemplateRef, computed } from 'vue';
import { Checkbox, Dialog, FormGroup, SingleSelect, MultiSelect } from '@cloudron/pankow';
import BackupSitesModel from '../models/BackupSitesModel.js';
import { cronDays, cronHours } from '../utils.js';
const emit = defineEmits([ 'success' ]);
const backupSitesModel = BackupSitesModel.create();
const id = ref('');
const busy = ref(false);
const formError = ref('');
const dialog = useTemplateRef('dialog');
const scheduleEnabled = ref(false);
const days = ref([]);
const hours = ref([]);
const configureRetention = ref(''); // this is 'name' and not 'id' of backupRetentions because SingleSelect needs strings
const isConfigureValid = computed(() => {
return !!days.value.length && !!hours.value.length;
});
async function onSubmit() {
if (!isConfigureValid.value) return;
busy.value = true;
let schedule;
if (scheduleEnabled.value) {
let daysPattern;
if (days.value.length === 7) daysPattern = '*';
else daysPattern = days.value;
let hoursPattern;
if (hours.value.length === 24) hoursPattern = '*';
else hoursPattern = hours.value;
schedule = `00 00 ${hoursPattern} * * ${daysPattern}`;
} else {
schedule = 'never';
}
let [error] = await backupSitesModel.setSchedule(id.value, schedule);
if (error) {
busy.value = false;
formError.value = error.body ? error.body.message : 'Internal error';
return console.error(error);
}
const selectedRetention = BackupSitesModel.backupRetentions.find(function (x) { return x.name === configureRetention.value; });
[error] = await backupSitesModel.setRetention(id.value, selectedRetention.id);
if (error) {
busy.value = false;
formError.value = error.body ? error.body.message : 'Internal error';
return console.error(error);
}
emit('success');
dialog.value.close();
busy.value = false;
}
defineExpose({
async open(site) {
id.value = site.id;
busy.value = false;
formError.value = false;
const currentRetentionString = JSON.stringify(site.retention);
const selectedRetention = BackupSitesModel.backupRetentions.find(function (x) { return JSON.stringify(x.id) === currentRetentionString; });
configureRetention.value = selectedRetention ? selectedRetention.name : BackupSitesModel.backupRetentions[0].name;
if (site.schedule === 'never') {
scheduleEnabled.value = false;
} else {
scheduleEnabled.value = true;
const tmp = site.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); });
}
dialog.value.open();
}
});
</script>
<template>
<Dialog ref="dialog"
:title="$t('backups.configureBackupSchedule.title')"
reject-style="secondary"
:reject-label="$t('main.dialog.cancel')"
:reject-active="!busy"
:confirm-label="$t('main.dialog.save')"
:confirm-busy="busy"
:confirm-active="isConfigureValid"
@confirm="onSubmit()"
>
<div class="error-label" v-show="formError">{{ formError }}</div>
<form @submit.prevent="onSubmit()" autocomplete="off">
<fieldset>
<FormGroup>
<label for="daysInput">{{ $t('backups.configureBackupSchedule.schedule') }}</label>
<div v-html="$t('backups.configureBackupSchedule.scheduleDescription')" style="margin-bottom: 10px; "></div>
<Checkbox :label="$t('main.statusEnabled')" v-model="scheduleEnabled" />
<div v-if="scheduleEnabled" style="display: flex; gap: 10px; margin-left: 10px">
<div>{{ $t('backups.configureBackupSchedule.days') }}: <MultiSelect id="daysInput" :disabled="!scheduleEnabled" v-model="days" :options="cronDays" option-key="id" option-label="name"></MultiSelect></div>
<div>{{ $t('backups.configureBackupSchedule.hours') }}: <MultiSelect :disabled="!scheduleEnabled" v-model="hours" :options="cronHours" option-key="id" option-label="name"></MultiSelect></div>
</div>
</FormGroup>
<FormGroup>
<label for="retentionInput">{{ $t('backups.configureBackupSchedule.retentionPolicy') }}</label>
<!-- we do not used id as key because SingleSelect can only handle strings -->
<SingleSelect id="retentionInput" v-model="configureRetention" :options="BackupSitesModel.backupRetentions" option-key="name" option-label="name" />
</FormGroup>
</fieldset>
</form>
</Dialog>
</template>