You've already forked AstralRinth
forked from didirus/AstralRinth
Modrinth Servers Mega Features & Bug Fix-a-thon (#3222)
* fix(content): changing mod versions works again * chore(assets): update pyro logo * fix(properties): deprecate fetchconfigfile * Revert "fix(content): changing mod versions works again" This reverts commit d7c0d1196f8c1850fd7ccbc1644941c6db4dc306. * feat(files): ability to sort via column click * chore(startup): update clunky wording * feat(serverListing): server icons SSR friendly * fix(servers): if archon fails, display err in listing * chore(serverlisting): use pyroserver hook to init icon * chore(servers): much more graceful reinstall * fix(servers): tw warn * fix(platform): correctly react when pack reinstalled * fix(serversroot): explicitly import navigateTo Signed-off-by: Evan Song <theevansong@gmail.com> * chore(serverlabels): show skeleton instead of hiding Signed-off-by: Evan Song <theevansong@gmail.com> * feat(platform): install-aware controls Signed-off-by: Evan Song <theevansong@gmail.com> * refactor!(platform): rewrite platform page * fix(platform): regression in autoselecting loader * chore(platform): prefer version over project modification date * fix(platform): permanent hang after initial mount * chore(platform): do not silently fail and hang if modpack fails loading * oops: remove hardcoded error causer * fix(platform): switch modpack btn while installing doesnt need class Signed-off-by: Evan Song <theevansong@gmail.com> * chore(platform): adjust styling in version modal Signed-off-by: Evan Song <theevansong@gmail.com> * chore(platform): prevent changing project card style Signed-off-by: Evan Song <theevansong@gmail.com> * refactor(pyrodropdown): rewrite Signed-off-by: Evan Song <theevansong@gmail.com> * fix(pyrodropdown): do nopt use deprecated substr Signed-off-by: Evan Song <theevansong@gmail.com> * chore: clean Signed-off-by: Evan Song <theevansong@gmail.com> * fix(network): sentence case Signed-off-by: Evan Song <theevansong@gmail.com> * refactor(terminal): initial batch Signed-off-by: Evan Song <theevansong@gmail.com> * fix(terminal): fulllog over fullscreen Signed-off-by: Evan Song <theevansong@gmail.com> * fix(terminal): fullscreen conflict with body scroll Signed-off-by: Evan Song <theevansong@gmail.com> * feat(terminal): init drag select * feat(terminal): shift click support Signed-off-by: Evan Song <theevansong@gmail.com> * chore(terminal): double lines limit Signed-off-by: Evan Song <theevansong@gmail.com> * feat(terminal): copy button Signed-off-by: Evan Song <theevansong@gmail.com> * chore(terminal): protip style Signed-off-by: Evan Song <theevansong@gmail.com> * chore(terminal): improve styles Signed-off-by: Evan Song <theevansong@gmail.com> * feat(terminal): regex search Signed-off-by: Evan Song <theevansong@gmail.com> * chore(terminal): move icons to icons dir Signed-off-by: Evan Song <theevansong@gmail.com> * chore(terminal): improve drag select autoscroll inertia Signed-off-by: Evan Song <theevansong@gmail.com> * fix(terminal): cancel selection on right click Signed-off-by: Evan Song <theevansong@gmail.com> * fix(terminal): progblur and stb btn disappearing Signed-off-by: Evan Song <theevansong@gmail.com> * refactor(serverstats): power efficiency * fix(subdomainlabel): correct tooltip terminology Signed-off-by: Evan Song <theevansong@gmail.com> * feat(preferences): users hide subdomain label Signed-off-by: Evan Song <theevansong@gmail.com> * chore(servers): clean Signed-off-by: Evan Song <theevansong@gmail.com> * chore(terminal): deselect lines on escape Signed-off-by: Evan Song <theevansong@gmail.com> * fix(serversidebar): type err Signed-off-by: Evan Song <theevansong@gmail.com> * fix(fileitem): vue server render type Signed-off-by: Evan Song <theevansong@gmail.com> * fix(terminal): disable pointer events on lines if scrolling Signed-off-by: Evan Song <theevansong@gmail.com> * fix(terminal): search result counts style Signed-off-by: Evan Song <theevansong@gmail.com> * fix(terminal): plural Signed-off-by: Evan Song <theevansong@gmail.com> * chore(terminal): clean Signed-off-by: Evan Song <theevansong@gmail.com> * feat(terminal): view selection Signed-off-by: Evan Song <theevansong@gmail.com> * feat(terminal): show actively selected lines in scrollbar Signed-off-by: Evan Song <theevansong@gmail.com> * fix(terminallog): btn color Signed-off-by: Evan Song <theevansong@gmail.com> * chore: clean Signed-off-by: Evan Song <theevansong@gmail.com> * fix(gamelabel): align to text Signed-off-by: Evan Song <theevansong@gmail.com> * fix(gamelabel): align to text Signed-off-by: Evan Song <theevansong@gmail.com> * fix(listing): remove deadcode Signed-off-by: Evan Song <theevansong@gmail.com> * fix(serverlisting): deprecated process.server Signed-off-by: Evan Song <theevansong@gmail.com> * fix(platform): correctly disable button Signed-off-by: Evan Song <theevansong@gmail.com> * fix(backups): do not allow backup creation during server installation Signed-off-by: Evan Song <theevansong@gmail.com> * fix(platform): flush stale currentversion data on successful install Signed-off-by: Evan Song <theevansong@gmail.com> * fix(gamelabel): fix gap Signed-off-by: Evan Song <theevansong@gmail.com> * chore(network): vaporize uppercase Signed-off-by: Evan Song <theevansong@gmail.com> * chore(info): vaporize uppercase Signed-off-by: Evan Song <theevansong@gmail.com> * chore(backups): style unification Signed-off-by: Evan Song <theevansong@gmail.com> * chore(backups): finalize style change Signed-off-by: Evan Song <theevansong@gmail.com> * fix(servers): catch pyro servers fetch errors during ssr Signed-off-by: Evan Song <theevansong@gmail.com> * fix(serverstats): ram as bytes graph now works Signed-off-by: Evan Song <theevansong@gmail.com> * fix(platform): unify attempts and refresh interval Signed-off-by: Evan Song <theevansong@gmail.com> * fix(terminal): input Signed-off-by: Evan Song <theevansong@gmail.com> * feat(servers): installing ticket + update available notice back in platform Signed-off-by: Evan Song <theevansong@gmail.com> * chore(terminal): dont add bg to scroll track Signed-off-by: Evan Song <theevansong@gmail.com> * fix(terminal): preserve whitespace Signed-off-by: Evan Song <theevansong@gmail.com> * chore(serversroot): unnest blurred icon query Signed-off-by: Evan Song <theevansong@gmail.com> * fix(serverstats): clamp memory usage to 100% no matter what Signed-off-by: Evan Song <theevansong@gmail.com> * feat(terminal): allow copy of single lines, show btn Signed-off-by: Evan Song <theevansong@gmail.com> * chore(terminal): animate copy>view transition Signed-off-by: Evan Song <theevansong@gmail.com> * init: search improvements Signed-off-by: Evan Song <theevansong@gmail.com> * fix: lint Signed-off-by: Evan Song <theevansong@gmail.com> * chore: change log modal title Signed-off-by: Evan Song <theevansong@gmail.com> * fix: hide fullscreen when selecting and cancel selection on clickout Signed-off-by: Evan Song <theevansong@gmail.com> * refactor(terminal): more reliable jumpToLine Signed-off-by: Evan Song <theevansong@gmail.com> * feat: search results separator Signed-off-by: Evan Song <theevansong@gmail.com> * chore: remove buggy isScrollable check Signed-off-by: Evan Song <theevansong@gmail.com> * fix: style Signed-off-by: Evan Song <theevansong@gmail.com> * refactor: correctly store pos to make jump reliable Signed-off-by: Evan Song <theevansong@gmail.com> * fix: disparity between search/log dragselect Signed-off-by: Evan Song <theevansong@gmail.com> * fix: prevent propagation of click events when clicking on jump btn Signed-off-by: Evan Song <theevansong@gmail.com> * fix: switch selection strategies depending on terminal mode Signed-off-by: Evan Song <theevansong@gmail.com> * chore: smarter esc handling Signed-off-by: Evan Song <theevansong@gmail.com> * finalize Signed-off-by: Evan Song <theevansong@gmail.com> * run fix * fix: ensure lines between cannot be selected Signed-off-by: Evan Song <theevansong@gmail.com> * fix: increase initial log batch to 256 Signed-off-by: Evan Song <theevansong@gmail.com> * fix(terminal): click on scroll track should take user to new scroll position Signed-off-by: Evan Song <theevansong@gmail.com> * fix(terminal): update aria label for view selected logs btn Signed-off-by: Evan Song <theevansong@gmail.com> * chore: clean Signed-off-by: Evan Song <theevansong@gmail.com> --------- Signed-off-by: Evan Song <theevansong@gmail.com>
This commit is contained in:
@@ -0,0 +1,551 @@
|
||||
<template>
|
||||
<NewModal
|
||||
ref="versionSelectModal"
|
||||
:header="
|
||||
isSecondPhase
|
||||
? 'Confirming reinstallation'
|
||||
: `${props.currentLoader === selectedLoader ? 'Reinstalling' : 'Installing'}
|
||||
${selectedLoader.toLowerCase() === 'vanilla' ? 'Vanilla Minecraft' : selectedLoader}`
|
||||
"
|
||||
@hide="onHide"
|
||||
@show="onShow"
|
||||
>
|
||||
<div class="flex flex-col gap-4 md:w-[600px]">
|
||||
<p
|
||||
v-if="isSecondPhase"
|
||||
:style="{
|
||||
lineHeight: isSecondPhase ? '1.5' : undefined,
|
||||
marginBottom: isSecondPhase ? '-12px' : '0',
|
||||
marginTop: isSecondPhase ? '-4px' : '-2px',
|
||||
}"
|
||||
>
|
||||
{{
|
||||
backupServer
|
||||
? "A backup will be created before proceeding with the reinstallation, then all data will be erased from your server. Are you sure you want to continue?"
|
||||
: "This will reinstall your server and erase all data. Are you sure you want to continue?"
|
||||
}}
|
||||
</p>
|
||||
<div v-if="!isSecondPhase" class="flex flex-col gap-4">
|
||||
<div class="mx-auto flex flex-row items-center gap-4">
|
||||
<div
|
||||
class="grid size-16 place-content-center rounded-2xl border-[2px] border-solid border-button-border bg-button-bg shadow-sm"
|
||||
>
|
||||
<UiServersIconsLoaderIcon class="size-10" :loader="selectedLoader" />
|
||||
</div>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="size-10"
|
||||
>
|
||||
<path d="M5 9v6" />
|
||||
<path d="M9 9h3V5l7 7-7 7v-4H9V9z" />
|
||||
</svg>
|
||||
<div
|
||||
class="grid size-16 place-content-center rounded-2xl border-[2px] border-solid border-button-border bg-table-alternateRow shadow-sm"
|
||||
>
|
||||
<ServerIcon class="size-10" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex w-full flex-col gap-2 rounded-2xl bg-table-alternateRow p-4">
|
||||
<div class="text-sm font-bold text-contrast">Minecraft version</div>
|
||||
<UiServersTeleportDropdownMenu
|
||||
v-model="selectedMCVersion"
|
||||
name="mcVersion"
|
||||
:options="mcVersions"
|
||||
class="w-full max-w-[100%]"
|
||||
placeholder="Select Minecraft version..."
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="selectedLoader.toLowerCase() !== 'vanilla'"
|
||||
class="flex w-full flex-col gap-2 rounded-2xl p-4"
|
||||
:class="{
|
||||
'bg-table-alternateRow':
|
||||
!selectedMCVersion || isLoading || selectedLoaderVersions.length > 0,
|
||||
'bg-highlight-red':
|
||||
selectedMCVersion && !isLoading && selectedLoaderVersions.length === 0,
|
||||
}"
|
||||
>
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="text-sm font-bold text-contrast">{{ selectedLoader }} version</div>
|
||||
|
||||
<template v-if="!selectedMCVersion">
|
||||
<div
|
||||
class="relative flex h-9 w-full select-none items-center rounded-xl bg-button-bg px-4 opacity-50"
|
||||
>
|
||||
Select a Minecraft version to see available versions
|
||||
<DropdownIcon class="absolute right-4" />
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="isLoading">
|
||||
<div
|
||||
class="relative flex h-9 w-full items-center rounded-xl bg-button-bg px-4 opacity-50"
|
||||
>
|
||||
<UiServersIconsLoadingIcon class="mr-2 animate-spin" />
|
||||
Loading versions...
|
||||
<DropdownIcon class="absolute right-4" />
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="selectedLoaderVersions.length > 0">
|
||||
<UiServersTeleportDropdownMenu
|
||||
v-model="selectedLoaderVersion"
|
||||
name="loaderVersion"
|
||||
:options="selectedLoaderVersions"
|
||||
class="w-full max-w-[100%]"
|
||||
:placeholder="
|
||||
selectedLoader.toLowerCase() === 'paper' ||
|
||||
selectedLoader.toLowerCase() === 'purpur'
|
||||
? `Select build number...`
|
||||
: `Select loader version...`
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div>No versions available for Minecraft {{ selectedMCVersion }}.</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex w-full flex-col gap-2 rounded-2xl bg-table-alternateRow p-4">
|
||||
<div class="flex w-full flex-row items-center justify-between">
|
||||
<label class="w-full text-lg font-bold text-contrast" for="hard-reset">
|
||||
Erase all data
|
||||
</label>
|
||||
<input
|
||||
id="hard-reset"
|
||||
v-model="hardReset"
|
||||
class="switch stylized-toggle shrink-0"
|
||||
type="checkbox"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
Removes all data on your server, including your worlds, mods, and configuration files,
|
||||
then reinstalls it with the selected version.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex w-full flex-col gap-2 rounded-2xl bg-table-alternateRow p-4">
|
||||
<div class="flex w-full flex-row items-center justify-between">
|
||||
<label class="w-full text-lg font-bold text-contrast" for="backup-server">
|
||||
Backup server
|
||||
</label>
|
||||
<input
|
||||
id="backup-server"
|
||||
v-model="backupServer"
|
||||
class="switch stylized-toggle shrink-0"
|
||||
type="checkbox"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
Creates a backup of your server before proceeding with the installation or
|
||||
reinstallation.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex justify-start gap-4">
|
||||
<ButtonStyled :color="isDangerous ? 'red' : 'brand'">
|
||||
<button :disabled="canInstall" @click="handleReinstall">
|
||||
<RightArrowIcon />
|
||||
{{
|
||||
isBackingUp
|
||||
? "Backing up..."
|
||||
: isLoading
|
||||
? "Installing..."
|
||||
: isSecondPhase
|
||||
? "Erase and install"
|
||||
: hardReset
|
||||
? "Continue"
|
||||
: "Install"
|
||||
}}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled>
|
||||
<button
|
||||
:disabled="isLoading"
|
||||
@click="
|
||||
if (isSecondPhase) {
|
||||
isSecondPhase = false;
|
||||
} else {
|
||||
hide();
|
||||
}
|
||||
"
|
||||
>
|
||||
<XIcon />
|
||||
{{ isSecondPhase ? "Go back" : "Cancel" }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</div>
|
||||
</NewModal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ButtonStyled, NewModal } from "@modrinth/ui";
|
||||
import { RightArrowIcon, XIcon, ServerIcon, DropdownIcon } from "@modrinth/assets";
|
||||
import type { Server } from "~/composables/pyroServers";
|
||||
import type { Loaders } from "~/types/servers";
|
||||
|
||||
interface LoaderVersion {
|
||||
id: string;
|
||||
stable: boolean;
|
||||
loaders: {
|
||||
id: string;
|
||||
url: string;
|
||||
stable: boolean;
|
||||
}[];
|
||||
}
|
||||
|
||||
type VersionMap = Record<string, LoaderVersion[]>;
|
||||
type VersionCache = Record<string, any>;
|
||||
|
||||
const props = defineProps<{
|
||||
server: Server<["general", "content", "backups", "network", "startup", "ws", "fs"]>;
|
||||
currentLoader: Loaders | undefined;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
reinstall: [any?];
|
||||
}>();
|
||||
|
||||
const versionSelectModal = ref();
|
||||
const isSecondPhase = ref(false);
|
||||
const hardReset = ref(false);
|
||||
const backupServer = ref(false);
|
||||
const isLoading = ref(false);
|
||||
const isBackingUp = ref(false);
|
||||
const loadingServerCheck = ref(false);
|
||||
const serverCheckError = ref("");
|
||||
|
||||
const selectedLoader = ref<Loaders>("Vanilla");
|
||||
const selectedMCVersion = ref("");
|
||||
const selectedLoaderVersion = ref("");
|
||||
|
||||
const paperVersions = ref<Record<string, number[]>>({});
|
||||
const purpurVersions = ref<Record<string, string[]>>({});
|
||||
const loaderVersions = ref<VersionMap>({});
|
||||
const cachedVersions = ref<VersionCache>({});
|
||||
|
||||
const versionStrings = ["forge", "fabric", "quilt", "neo"] as const;
|
||||
|
||||
const fetchLoaderVersions = async () => {
|
||||
const versions = await Promise.all(
|
||||
versionStrings.map(async (loader) => {
|
||||
const runFetch = async (iterations: number) => {
|
||||
if (iterations > 5) {
|
||||
throw new Error("Failed to fetch loader versions");
|
||||
}
|
||||
try {
|
||||
const res = await $fetch(`/loader-versions?loader=${loader}`);
|
||||
return { [loader]: (res as any).gameVersions };
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
} catch (_) {
|
||||
return await runFetch(iterations + 1);
|
||||
}
|
||||
};
|
||||
try {
|
||||
return await runFetch(0);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return { [loader]: [] };
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
loaderVersions.value = versions.reduce((acc, val) => ({ ...acc, ...val }), {});
|
||||
};
|
||||
|
||||
const fetchPaperVersions = async (mcVersion: string) => {
|
||||
try {
|
||||
const res = await $fetch(`https://api.papermc.io/v2/projects/paper/versions/${mcVersion}`);
|
||||
paperVersions.value[mcVersion] = (res as any).builds.sort((a: number, b: number) => b - a);
|
||||
return res;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const fetchPurpurVersions = async (mcVersion: string) => {
|
||||
try {
|
||||
const res = await $fetch(`https://api.purpurmc.org/v2/purpur/${mcVersion}`);
|
||||
purpurVersions.value[mcVersion] = (res as any).builds.all.sort(
|
||||
(a: string, b: string) => parseInt(b) - parseInt(a),
|
||||
);
|
||||
return res;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const selectedLoaderVersions = computed(() => {
|
||||
const loader = selectedLoader.value.toLowerCase();
|
||||
|
||||
if (loader === "paper") {
|
||||
return paperVersions.value[selectedMCVersion.value] || [];
|
||||
}
|
||||
|
||||
if (loader === "purpur") {
|
||||
return purpurVersions.value[selectedMCVersion.value] || [];
|
||||
}
|
||||
|
||||
if (loader === "vanilla") {
|
||||
return [];
|
||||
}
|
||||
|
||||
let apiLoader = loader;
|
||||
if (loader === "neoforge") {
|
||||
apiLoader = "neo";
|
||||
}
|
||||
|
||||
const backwardsCompatibleVersion = loaderVersions.value[apiLoader]?.find(
|
||||
// eslint-disable-next-line no-template-curly-in-string
|
||||
(x) => x.id === "${modrinth.gameVersion}",
|
||||
);
|
||||
|
||||
if (backwardsCompatibleVersion) {
|
||||
return backwardsCompatibleVersion.loaders.map((x) => x.id);
|
||||
}
|
||||
|
||||
return (
|
||||
loaderVersions.value[apiLoader]
|
||||
?.find((x) => x.id === selectedMCVersion.value)
|
||||
?.loaders.map((x) => x.id) || []
|
||||
);
|
||||
});
|
||||
|
||||
watch(selectedLoader, async () => {
|
||||
if (selectedMCVersion.value) {
|
||||
selectedLoaderVersion.value = "";
|
||||
serverCheckError.value = "";
|
||||
|
||||
await checkVersionAvailability(selectedMCVersion.value);
|
||||
}
|
||||
});
|
||||
|
||||
watch(
|
||||
selectedLoaderVersions,
|
||||
(newVersions) => {
|
||||
if (newVersions.length > 0 && !selectedLoaderVersion.value) {
|
||||
selectedLoaderVersion.value = String(newVersions[0]); // Ensure string type
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
const checkVersionAvailability = async (version: string) => {
|
||||
if (!version || version.trim().length < 3) return;
|
||||
|
||||
isLoading.value = true;
|
||||
loadingServerCheck.value = true;
|
||||
|
||||
try {
|
||||
const mcRes =
|
||||
cachedVersions.value[version] ||
|
||||
(await $fetch(`/loader-versions?loader=minecraft&version=${version}`));
|
||||
|
||||
cachedVersions.value[version] = mcRes;
|
||||
|
||||
if (!mcRes.downloads?.server) {
|
||||
serverCheckError.value = "We couldn't find a server.jar for this version.";
|
||||
return;
|
||||
}
|
||||
|
||||
const loader = selectedLoader.value.toLowerCase();
|
||||
if (loader === "paper" || loader === "purpur") {
|
||||
const fetchFn = loader === "paper" ? fetchPaperVersions : fetchPurpurVersions;
|
||||
const result = await fetchFn(version);
|
||||
if (!result) {
|
||||
serverCheckError.value = `This Minecraft version is not supported by ${loader}.`;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
serverCheckError.value = "";
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
serverCheckError.value = "Failed to fetch versions.";
|
||||
} finally {
|
||||
loadingServerCheck.value = false;
|
||||
isLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
watch(selectedMCVersion, checkVersionAvailability);
|
||||
|
||||
onMounted(() => {
|
||||
fetchLoaderVersions();
|
||||
});
|
||||
|
||||
const tags = useTags();
|
||||
const mcVersions = tags.value.gameVersions
|
||||
.filter((x) => x.version_type === "release")
|
||||
.map((x) => x.version)
|
||||
.filter((x) => {
|
||||
const segment = parseInt(x.split(".")[1], 10);
|
||||
return !isNaN(segment) && segment > 2;
|
||||
});
|
||||
|
||||
const isDangerous = computed(() => hardReset.value);
|
||||
const canInstall = computed(() => {
|
||||
const conds =
|
||||
!selectedMCVersion.value ||
|
||||
isLoading.value ||
|
||||
loadingServerCheck.value ||
|
||||
serverCheckError.value.trim().length > 0;
|
||||
|
||||
if (selectedLoader.value.toLowerCase() === "vanilla") {
|
||||
return conds;
|
||||
}
|
||||
|
||||
return conds || !selectedLoaderVersion.value;
|
||||
});
|
||||
|
||||
const performBackup = async (): Promise<boolean> => {
|
||||
try {
|
||||
const date = new Date();
|
||||
const format = date.toLocaleString(navigator.language || "en-US", {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
second: "numeric",
|
||||
timeZoneName: "short",
|
||||
});
|
||||
const backupName = `Reinstallation - ${format}`;
|
||||
isLoading.value = true;
|
||||
const backupId = await props.server.backups?.create(backupName);
|
||||
isBackingUp.value = true;
|
||||
let attempts = 0;
|
||||
while (true) {
|
||||
attempts++;
|
||||
if (attempts > 100) {
|
||||
addNotification({
|
||||
group: "server",
|
||||
title: "Backup Failed",
|
||||
text: "An unexpected error occurred while backing up. Please try again later.",
|
||||
});
|
||||
return false;
|
||||
}
|
||||
await props.server.refresh(["backups"]);
|
||||
const backups = await props.server.backups?.data;
|
||||
const backup = backupId ? backups?.find((x) => x.id === backupId) : undefined;
|
||||
if (backup && !backup.ongoing) {
|
||||
isBackingUp.value = false;
|
||||
break;
|
||||
}
|
||||
await new Promise((resolve) => setTimeout(resolve, 5000));
|
||||
}
|
||||
return true;
|
||||
} catch {
|
||||
addNotification({
|
||||
group: "server",
|
||||
title: "Backup Failed",
|
||||
text: "An unexpected error occurred while backing up. Please try again later.",
|
||||
});
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleReinstall = async () => {
|
||||
if (hardReset.value && !isSecondPhase.value) {
|
||||
isSecondPhase.value = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (backupServer.value) {
|
||||
isBackingUp.value = true;
|
||||
if (!(await performBackup())) {
|
||||
isBackingUp.value = false;
|
||||
isLoading.value = false;
|
||||
return;
|
||||
}
|
||||
isBackingUp.value = false;
|
||||
}
|
||||
|
||||
isLoading.value = true;
|
||||
|
||||
try {
|
||||
await props.server.general?.reinstall(
|
||||
props.server.serverId,
|
||||
true,
|
||||
selectedLoader.value,
|
||||
selectedMCVersion.value,
|
||||
selectedLoader.value === "Vanilla" ? "" : selectedLoaderVersion.value,
|
||||
hardReset.value,
|
||||
);
|
||||
|
||||
emit("reinstall", {
|
||||
loader: selectedLoader.value,
|
||||
lVersion: selectedLoaderVersion.value,
|
||||
mVersion: selectedMCVersion.value,
|
||||
});
|
||||
|
||||
hide();
|
||||
} catch (error) {
|
||||
if (error instanceof PyroFetchError && error.statusCode === 429) {
|
||||
addNotification({
|
||||
group: "server",
|
||||
title: "Cannot reinstall server",
|
||||
text: "You are being rate limited. Please try again later.",
|
||||
type: "error",
|
||||
});
|
||||
} else {
|
||||
addNotification({
|
||||
group: "server",
|
||||
title: "Reinstall Failed",
|
||||
text: "An unexpected error occurred while reinstalling. Please try again later.",
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const onShow = () => {
|
||||
selectedMCVersion.value = props.server.general?.mc_version || "";
|
||||
selectedLoaderVersion.value = "";
|
||||
hardReset.value = false;
|
||||
};
|
||||
|
||||
const onHide = () => {
|
||||
hardReset.value = false;
|
||||
backupServer.value = false;
|
||||
isSecondPhase.value = false;
|
||||
serverCheckError.value = "";
|
||||
loadingServerCheck.value = false;
|
||||
isLoading.value = false;
|
||||
selectedMCVersion.value = "";
|
||||
selectedLoaderVersion.value = "";
|
||||
serverCheckError.value = "";
|
||||
paperVersions.value = {};
|
||||
purpurVersions.value = {};
|
||||
};
|
||||
|
||||
const show = (loader: Loaders) => {
|
||||
selectedLoader.value = loader;
|
||||
selectedMCVersion.value = props.server.general?.mc_version || "";
|
||||
versionSelectModal.value?.show();
|
||||
};
|
||||
const hide = () => versionSelectModal.value?.hide();
|
||||
|
||||
defineExpose({ show, hide });
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.stylized-toggle:checked::after {
|
||||
background: var(--color-accent-contrast) !important;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user