Migrate first parts of backups view to vue

This commit is contained in:
Johannes Zellner
2025-02-04 15:10:38 +01:00
parent 55939f6320
commit 776e65bc5e
10 changed files with 631 additions and 16 deletions
+6 -3
View File
@@ -169,14 +169,17 @@ function toggleView() {
}
onMounted(async () => {
profile.value = await profileModel.get();
let [error, result] = await profileModel.get();
if (error) return console.error(error);
profile.value = result;
await refreshApps();
const [error, domains] = await domainsModel.list();
[error, result] = await domainsModel.list();
if (error) return console.error(error);
domainFilterOptions.value = domainFilterOptions.value.concat(domains.map(d => { d.id = d.domain; return d; }));
domainFilterOptions.value = domainFilterOptions.value.concat(result.map(d => { d.id = d.domain; return d; }));
domainFilter.value = domainFilterOptions.value[0].id;
stateFilter.value = stateFilterOptions[0].id;
+123
View File
@@ -0,0 +1,123 @@
<script setup>
import { ref, onMounted } from 'vue';
import { marked } from 'marked';
import { Button } from 'pankow';
import Section from '../components/Section.vue';
import BackupSchedule from '../components/BackupSchedule.vue';
import BackupList from '../components/BackupList.vue';
import BackupsModel from '../models/BackupsModel.js';
import ProfileModel from '../models/ProfileModel.js';
const profileModel = ProfileModel.create();
const backupsModel = BackupsModel.create();
function mountlike(provider) {
return provider === 'sshfs' || provider === 'cifs' || provider === 'nfs' || provider === 'mountpoint' || provider === 'ext4' || provider === 'xfs' || provider === 'disk';
}
function s3like(provider) {
return provider === 's3' || provider === 'minio' || provider === 's3-v4-compat'
|| provider === 'exoscale-sos' || provider === 'digitalocean-spaces' || provider === 'hetzner-objectstorage'
|| provider === 'scaleway-objectstorage' || provider === 'wasabi' || provider === 'backblaze-b2' || provider === 'cloudflare-r2'
|| provider === 'linode-objectstorage' || provider === 'ovh-objectstorage' || provider === 'ionos-objectstorage'
|| provider === 'vultr-objectstorage' || provider === 'upcloud-objectstorage' || provider === 'idrive-e2'
|| provider === 'contabo-objectstorage';
}
const profile = ref({});
const manualBackupApps = ref([]);
const config = ref({});
const mountOptions = ref({});
const mountStatus = ref({});
const remountBusy = ref(false);
function onConfigure() {
// TODO
}
function onRemount() {
// TODO
}
async function refresh() {
const [error, result] = await backupsModel.getConfig();
if (error) return console.error(error);
config.value = result;
mountOptions.value = result.mountOptions || {};
// $scope.backupConfig = backupConfig;
// $scope.mountStatus = null;
// if (!$scope.mountlike($scope.backupConfig.provider)) return;
// Client.getBackupMountStatus(function (error, mountStatus) {
// if (error) return console.error(error);
// $scope.mountStatus = mountStatus;
// });
}
onMounted(async () => {
const [error, result] = await profileModel.get();
if (error) return console.error(error);
profile.value = result;
await refresh();
});
</script>
<template>
<div class="content">
<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)">
<i class="fa fa-circle" :style="{ color: mountStatus.state === 'active' ? '#27CE65' : '#d9534f' }" v-show="mountStatus" v-tooltip="mountStatus.message"></i>
<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) || 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>
<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>
</Section>
<BackupSchedule :profile="profile"/>
<BackupList />
</div>
</template>
+12 -6
View File
@@ -36,6 +36,12 @@ async function onSelectLanguage(lang) {
// TODO dynamically change lange instead of reloading
}
async function refreshProfile() {
const [error, result] = await profileModel.get();
if (error) return console.error(error);
user.value = result;
}
// Profile edits
async function onChangeDisplayName(currentDisplayName) {
@@ -53,7 +59,7 @@ async function onChangeDisplayName(currentDisplayName) {
const error = await profileModel.setDisplayName(displayName);
if (error) return console.error('Failed to set displayName', error);
user.value = await profileModel.get();
await refreshProfile();
}
async function onChangeEmail(currentEmail) {
@@ -72,7 +78,7 @@ async function onChangeEmail(currentEmail) {
const error = await profileModel.setEmail(result[0], result[1]);
if (error) return console.error('Failed to set email', error);
user.value = await profileModel.get();
await refreshProfile();
}
async function onChangeFallbackEmail(currentFallbackEmail) {
@@ -91,7 +97,7 @@ async function onChangeFallbackEmail(currentFallbackEmail) {
const error = await profileModel.setFallbackEmail(result[0], result[1]);
if (error) return console.error('Failed to set fallback email', error);
user.value = await profileModel.get();
await refreshProfile();
}
const avatarFileInput = useTemplateRef('avatarFileInput');
@@ -173,7 +179,7 @@ async function onOpenTwoFASetupDialog() {
async function onTwoFAEnable() {
const [error] = await profileModel.enableTwoFA(twoFATotpToken.value);
if (error) return twoFAEnableError.value = error.body ? error.body.message : 'Internal error';
user.value = await profileModel.get();
await refreshProfile();
twoFADialog.value.close();
}
@@ -194,13 +200,13 @@ async function onTwoFADisable() {
const [error] = await profileModel.disableTwoFA(password);
if (error) return onTwoFADisable();
user.value = await profileModel.get();
await refreshProfile();
}
// Init
onMounted(async () => {
user.value = await profileModel.get();
await refreshProfile();
let [error, result] = await cloudronModel.languages();
languages.value = result.map(l => {