hosting: "Reset to onboarding" support-only action (#5659)

* Reset to onboarding button

* Lint

* Intl
This commit is contained in:
François-Xavier Talbot
2026-03-25 10:50:31 -04:00
committed by GitHub
parent d2abeb434c
commit 7b3471944d
3 changed files with 120 additions and 0 deletions

View File

@@ -1313,6 +1313,9 @@
"hosting.loader.failed-to-repair": {
"message": "Failed to repair server"
},
"hosting.loader.failed-to-reset-to-onboarding": {
"message": "Failed to reset server to onboarding"
},
"hosting.loader.failed-to-save-settings": {
"message": "Failed to save installation settings"
},
@@ -1334,6 +1337,24 @@
"hosting.loader.reset-server-description": {
"message": "Removes all data on your server, including your worlds, mods, and configuration files. Backups will remain and can be restored."
},
"hosting.loader.reset-to-onboarding-button": {
"message": "Reset to onboarding"
},
"hosting.loader.reset-to-onboarding-modal-description": {
"message": "This will send the server back into onboarding so setup can be completed again. Are you sure you want to continue?"
},
"hosting.loader.reset-to-onboarding-modal-title": {
"message": "Reset to onboarding"
},
"hosting.loader.reset-to-onboarding-success-description": {
"message": "The server has been returned to the onboarding flow."
},
"hosting.loader.reset-to-onboarding-success-title": {
"message": "Server reset to onboarding"
},
"hosting.loader.support-options-title": {
"message": "Support options"
},
"hosting.plan.out-of-stock": {
"message": "Out of stock"
},

View File

@@ -1,5 +1,13 @@
<template>
<div class="flex flex-col gap-6 rounded-2xl bg-surface-3 p-6">
<ConfirmModal
ref="resetToOnboardingModal"
:title="formatMessage(messages.resetToOnboardingModalTitle)"
:description="formatMessage(messages.resetToOnboardingModalDescription)"
:proceed-label="formatMessage(messages.resetToOnboardingButton)"
@proceed="confirmResetToOnboarding"
/>
<InstallationSettingsLayout ref="installationSettingsLayout">
<template #extra>
<div class="flex flex-col gap-2.5">
@@ -28,6 +36,24 @@
/>
</template>
</InstallationSettingsLayout>
<div v-if="isSiteAdmin" class="flex flex-col gap-2.5">
<span class="text-lg font-semibold text-contrast">
{{ formatMessage(messages.supportOptionsTitle) }}
</span>
<div>
<ButtonStyled color="red">
<button
class="!shadow-none"
:disabled="!worldId || isResettingToOnboarding"
@click="resetToOnboardingModal?.show()"
>
<RotateCounterClockwiseIcon class="size-5" />
{{ formatMessage(messages.resetToOnboardingButton) }}
</button>
</ButtonStyled>
</div>
</div>
</div>
</template>
@@ -37,6 +63,7 @@ import { RotateCounterClockwiseIcon } from '@modrinth/assets'
import {
ButtonStyled,
commonMessages,
ConfirmModal,
defineMessages,
formatLoaderLabel,
injectModrinthClient,
@@ -106,6 +133,35 @@ const messages = defineMessages({
id: 'hosting.loader.failed-to-unlink',
defaultMessage: 'Failed to unlink modpack',
},
supportOptionsTitle: {
id: 'hosting.loader.support-options-title',
defaultMessage: 'Support options',
},
resetToOnboardingButton: {
id: 'hosting.loader.reset-to-onboarding-button',
defaultMessage: 'Reset to onboarding',
},
resetToOnboardingModalTitle: {
id: 'hosting.loader.reset-to-onboarding-modal-title',
defaultMessage: 'Reset to onboarding',
},
resetToOnboardingModalDescription: {
id: 'hosting.loader.reset-to-onboarding-modal-description',
defaultMessage:
'This will send the server back into onboarding so setup can be completed again. Are you sure you want to continue?',
},
resetToOnboardingSuccessTitle: {
id: 'hosting.loader.reset-to-onboarding-success-title',
defaultMessage: 'Server reset to onboarding',
},
resetToOnboardingSuccessDescription: {
id: 'hosting.loader.reset-to-onboarding-success-description',
defaultMessage: 'The server has been returned to the onboarding flow.',
},
failedToResetToOnboarding: {
id: 'hosting.loader.failed-to-reset-to-onboarding',
defaultMessage: 'Failed to reset server to onboarding',
},
})
const emit = defineEmits<{
@@ -156,8 +212,13 @@ const modpackVersionsQuery = useQuery({
enabled: computed(() => !!modpack.value?.spec.project_id),
})
const auth = await useAuth()
const isSiteAdmin = computed(() => auth.value?.user?.role === 'admin')
const editingPlatform = ref(server.value?.loader?.toLowerCase() ?? 'vanilla')
const editingGameVersion = ref(server.value?.mc_version ?? '')
const resetToOnboardingModal = ref<InstanceType<typeof ConfirmModal>>()
const isResettingToOnboarding = ref(false)
const modLoaders = ['fabric', 'forge', 'quilt', 'neoforge']
@@ -590,4 +651,30 @@ function onBrowseModpacks() {
query: { sid: serverId, from: 'reset-server', wid: worldId.value },
})
}
async function confirmResetToOnboarding() {
if (!worldId.value) return
try {
isResettingToOnboarding.value = true
await client.archon.servers_v1.resetToOnboarding(serverId, worldId.value)
server.value.flows = { intro: true }
await Promise.all([
queryClient.invalidateQueries({ queryKey: ['servers', 'detail', serverId] }),
queryClient.invalidateQueries({ queryKey: ['servers', 'v1', 'detail', serverId] }),
])
addNotification({
type: 'success',
title: formatMessage(messages.resetToOnboardingSuccessTitle),
text: formatMessage(messages.resetToOnboardingSuccessDescription),
})
} catch (err) {
addNotification({
type: 'error',
text: err instanceof Error ? err.message : formatMessage(messages.failedToResetToOnboarding),
})
} finally {
isResettingToOnboarding.value = false
}
}
</script>

View File

@@ -54,4 +54,16 @@ export class ArchonServersV1Module extends AbstractModule {
method: 'DELETE',
})
}
/**
* Reset a world to onboarding
* POST /v1/servers/:id/worlds/:wid/onboard
*/
public async resetToOnboarding(serverId: string, worldId: string): Promise<void> {
await this.client.request(`/servers/${serverId}/worlds/${worldId}/onboard`, {
api: 'archon',
version: 1,
method: 'POST',
})
}
}