Files
cloudron-box/dashboard/src/components/BackupInfoDialog.vue
T

159 lines
5.7 KiB
Vue
Raw Normal View History

<script setup>
import { ref, useTemplateRef } from 'vue';
import { ClipboardAction, TableView, Dialog } from '@cloudron/pankow';
import { prettyDuration, prettyLongDate, prettyFileSize } from '@cloudron/pankow/utils';
import AppsModel from '../models/AppsModel.js';
import BackupsModel from '../models/BackupsModel.js';
import { useI18n } from 'vue-i18n';
const i18n = useI18n();
const t = i18n.t;
const appsModel = AppsModel.create();
const backupsModel = BackupsModel.create();
const busy = ref(true);
const backupContentTableColumns = {
label: {
label: t('backups.listing.contents'),
sort: true,
},
fileCount: {
label: t('backup.target.fileCount'),
sort(a, b, A, B) {
return A.stats?.upload?.fileCount - B.stats?.upload?.fileCount;
},
},
size: {
label: t('backup.target.size'),
sort(a, b, A , B) {
return A.stats?.upload?.size - B.stats?.upload?.size;
},
}
};
const backup = ref({ contents: [], validStats: false });
const dialog = useTemplateRef('dialog');
defineExpose({
async open(b) {
backup.value = JSON.parse(JSON.stringify(b)); // make a copy
backup.value.contents = [];
backup.value.validStats = false; // old cloudron version had invalid stats
busy.value = true;
dialog.value.open();
if (backup.value.type === 'app') {
backup.value.validStats = backup.value.stats?.upload && backup.value.stats?.copy;
busy.value = false;
return;
}
// amend detailed app info
const appsById = {};
const [appsError, apps] = await appsModel.list();
if (appsError) console.error('Failed to get apps list:', appsError);
(apps || []).forEach(function (app) {
appsById[app.id] = app;
});
for (const contentId of backup.value.dependsOn) {
const match = contentId.match(/(mail|app)_(.*?)_.*/); // *? means non-greedy
if (!match) continue;
const [error, result] = await backupsModel.get(contentId);
if (error) console.error(error);
const content = { id: null, label: null, fqdn: null, stats: null };
content.stats = result.stats;
if (match[1] === 'mail') {
content.id = 'mail';
content.label = 'Mail Server';
} else {
const app = appsById[match[2]];
if (app) {
content.id = app.id;
content.label = app.label;
content.fqdn = app.fqdn;
} else { // uninstalled app
content.id = match[2];
}
}
backup.value.contents.push(content);
}
backup.value.validStats = backup.value.stats?.aggregatedUpload && backup.value.stats?.aggregatedCopy;
busy.value = false;
}
});
</script>
<template>
<Dialog ref="dialog"
:title="$t('backups.backupDetails.title')"
:reject-label="$t('main.dialog.close')"
>
<div class="info-row">
<div class="info-label">{{ $t('backups.backupDetails.id') }}</div>
<div class="info-value">{{ backup.id }}</div>
</div>
<div class="info-row">
<div class="info-label">{{ $t('backups.backupEdit.label') }}</div>
<div class="info-value">{{ backup.label }}</div>
</div>
<div class="info-row">
<div class="info-label">{{ $t('backups.backupEdit.remotePath') }}</div>
<div class="info-value">
<div>
{{ backup.remotePath }}
<ClipboardAction plain :value="backup.remotePath"/>
</div>
</div>
</div>
<div class="info-row">
<div class="info-label">{{ $t('backups.backupDetails.date') }}</div>
<div class="info-value">{{ prettyLongDate(backup.creationTime) }}</div>
</div>
<div class="info-row">
<div class="info-label">{{ $t('backups.backupDetails.version') }}</div>
<div class="info-value">{{ backup.packageVersion }}</div>
</div>
<div class="info-row" v-if="backup.validStats">
<div class="info-label">{{ $t('backups.backupDetails.size') }}</div>
<div v-if="backup.type === 'box'" class="info-value">{{ prettyFileSize(backup.stats.aggregatedUpload.size) }} | {{ backup.stats.aggregatedUpload.fileCount }} file(s)</div>
<div v-else class="info-value">{{ prettyFileSize(backup.stats.upload.size) }} | {{ backup.stats.upload.fileCount }} file(s)</div>
</div>
<div class="info-row" v-if="backup.validStats">
<div class="info-label">{{ $t('backups.backupDetails.duration') }}</div>
<div v-if="backup.type === 'box'" class="info-value">{{ prettyDuration(backup.stats.aggregatedUpload.duration + backup.stats.aggregatedCopy.duration) }}</div>
<div v-else class="info-value">{{ prettyDuration(backup.stats.upload.duration + backup.stats.copy.duration) }}</div>
</div>
<div v-if="backup.type === 'box'">
<br/>
<div>{{ $t('backups.backupDetails.list', { appCount: backup.appCount }) }}:</div>
<br/>
<TableView :columns="backupContentTableColumns" :model="backup.contents" :busy="busy">
<template #label="content">
<a v-if="content.id === 'mail'" href="/#/mailboxes">{{ content.label }}</a>
<a v-else-if="content.fqdn" :href="`/#/app/${content.id}/backups`">{{ content.label || content.fqdn }}</a>
<a v-else :href="`/#/system-eventlog?search=${content.id}`">{{ content.id }}</a>
</template>
<template #fileCount="content">
<div v-if="content.stats?.upload" style="text-align: right">{{ content.stats.upload.fileCount }}</div>
<div v-else style="text-align: right">-</div>
</template>
<!-- <td>{{ prettyDuration(content.stats.upload.duration | content.stats.copy.duration) }}</td> -->
<template #size="content">
<div v-if="content.stats?.upload" style="text-align: right">{{ prettyFileSize(content.stats.upload.size) }}</div>
<div v-else style="text-align: right">-</div>
</template>
</TableView>
</div>
</Dialog>
</template>