Create separate views for backup targets and archives

This commit is contained in:
Johannes Zellner
2025-07-31 11:51:45 +02:00
parent ae3a34287a
commit b40248a1d5
3 changed files with 168 additions and 17 deletions
+135
View File
@@ -0,0 +1,135 @@
<script setup>
import { ref, onMounted, useTemplateRef } from 'vue';
import { marked } from 'marked';
import { Button } from '@cloudron/pankow';
import Section from '../components/Section.vue';
import StateLED from '../components/StateLED.vue';
import BackupDialog from '../components/BackupDialog.vue';
import BackupSchedule from '../components/BackupSchedule.vue';
import BackupList from '../components/BackupList.vue';
import BackupsModel from '../models/BackupsModel.js';
import BackupTargetsModel from '../models/BackupTargetsModel.js';
import ProfileModel from '../models/ProfileModel.js';
import { mountlike, s3like } from '../utils.js';
const profileModel = ProfileModel.create();
const backupsModel = BackupsModel.create();
const backupTargetsModel = BackupTargetsModel.create();
const profile = ref({});
const manualBackupApps = ref([]);
const config = ref({});
const mountOptions = ref({});
const mountStatus = ref({});
const targets = ref([]);
const backupDialog = useTemplateRef('backupDialog');
function onConfigure() {
backupDialog.value.open();
}
const remountBusy = ref(false);
async function onRemount() {
if (!mountlike(config.value.provider)) return;
remountBusy.value = true;
const [error] = await backupsModel.remount();
if (error) {
console.error('Failed to remount backup storage.', error);
window.pankow.notify({ text: `Remount failed: ${error.message}`, persistent: true, type: 'danger' });
}
// give the backend some time
setTimeout(() => {
remountBusy.value = false;
refresh();
}, 2000);
}
async function refresh() {
const [error, result] = await backupTargetsModel.list();
if (error) return console.error(error);
targets.value = result;
// mountOptions.value = result.mountOptions || {};
// mountStatus.value = {};
// if (!mountlike(config.value.provider)) return;
// [error, result] = await backupsModel.mountStatus();
// if (error) return console.error(error);
// mountStatus.value = result;
console.log(targets.value)
}
onMounted(async () => {
const [error, result] = await profileModel.get();
if (error) return console.error(error);
profile.value = result;
await refresh();
});
</script>
<template>
<div class="content">
<BackupDialog ref="backupDialog" @success="refresh()"/>
<Section :title="$t('backups.title')">
<p>{{ $t('backups.location.description') }}
<span v-show="manualBackupApps.length">
{{ $t('backups.location.disabledList') }}
<span v-for="app in manualBackupApps" :key="app.id">
<a :href="`/#/app/${app.id}/backups`">{{ app.label || app.fqdn }}</a>,
</span>
</span>
</p>
<p v-show="config.provider === 'noop'" class="text-danger" v-html="marked.parse($t('backups.check.noop'))"></p>
<p v-show="config.provider === 'filesystem'" class="text-danger" v-html="marked.parse($t('backups.check.sameDisk'))"></p>
<div class="info-row">
<div class="info-label">{{ $t('backups.location.provider') }}</div>
<div class="info-value">{{ config.provider }}</div>
</div>
<div class="info-row" v-show="config.provider !== 'noop'">
<div class="info-label">{{ $t('backups.location.location') }}</div>
<div class="info-value">
<span v-show="config.provider === 'filesystem'">{{ config.backupFolder }}</span>
<span v-show="mountlike(config.provider)">
<StateLED v-if="mountStatus" :state="mountStatus.state === 'active' ? 'success' : 'danger'" v-tooltip="mountStatus.message" style="margin-right: 6px"/>
<span v-show="config.provider === 'disk' || config.provider === 'filesystem' || config.provider === 'ext4' || config.provider === 'xfs' || config.provider === 'mountpoint'">{{ mountOptions.diskPath || config.mountPoint }}{{ (config.prefix ? '/' : '') + config.prefix }}</span>
<span v-show="config.provider === 'cifs' || config.provider === 'nfs' || config.provider === 'sshfs'">{{ mountOptions.host }}:{{ mountOptions.remoteDir }}{{ (config.prefix ? '/' : '') + config.prefix }}</span>
</span>
<span v-show="config.provider !== 's3' && config.provider !== 'minio' && (s3like(config.provider) || config.provider === 'gcs')">{{ config.bucket + (config.prefix ? '/' : '') + config.prefix }}</span>
<span v-show="config.provider === 's3'">{{ config.region + ' ' + config.bucket + (config.prefix ? '/' : '') + config.prefix }}</span>
<span v-show="config.provider === 'minio'">{{ config.endpoint + ' ' + config.bucket + (config.prefix ? '/' : '') + config.prefix }}</span>
</div>
</div>
<div class="info-row" v-show="config.endpoint && config.provider !== 'minio'">
<div class="info-label">{{ $t('backups.location.endpoint') }}</div>
<div class="info-value">{{ config.endpoint || config.region }}</div>
</div>
<div class="info-row">
<div class="info-label">{{ $t('backups.location.format') }}</div>
<div class="info-value">{{ config.format }} <i class="fas fa-lock" v-show="config.password" ></i></div>
</div>
<div class="button-bar">
<Button v-show="profile.isAtLeastOwner" @click="onConfigure()">{{ $t('backups.location.configure') }}</Button>
<Button v-show="profile.isAtLeastOwner && mountlike(config.provider)" :disabled="remountBusy" :loading="remountBusy" @click="onRemount()">{{ $t('backups.location.remount') }}</Button>
</div>
</Section>
<BackupSchedule :profile="profile"/>
<BackupList :config="config"/>
</div>
</template>