diff --git a/dashboard/src/components/BackupList.vue b/dashboard/src/components/BackupList.vue index 3f9569a24..5120c7e0c 100644 --- a/dashboard/src/components/BackupList.vue +++ b/dashboard/src/components/BackupList.vue @@ -4,21 +4,28 @@ import { useI18n } from 'vue-i18n'; const i18n = useI18n(); const t = i18n.t; -import { ref, onMounted, useTemplateRef, computed } from 'vue'; -import { Button, InputDialog, Dialog, FormGroup, TableView } from 'pankow'; +import { ref, onMounted, useTemplateRef } from 'vue'; +import { Button, ProgressBar, TableView, Dialog } from 'pankow'; import { prettyLongDate } from 'pankow/utils'; -import { TASK_TYPES } from '../constants.js'; +import { TASK_TYPES, SECRET_PLACEHOLDER } from '../constants.js'; import Section from '../components/Section.vue'; import BackupsModel from '../models/BackupsModel.js'; import AppsModel from '../models/AppsModel.js'; import TasksModel from '../models/TasksModel.js'; +import DashboardModel from '../models/DashboardModel.js'; +import { download } from '../utils.js'; + +const props = defineProps({ + config: Object +}); const backupsModel = BackupsModel.create(); const appsModel = AppsModel.create(); const tasksModel = TasksModel.create(); +const dashboardModel = DashboardModel.create(); const columns = { - archived: {}, + preserveSecs: {}, // archived packageVersion: { label: t('backups.listing.version'), sort: true }, creationTime: { label: t('main.table.date'), sort: true }, content: { label: t('backups.listing.contents'), sort: false }, @@ -28,15 +35,15 @@ const columns = { const busy = ref(true); const backups = ref([]); const taskLogsMenu = ref([]); -const backupTask = ref({}); +const lastTask = ref({}); async function waitForTask() { - if (!backupTask.value.id) return; + if (!lastTask.value.id) return; - const [error, result] = await tasksModel.get(backupTask.value.id); + const [error, result] = await tasksModel.get(lastTask.value.id); if (error) return console.error(error); - backupTask.value = result; + lastTask.value = result; // task done, refresh menu if (!result.active) return await refreshTasks(); @@ -48,7 +55,7 @@ async function refreshTasks() { const [error, result] = await tasksModel.getByType(TASK_TYPES.TASK_BACKUP); if (error) return console.error(error); - backupTask.value = result[0] || {}; + lastTask.value = result[0] || {}; // limit to last 10 taskLogsMenu.value = result.slice(0,10).map(t => { @@ -60,7 +67,7 @@ async function refreshTasks() { }); // if last task is currently active, start polling - if (backupTask.value.active) waitForTask(); + if (lastTask.value.active) waitForTask(); } async function refreshBackups() { @@ -103,6 +110,58 @@ async function refreshBackups() { backups.value = result; } + +async function onStartBackup() { + const [error] = await backupsModel.create(); + if (error) { + if (error.status === 409 && error.message.indexOf('full_backup') !== -1) { + // TODO + // $scope.createBackup.errorMessage = 'Backup already in progress. Please retry later.'; + } else if (error.statusCode === 409) { + // TODO + // $scope.createBackup.errorMessage = 'App task is currently in progress. Please retry later.'; + } + + return console.error(error); + } + + await refreshTasks(); +} + +async function onStopBackup() { + const [error] = await tasksModel.stop(lastTask.value.id); + if (error) return console.error(error); +} + +async function onDownloadConfig(backup) { + const [error, result] = await dashboardModel.getConfig(); + if (error) return console.error(error); + + // secrets and tokens already come with placeholder characters we remove them + const tmp = { + remotePath: backup.remotePath, + encrypted: !!props.config.password // we add this just to help the import UI + }; + + Object.keys(props.config).forEach((k) => { + if (props.config[k] !== SECRET_PLACEHOLDER) tmp[k] = props.config[k]; + }); + + const filename = `${result.adminFqdn}-backup-config-${(new Date(backup.creationTime)).toISOString().split('T')[0]}.json`; + download(filename, JSON.stringify(tmp, null, 4)); +} + +function onEdit(backup) { + console.log('edit', backup); +} + +const infoDialog = useTemplateRef('infoDialog'); +const infoBackup = ref({ contents: [] }); +function onInfo(backup) { + infoBackup.value = backup; + infoDialog.value.open(); +} + onMounted(async () => { await refreshBackups(); await refreshTasks(); @@ -112,13 +171,51 @@ onMounted(async () => {