mirror of https://github.com/wg-easy/wg-easy
Browse Source
- redirect to login when the setup is done - allow user to return to previous steps - prompt error message - i18n frenchpull/1397/head
committed by
Bernd Storath
8 changed files with 151 additions and 311 deletions
@ -0,0 +1,15 @@ |
|||
<template> |
|||
<svg |
|||
xmlns="http://www.w3.org/2000/svg" |
|||
fill="none" |
|||
viewBox="0 0 24 24" |
|||
stroke-width="1.5" |
|||
stroke="currentColor" |
|||
> |
|||
<path |
|||
stroke-linecap="round" |
|||
stroke-linejoin="round" |
|||
d="M9 12.75 11.25 15 15 9.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" |
|||
/> |
|||
</svg> |
|||
</template> |
@ -1,277 +0,0 @@ |
|||
<template> |
|||
<main class="container mx-auto px-4"> |
|||
<UiBanner /> |
|||
<Panel> |
|||
<PanelBody class="md:w-[70%] lg:w-[60%] mx-auto mt-10 p-4"> |
|||
<h2 class="mt-8 mb-16 text-3xl font-medium"> |
|||
{{ $t('setup.welcome') }} |
|||
</h2> |
|||
|
|||
<div v-if="step === 1"> |
|||
<p class="text-lg p-8 text-center"> |
|||
{{ $t('setup.messageSetupLanguage') }} |
|||
</p> |
|||
<div class="flex justify-center mb-8"> |
|||
<UiChooseLang :lang="lang" @update:lang="handleEventUpdateLang" /> |
|||
</div> |
|||
</div> |
|||
|
|||
<div v-if="step === 2"> |
|||
<p class="text-lg p-8 text-center"> |
|||
{{ $t('setup.messageSetupCreateAdminUser') }} |
|||
</p> |
|||
<div> |
|||
<Label for="username" class="inline-block py-2">{{ |
|||
$t('username') |
|||
}}</Label> |
|||
<input |
|||
id="username" |
|||
v-model="username" |
|||
form="form-create-admin-user" |
|||
type="text" |
|||
name="username" |
|||
autocomplete="username" |
|||
autofocus |
|||
:placeholder="$t('setup.usernamePlaceholder')" |
|||
:class="inputClass" |
|||
/> |
|||
</div> |
|||
<div> |
|||
<Label for="password" class="inline-block py-2">{{ |
|||
$t('setup.newPassword') |
|||
}}</Label> |
|||
<input |
|||
id="password" |
|||
v-model="password" |
|||
form="form-create-admin-user" |
|||
type="password" |
|||
name="password" |
|||
autocomplete="new-password" |
|||
:placeholder="$t('setup.passwordPlaceholder')" |
|||
:class="inputClass" |
|||
/> |
|||
</div> |
|||
<div> |
|||
<Label for="accept" class="inline-block my-4 mr-4">{{ |
|||
$t('setup.accept') |
|||
}}</Label> |
|||
<input id="accept" v-model="accept" type="checkbox" name="accept" /> |
|||
</div> |
|||
<form id="form-create-admin-user"></form> |
|||
</div> |
|||
|
|||
<div v-if="step === 3"> |
|||
<p class="text-lg p-8 text-center"> |
|||
{{ $t('setup.messageSetupHostPort') }} |
|||
</p> |
|||
<div> |
|||
<Label for="host">{{ $t('setup.host') }}</Label> |
|||
<input |
|||
id="host" |
|||
v-model="host" |
|||
form="form-set-host-port" |
|||
type="text" |
|||
name="host" |
|||
autofocus |
|||
:placeholder="t('setup.hostPlaceholder')" |
|||
:class="inputClass" |
|||
/> |
|||
</div> |
|||
<div> |
|||
<Label for="port">{{ $t('setup.port') }}</Label> |
|||
<input |
|||
id="port" |
|||
v-model="port" |
|||
form="form-set-host-port" |
|||
type="number" |
|||
name="port" |
|||
min="1" |
|||
max="65535" |
|||
:placeholder="t('setup.portPlaceholder')" |
|||
:class="inputClass" |
|||
/> |
|||
</div> |
|||
<form id="form-set-host-port"></form> |
|||
</div> |
|||
|
|||
<div v-if="step === 4"> |
|||
<p class="text-lg p-8 text-center">Migration section</p> |
|||
</div> |
|||
|
|||
<div v-if="step === 5"> |
|||
<p class="text-lg p-8 text-center">Validation section</p> |
|||
</div> |
|||
|
|||
<div class="flex justify-between items-center"> |
|||
<IconsArrowLeftCircle |
|||
:class="[ |
|||
'size-12', |
|||
step === 1 || towardStepValide() |
|||
? 'text-gray-500' |
|||
: 'text-red-800 dark:text-white', |
|||
]" |
|||
@click="decreaseStep" |
|||
/> |
|||
<UiStepProgress :step="step" /> |
|||
<IconsArrowRightCircle |
|||
:class="[ |
|||
'size-12', |
|||
step === 4 ? 'text-gray-500' : 'text-red-800 dark:text-white', |
|||
]" |
|||
@click="increaseStep" |
|||
/> |
|||
</div> |
|||
</PanelBody> |
|||
</Panel> |
|||
|
|||
<ErrorToast |
|||
v-if="setupError" |
|||
:title="setupError.title" |
|||
:message="setupError.message" |
|||
:duration="12000" |
|||
/> |
|||
</main> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { FetchError } from 'ofetch'; |
|||
|
|||
const { t, locale, setLocale } = useI18n(); |
|||
const authStore = useAuthStore(); |
|||
const setupStore = useSetupStore(); |
|||
const globalStore = useGlobalStore(); |
|||
|
|||
const inputClass = |
|||
'px-3 py-2 text-sm dark:bg-neutral-700 text-gray-500 dark:text-gray-500 mb-5 border-2 border-gray-100 dark:border-neutral-800 rounded-lg w-full focus:border-red-800 dark:focus:border-red-800 dark:placeholder:text-neutral-400 focus:outline-0 focus:ring-0'; |
|||
|
|||
type SetupError = { |
|||
title: string; |
|||
message: string; |
|||
}; |
|||
|
|||
const lang = ref(locale.value); |
|||
|
|||
/* STEP CREATE ADMIN USER MODELS */ |
|||
const username = ref<null | string>(null); |
|||
const password = ref<null | string>(null); |
|||
const accept = ref<boolean>(true); |
|||
|
|||
/* STEP SET HOST & PORT MODELS */ |
|||
const host = ref<null | string>(null); |
|||
const port = ref<null | number>(null); |
|||
|
|||
const step = ref(1); |
|||
const stepInvalide = ref<number[]>([]); |
|||
const setupError = ref<null | SetupError>(null); |
|||
|
|||
// TODO: improve error handling |
|||
watch(setupError, (value) => { |
|||
if (value) { |
|||
setTimeout(() => { |
|||
setupError.value = null; |
|||
}, 13000); |
|||
} |
|||
}); |
|||
|
|||
function handleEventUpdateLang(value: string) { |
|||
lang.value = value; |
|||
setLocale(lang.value); |
|||
} |
|||
|
|||
async function increaseStep() { |
|||
try { |
|||
if (step.value === 1) { |
|||
await updateLang(); |
|||
stepInvalide.value.push(1); |
|||
} |
|||
|
|||
if (step.value === 2) { |
|||
await newAccount(); |
|||
stepInvalide.value.push(2); |
|||
} |
|||
|
|||
if (step.value === 3) { |
|||
await updateHostPort(); |
|||
stepInvalide.value.push(3); |
|||
} |
|||
|
|||
if (step.value === 4) { |
|||
/* migration */ |
|||
stepInvalide.value.push(4); |
|||
} |
|||
|
|||
if (step.value === 5) { |
|||
/* validation/welcome */ |
|||
navigateTo('/login'); |
|||
stepInvalide.value.push(5); |
|||
} |
|||
|
|||
if (step.value < 5) step.value += 1; |
|||
// eslint-disable-next-line @typescript-eslint/no-unused-vars |
|||
} catch (error) { |
|||
/* throw in functions */ |
|||
} |
|||
} |
|||
|
|||
// TODO: improve while user reload the page, might use server check |
|||
/* Check if previous steps are invalide (mean successful executed). */ |
|||
function towardStepValide() { |
|||
return stepInvalide.value.includes(step.value - 1); |
|||
} |
|||
|
|||
function decreaseStep() { |
|||
if (towardStepValide()) return; |
|||
|
|||
if (step.value > 1) step.value -= 1; |
|||
} |
|||
|
|||
async function updateLang() { |
|||
try { |
|||
await globalStore.updateLang(lang.value); |
|||
} catch (error) { |
|||
if (error instanceof FetchError) { |
|||
setupError.value = { |
|||
title: t('setup.requirements'), |
|||
message: error.data.message, |
|||
}; |
|||
} |
|||
// increaseStep fn |
|||
throw error; |
|||
} |
|||
} |
|||
|
|||
async function newAccount() { |
|||
if (!username.value || !password.value) return; |
|||
|
|||
try { |
|||
await setupStore.signup(username.value, password.value, accept.value); |
|||
// the next step need authentication |
|||
await authStore.login(username.value, password.value, false); |
|||
} catch (error) { |
|||
if (error instanceof FetchError) { |
|||
setupError.value = { |
|||
title: t('setup.requirements'), |
|||
message: error.data.message, |
|||
}; |
|||
} |
|||
// increaseStep fn |
|||
throw error; |
|||
} |
|||
} |
|||
|
|||
async function updateHostPort() { |
|||
if (!host.value || !port.value) return; |
|||
try { |
|||
await setupStore.updateHostPort(host.value, port.value); |
|||
} catch (error) { |
|||
if (error instanceof FetchError) { |
|||
setupError.value = { |
|||
title: t('setup.requirements'), |
|||
message: error.data.message, |
|||
}; |
|||
} |
|||
// increaseStep fn |
|||
throw error; |
|||
} |
|||
} |
|||
</script> |
@ -0,0 +1,40 @@ |
|||
<template> |
|||
<div> |
|||
<p class="text-lg p-8 text-center"> |
|||
{{ $t('setup.messageSetupValidation') }} |
|||
</p> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { FetchError } from 'ofetch'; |
|||
|
|||
const { t } = useI18n(); |
|||
|
|||
const emit = defineEmits(['validated']); |
|||
|
|||
const props = defineProps<{ |
|||
next: boolean; |
|||
}>(); |
|||
|
|||
const next = toRef(props, 'next'); |
|||
|
|||
watch(next, async (newVal) => { |
|||
if (newVal) { |
|||
await runNext(); |
|||
} |
|||
}); |
|||
|
|||
async function runNext() { |
|||
try { |
|||
emit('validated', null); |
|||
} catch (error) { |
|||
if (error instanceof FetchError) { |
|||
emit('validated', { |
|||
title: t('setup.requirements'), |
|||
message: error.data.message, |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
</script> |
Loading…
Reference in new issue