1
0
Files
AstralRinth/apps/frontend/src/components/ui/servers/BackupSettingsModal.vue
Evan Song a88593fec5 Modrinth Servers February Release: Bug Fix Round 1 (#3267)
* chore(pyroservers): attempt better error propogation

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore(pyroservers): introduce deferred modules

* fix(pyroservers): synchronize server icon processing

Signed-off-by: Evan Song <theevansong@gmail.com>

* refactor: server action buttons

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore: bring back skeleton

* fix(startup): populate values on refresh

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore: properly refresh network

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix: do not open backup settings modal if fetch failed

* fix(platform): only clear selected loader version if selecting a different loader

Signed-off-by: Evan Song <theevansong@gmail.com>

* feat: parse links in console log

* fix: attempt to mitigate power button state flash

Signed-off-by: Evan Song <theevansong@gmail.com>

* Revert "fix: attempt to mitigate power button state flash"

This reverts commit 3ba5c0b4f7f5bacf1576aba5efe42785696a5aed.

* refactor: error accumulation builder in PyroServersFetch

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix: sentence case

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix(files): await deferred fs

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix: startup border

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix: prevent suspended server errors from being overwritten

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix: add server id copy button to suspended server listing

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix: refresh behavior

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix: behavior of server icon in options

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore: clean

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore: clean

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix: prevent error inspector failures from destroying the page

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore: clean

Signed-off-by: Evan Song <theevansong@gmail.com>

* chore: remove nexttick wrapper

Signed-off-by: Evan Song <theevansong@gmail.com>

* fix: ensure file edit gets initted due to deferred module

Signed-off-by: Evan Song <theevansong@gmail.com>

* refactor: prevent module errors from breaking the layout

* chore: clean

Signed-off-by: Evan Song <theevansong@gmail.com>

---------

Signed-off-by: Evan Song <theevansong@gmail.com>
2025-02-18 22:17:50 +00:00

173 lines
4.8 KiB
Vue

<template>
<NewModal ref="modal" header="Editing auto backup settings">
<div class="flex flex-col gap-4 md:w-[600px]">
<div class="flex flex-col gap-2">
<div class="font-semibold text-contrast">Auto backup</div>
<p class="m-0">
Automatically create a backup of your server
<strong>{{ backupIntervalsLabel.toLowerCase() }}</strong>
</p>
</div>
<div v-if="isLoadingSettings" class="py-2 text-sm text-secondary">Loading settings...</div>
<template v-else>
<input
id="auto-backup-toggle"
v-model="autoBackupEnabled"
class="switch stylized-toggle"
type="checkbox"
:disabled="isSaving"
/>
<div class="flex flex-col gap-2">
<div class="font-semibold text-contrast">Interval</div>
<p class="m-0">
The amount of time between each backup. This will only backup your server if it has been
modified since the last backup.
</p>
</div>
<UiServersTeleportDropdownMenu
:id="'interval-field'"
v-model="backupIntervalsLabel"
:disabled="!autoBackupEnabled || isSaving"
name="interval"
:options="Object.keys(backupIntervals)"
placeholder="Backup interval"
/>
<div class="mt-4 flex justify-start gap-4">
<ButtonStyled color="brand">
<button :disabled="!hasChanges || isSaving" @click="saveSettings">
<SaveIcon class="h-5 w-5" />
{{ isSaving ? "Saving..." : "Save changes" }}
</button>
</ButtonStyled>
<ButtonStyled>
<button :disabled="isSaving" @click="modal?.hide()">
<XIcon />
Cancel
</button>
</ButtonStyled>
</div>
</template>
</div>
</NewModal>
</template>
<script setup lang="ts">
import { ButtonStyled, NewModal } from "@modrinth/ui";
import { XIcon, SaveIcon } from "@modrinth/assets";
import { ref, computed } from "vue";
import type { Server } from "~/composables/pyroServers";
const props = defineProps<{
server: Server<["backups"]>;
}>();
const modal = ref<InstanceType<typeof NewModal>>();
const initialSettings = ref<{ interval: number; enabled: boolean } | null>(null);
const autoBackupEnabled = ref(false);
const isLoadingSettings = ref(true);
const isSaving = ref(false);
const backupIntervals = {
"Every 3 hours": 3,
"Every 6 hours": 6,
"Every 12 hours": 12,
Daily: 24,
};
const backupIntervalsLabel = ref<keyof typeof backupIntervals>("Every 6 hours");
const autoBackupInterval = computed({
get: () => backupIntervals[backupIntervalsLabel.value],
set: (value) => {
const [label] =
Object.entries(backupIntervals).find(([_, interval]) => interval === value) || [];
if (label) backupIntervalsLabel.value = label as keyof typeof backupIntervals;
},
});
const hasChanges = computed(() => {
if (!initialSettings.value) return false;
return (
autoBackupEnabled.value !== initialSettings.value.enabled ||
(initialSettings.value.enabled && autoBackupInterval.value !== initialSettings.value.interval)
);
});
const fetchSettings = async () => {
isLoadingSettings.value = true;
try {
const settings = await props.server.backups?.getAutoBackup();
initialSettings.value = settings as { interval: number; enabled: boolean };
autoBackupEnabled.value = settings?.enabled ?? false;
autoBackupInterval.value = settings?.interval || 6;
return true;
} catch (error) {
console.error("Error fetching backup settings:", error);
addNotification({
group: "server",
title: "Error",
text: "Failed to load backup settings",
type: "error",
});
return false;
} finally {
isLoadingSettings.value = false;
}
};
const saveSettings = async () => {
isSaving.value = true;
try {
await props.server.backups?.updateAutoBackup(
autoBackupEnabled.value ? "enable" : "disable",
autoBackupInterval.value,
);
initialSettings.value = {
enabled: autoBackupEnabled.value,
interval: autoBackupInterval.value,
};
addNotification({
group: "server",
title: "Success",
text: "Backup settings updated successfully",
type: "success",
});
modal.value?.hide();
} catch (error) {
console.error("Error saving backup settings:", error);
addNotification({
group: "server",
title: "Error",
text: "Failed to save backup settings",
type: "error",
});
} finally {
isSaving.value = false;
}
};
defineExpose({
show: async () => {
const success = await fetchSettings();
if (success) {
modal.value?.show();
}
},
});
</script>
<style scoped>
.stylized-toggle:checked::after {
background: var(--color-accent-contrast) !important;
}
</style>