You've already forked AstralRinth
forked from didirus/AstralRinth
backup page fixes and new impls for new apis (#3437)
* wip: backup page fixes and new impls for new apis * wip: more progress on backup fixes, almost done * lint * Backups cleanup * Don't show create warning if creating * Fix ongoing state * Download support * Support ready * Disable auto backup button * Use auth param for download of backups * Disable install buttons when backup is in progress, add retrying * Make prepare button have immediate feedback, don't refresh backups in all cases * Intl:extract & rebase fixes * Updated changelog and fix lint --------- Co-authored-by: Prospector <prospectordev@gmail.com>
This commit is contained in:
@@ -1,24 +1,41 @@
|
||||
<template>
|
||||
<NewModal ref="modal" header="Renaming backup" @show="focusInput">
|
||||
<div class="flex flex-col gap-2 md:w-[600px]">
|
||||
<div class="font-semibold text-contrast">Name</div>
|
||||
<label for="backup-name-input">
|
||||
<span class="text-lg font-semibold text-contrast"> Name </span>
|
||||
</label>
|
||||
<input
|
||||
id="backup-name-input"
|
||||
ref="input"
|
||||
v-model="backupName"
|
||||
type="text"
|
||||
class="bg-bg-input w-full rounded-lg p-4"
|
||||
placeholder="e.g. Before 1.21"
|
||||
:placeholder="`Backup #${backupNumber}`"
|
||||
maxlength="48"
|
||||
/>
|
||||
<div v-if="nameExists" class="flex items-center gap-1">
|
||||
<IssuesIcon class="hidden text-orange sm:block" />
|
||||
<span class="text-sm text-orange">
|
||||
You already have a backup named '<span class="font-semibold">{{ trimmedName }}</span
|
||||
>'
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-1 mt-4 flex justify-start gap-4">
|
||||
<div class="mt-2 flex justify-start gap-2">
|
||||
<ButtonStyled color="brand">
|
||||
<button :disabled="isRenaming" @click="renameBackup">
|
||||
<SaveIcon />
|
||||
Rename backup
|
||||
<button :disabled="isRenaming || nameExists" @click="renameBackup">
|
||||
<template v-if="isRenaming">
|
||||
<SpinnerIcon class="animate-spin" />
|
||||
Renaming...
|
||||
</template>
|
||||
<template v-else>
|
||||
<SaveIcon />
|
||||
Save changes
|
||||
</template>
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled>
|
||||
<button @click="hideModal">
|
||||
<button @click="hide">
|
||||
<XIcon />
|
||||
Cancel
|
||||
</button>
|
||||
@@ -28,23 +45,38 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, nextTick } from "vue";
|
||||
import { ref, nextTick, computed } from "vue";
|
||||
import { ButtonStyled, NewModal } from "@modrinth/ui";
|
||||
import { SaveIcon, XIcon } from "@modrinth/assets";
|
||||
import { SpinnerIcon, SaveIcon, XIcon, IssuesIcon } from "@modrinth/assets";
|
||||
import type { Server } from "~/composables/pyroServers";
|
||||
|
||||
const props = defineProps<{
|
||||
server: Server<["general", "mods", "backups", "network", "startup", "ws", "fs"]>;
|
||||
currentBackupId: string;
|
||||
server: Server<["general", "content", "backups", "network", "startup", "ws", "fs"]>;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits(["backupRenamed"]);
|
||||
|
||||
const modal = ref<InstanceType<typeof NewModal>>();
|
||||
const input = ref<HTMLInputElement>();
|
||||
const backupName = ref("");
|
||||
const originalName = ref("");
|
||||
const isRenaming = ref(false);
|
||||
const backupError = ref<string | null>(null);
|
||||
|
||||
const currentBackup = ref<Backup | null>(null);
|
||||
|
||||
const trimmedName = computed(() => backupName.value.trim());
|
||||
|
||||
const nameExists = computed(() => {
|
||||
if (!props.server.backups?.data || trimmedName.value === originalName.value || isRenaming.value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return props.server.backups.data.some(
|
||||
(backup) => backup.name.trim().toLowerCase() === trimmedName.value.toLowerCase(),
|
||||
);
|
||||
});
|
||||
|
||||
const backupNumber = computed(
|
||||
() => (props.server.backups?.data?.findIndex((b) => b.id === currentBackup.value?.id) ?? 0) + 1,
|
||||
);
|
||||
|
||||
const focusInput = () => {
|
||||
nextTick(() => {
|
||||
@@ -54,33 +86,55 @@ const focusInput = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const hideModal = () => {
|
||||
backupName.value = "";
|
||||
function show(backup: Backup) {
|
||||
currentBackup.value = backup;
|
||||
backupName.value = backup.name;
|
||||
originalName.value = backup.name;
|
||||
isRenaming.value = false;
|
||||
modal.value?.show();
|
||||
}
|
||||
|
||||
function hide() {
|
||||
modal.value?.hide();
|
||||
};
|
||||
}
|
||||
|
||||
const renameBackup = async () => {
|
||||
if (!backupName.value.trim() || !props.currentBackupId) {
|
||||
emit("backupRenamed", { success: false, message: "Backup name cannot be empty" });
|
||||
if (!currentBackup.value) {
|
||||
addNotification({
|
||||
type: "error",
|
||||
title: "Error renaming backup",
|
||||
text: "Current backup is null",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (trimmedName.value === originalName.value) {
|
||||
hide();
|
||||
return;
|
||||
}
|
||||
|
||||
isRenaming.value = true;
|
||||
try {
|
||||
await props.server.backups?.rename(props.currentBackupId, backupName.value);
|
||||
let newName = trimmedName.value;
|
||||
|
||||
if (newName.length === 0) {
|
||||
newName = `Backup #${backupNumber.value}`;
|
||||
}
|
||||
|
||||
await props.server.backups?.rename(currentBackup.value.id, newName);
|
||||
hide();
|
||||
await props.server.refresh();
|
||||
hideModal();
|
||||
emit("backupRenamed", { success: true, message: "Backup renamed successfully" });
|
||||
} catch (error) {
|
||||
backupError.value = error instanceof Error ? error.message : String(error);
|
||||
emit("backupRenamed", { success: false, message: backupError.value });
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
addNotification({ type: "error", title: "Error renaming backup", text: message });
|
||||
} finally {
|
||||
hide();
|
||||
isRenaming.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
show: () => modal.value?.show(),
|
||||
hide: hideModal,
|
||||
show,
|
||||
hide,
|
||||
});
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user