You've already forked AstralRinth
forked from didirus/AstralRinth
Fixes MOD-160 (#2948)
* fix: refresh backups automatically when ongoing backups are running Signed-off-by: Evan Song <theevansong@gmail.com> * chore: improve backup creation rate limit msg Signed-off-by: Evan Song <theevansong@gmail.com> * chore: increase polling timeout Signed-off-by: Evan Song <theevansong@gmail.com> * chore: clean Signed-off-by: Evan Song <theevansong@gmail.com> * chore: add notice of automatic refresh Signed-off-by: Evan Song <theevansong@gmail.com> --------- Signed-off-by: Evan Song <theevansong@gmail.com>
This commit is contained in:
@@ -17,6 +17,9 @@
|
|||||||
<span class="font-semibold"> Backup #{{ newBackupAmount }}</span>
|
<span class="font-semibold"> Backup #{{ newBackupAmount }}</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="isRateLimited" class="mt-2 text-sm text-red">
|
||||||
|
You're creating backups too fast. Please wait a moment before trying again.
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-1 mt-4 flex justify-start gap-4">
|
<div class="mb-1 mt-4 flex justify-start gap-4">
|
||||||
<ButtonStyled color="brand">
|
<ButtonStyled color="brand">
|
||||||
@@ -36,10 +39,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, nextTick } from "vue";
|
import { ref, nextTick, computed } from "vue";
|
||||||
import { ButtonStyled, NewModal } from "@modrinth/ui";
|
import { ButtonStyled, NewModal } from "@modrinth/ui";
|
||||||
import { PlusIcon, XIcon, InfoIcon } from "@modrinth/assets";
|
import { PlusIcon, XIcon, InfoIcon } from "@modrinth/assets";
|
||||||
import type { Server } from "~/composables/pyroServers";
|
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
server: Server<["general", "mods", "backups", "network", "startup", "ws", "fs"]>;
|
server: Server<["general", "mods", "backups", "network", "startup", "ws", "fs"]>;
|
||||||
@@ -50,6 +52,7 @@ const emit = defineEmits(["backupCreated"]);
|
|||||||
const modal = ref<InstanceType<typeof NewModal>>();
|
const modal = ref<InstanceType<typeof NewModal>>();
|
||||||
const input = ref<HTMLInputElement>();
|
const input = ref<HTMLInputElement>();
|
||||||
const isCreating = ref(false);
|
const isCreating = ref(false);
|
||||||
|
const isRateLimited = ref(false);
|
||||||
const backupError = ref<string | null>(null);
|
const backupError = ref<string | null>(null);
|
||||||
const backupName = ref("");
|
const backupName = ref("");
|
||||||
const newBackupAmount = computed(() =>
|
const newBackupAmount = computed(() =>
|
||||||
@@ -75,14 +78,20 @@ const createBackup = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isCreating.value = true;
|
isCreating.value = true;
|
||||||
|
isRateLimited.value = false;
|
||||||
try {
|
try {
|
||||||
await props.server.backups?.create(backupName.value);
|
await props.server.backups?.create(backupName.value);
|
||||||
await props.server.refresh();
|
await props.server.refresh();
|
||||||
hideModal();
|
hideModal();
|
||||||
emit("backupCreated", { success: true, message: "Backup created successfully" });
|
emit("backupCreated", { success: true, message: "Backup created successfully" });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
backupError.value = error instanceof Error ? error.message : String(error);
|
if (error instanceof PyroFetchError && error.statusCode === 429) {
|
||||||
emit("backupCreated", { success: false, message: backupError.value });
|
isRateLimited.value = true;
|
||||||
|
backupError.value = "You're creating backups too fast.";
|
||||||
|
} else {
|
||||||
|
backupError.value = error instanceof Error ? error.message : String(error);
|
||||||
|
emit("backupCreated", { success: false, message: backupError.value });
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
isCreating.value = false;
|
isCreating.value = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,11 @@
|
|||||||
: ''
|
: ''
|
||||||
"
|
"
|
||||||
class="w-full sm:w-fit"
|
class="w-full sm:w-fit"
|
||||||
:disabled="isServerRunning && !userPreferences.backupWhileRunning"
|
:disabled="
|
||||||
|
(isServerRunning && !userPreferences.backupWhileRunning) ||
|
||||||
|
data.used_backup_quota >= data.backup_quota ||
|
||||||
|
backups.some((backup) => backup.ongoing)
|
||||||
|
"
|
||||||
@click="showCreateModel"
|
@click="showCreateModel"
|
||||||
>
|
>
|
||||||
<PlusIcon class="h-5 w-5" />
|
<PlusIcon class="h-5 w-5" />
|
||||||
@@ -77,6 +81,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="backups.some((backup) => backup.ongoing)"
|
||||||
|
data-pyro-server-backup-ongoing
|
||||||
|
class="flex w-full flex-row items-center gap-4 rounded-2xl bg-bg-orange p-4 text-contrast"
|
||||||
|
>
|
||||||
|
A backup is currently being created. This may take a few minutes. This page will
|
||||||
|
automatically refresh when the backup is complete.
|
||||||
|
</div>
|
||||||
|
|
||||||
<li
|
<li
|
||||||
v-for="(backup, index) in backups"
|
v-for="(backup, index) in backups"
|
||||||
:key="backup.id"
|
:key="backup.id"
|
||||||
@@ -246,6 +259,8 @@ const backupSettingsModal = ref<typeof NewModal>();
|
|||||||
const renameBackupName = ref("");
|
const renameBackupName = ref("");
|
||||||
const currentBackup = ref("");
|
const currentBackup = ref("");
|
||||||
|
|
||||||
|
const refreshInterval = ref<ReturnType<typeof setInterval>>();
|
||||||
|
|
||||||
const currentBackupDetails = computed(() => {
|
const currentBackupDetails = computed(() => {
|
||||||
return backups.value.find((backup) => backup.id === currentBackup.value);
|
return backups.value.find((backup) => backup.id === currentBackup.value);
|
||||||
});
|
});
|
||||||
@@ -319,6 +334,29 @@ const initiateDownload = async (backupId: string) => {
|
|||||||
console.error("Download failed:", error);
|
console.error("Download failed:", error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
watchEffect(() => {
|
||||||
|
const hasOngoingBackups = backups.value.some((backup) => backup.ongoing);
|
||||||
|
|
||||||
|
if (refreshInterval.value) {
|
||||||
|
clearInterval(refreshInterval.value);
|
||||||
|
refreshInterval.value = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasOngoingBackups) {
|
||||||
|
refreshInterval.value = setInterval(() => {
|
||||||
|
props.server.refresh(["backups"]);
|
||||||
|
}, 10000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
if (refreshInterval.value) {
|
||||||
|
clearInterval(refreshInterval.value);
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
Reference in New Issue
Block a user