Feat: Initial Setup through env vars (#1736)
* initial support for initial setup * improve setup * improve mobile view * move base admin route * admin panel mobile view * set initial host and port * add docs * properly setup everything, use for dev env * change userconfig and interface port on setup, note users afterwards
This commit is contained in:
+10
-5
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="container mx-auto p-4">
|
||||
<div class="flex">
|
||||
<div class="mr-4 w-64 rounded-lg bg-white p-4 dark:bg-neutral-700">
|
||||
<div class="flex flex-col gap-4 lg:flex-row">
|
||||
<div class="rounded-lg bg-white p-4 lg:w-64 dark:bg-neutral-700">
|
||||
<NuxtLink to="/admin">
|
||||
<h2 class="mb-4 text-xl font-bold dark:text-neutral-200">
|
||||
{{ t('pages.admin.panel') }}
|
||||
@@ -13,6 +13,7 @@
|
||||
v-for="(item, index) in menuItems"
|
||||
:key="index"
|
||||
:to="`/admin/${item.id}`"
|
||||
active-class="bg-red-800 rounded"
|
||||
>
|
||||
<BaseButton
|
||||
as="span"
|
||||
@@ -27,7 +28,7 @@
|
||||
<div
|
||||
class="flex-1 rounded-lg bg-white p-6 dark:bg-neutral-700 dark:text-neutral-200"
|
||||
>
|
||||
<h1 class="mb-6 text-3xl font-bold">{{ activeMenuItem?.name }}</h1>
|
||||
<h1 class="mb-6 text-3xl font-bold">{{ activeMenuItem.name }}</h1>
|
||||
<NuxtPage />
|
||||
</div>
|
||||
</div>
|
||||
@@ -44,13 +45,17 @@ const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
|
||||
const menuItems = [
|
||||
{ id: '', name: t('pages.admin.general') },
|
||||
{ id: 'general', name: t('pages.admin.general') },
|
||||
{ id: 'config', name: t('pages.admin.config') },
|
||||
{ id: 'interface', name: t('pages.admin.interface') },
|
||||
{ id: 'hooks', name: t('pages.admin.hooks') },
|
||||
];
|
||||
|
||||
const defaultItem = { id: '', name: t('pages.admin.panel') };
|
||||
|
||||
const activeMenuItem = computed(() => {
|
||||
return menuItems.find((item) => route.path === `/admin/${item.id}`);
|
||||
return (
|
||||
menuItems.find((item) => route.path === `/admin/${item.id}`) ?? defaultItem
|
||||
);
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<main v-if="data">
|
||||
<FormElement @submit.prevent="submit">
|
||||
<FormGroup>
|
||||
<FormNumberField
|
||||
id="session"
|
||||
v-model="data.sessionTimeout"
|
||||
:label="$t('admin.general.sessionTimeout')"
|
||||
:description="$t('admin.general.sessionTimeoutDesc')"
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup>
|
||||
<FormHeading>{{ $t('admin.general.metrics') }}</FormHeading>
|
||||
<FormNullTextField
|
||||
id="password"
|
||||
v-model="data.metricsPassword"
|
||||
:label="$t('admin.general.metricsPassword')"
|
||||
:description="$t('admin.general.metricsPasswordDesc')"
|
||||
/>
|
||||
<FormSwitchField
|
||||
id="prometheus"
|
||||
v-model="data.metricsPrometheus"
|
||||
:label="$t('admin.general.prometheus')"
|
||||
:description="$t('admin.general.prometheusDesc')"
|
||||
/>
|
||||
<FormSwitchField
|
||||
id="json"
|
||||
v-model="data.metricsJson"
|
||||
:label="$t('admin.general.json')"
|
||||
:description="$t('admin.general.jsonDesc')"
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup>
|
||||
<FormHeading>{{ $t('form.actions') }}</FormHeading>
|
||||
<FormActionField type="submit" :label="$t('form.save')" />
|
||||
<FormActionField :label="$t('form.revert')" @click="revert" />
|
||||
</FormGroup>
|
||||
</FormElement>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const { data: _data, refresh } = await useFetch(`/api/admin/general`, {
|
||||
method: 'get',
|
||||
});
|
||||
const data = toRef(_data.value);
|
||||
|
||||
const _submit = useSubmit(
|
||||
`/api/admin/general`,
|
||||
{
|
||||
method: 'post',
|
||||
},
|
||||
{ revert }
|
||||
);
|
||||
|
||||
function submit() {
|
||||
return _submit(data.value);
|
||||
}
|
||||
|
||||
async function revert() {
|
||||
await refresh();
|
||||
data.value = toRef(_data.value).value;
|
||||
}
|
||||
</script>
|
||||
@@ -1,64 +1,5 @@
|
||||
<template>
|
||||
<main v-if="data">
|
||||
<FormElement @submit.prevent="submit">
|
||||
<FormGroup>
|
||||
<FormNumberField
|
||||
id="session"
|
||||
v-model="data.sessionTimeout"
|
||||
:label="$t('admin.general.sessionTimeout')"
|
||||
:description="$t('admin.general.sessionTimeoutDesc')"
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup>
|
||||
<FormHeading>{{ $t('admin.general.metrics') }}</FormHeading>
|
||||
<FormNullTextField
|
||||
id="password"
|
||||
v-model="data.metricsPassword"
|
||||
:label="$t('admin.general.metricsPassword')"
|
||||
:description="$t('admin.general.metricsPasswordDesc')"
|
||||
/>
|
||||
<FormSwitchField
|
||||
id="prometheus"
|
||||
v-model="data.metricsPrometheus"
|
||||
:label="$t('admin.general.prometheus')"
|
||||
:description="$t('admin.general.prometheusDesc')"
|
||||
/>
|
||||
<FormSwitchField
|
||||
id="json"
|
||||
v-model="data.metricsJson"
|
||||
:label="$t('admin.general.json')"
|
||||
:description="$t('admin.general.jsonDesc')"
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup>
|
||||
<FormHeading>{{ $t('form.actions') }}</FormHeading>
|
||||
<FormActionField type="submit" :label="$t('form.save')" />
|
||||
<FormActionField :label="$t('form.revert')" @click="revert" />
|
||||
</FormGroup>
|
||||
</FormElement>
|
||||
<main class="flex flex-col gap-3">
|
||||
<p class="whitespace-pre-line">{{ $t('admin.introText') }}</p>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const { data: _data, refresh } = await useFetch(`/api/admin/general`, {
|
||||
method: 'get',
|
||||
});
|
||||
const data = toRef(_data.value);
|
||||
|
||||
const _submit = useSubmit(
|
||||
`/api/admin/general`,
|
||||
{
|
||||
method: 'post',
|
||||
},
|
||||
{ revert }
|
||||
);
|
||||
|
||||
function submit() {
|
||||
return _submit(data.value);
|
||||
}
|
||||
|
||||
async function revert() {
|
||||
await refresh();
|
||||
data.value = toRef(_data.value).value;
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -54,6 +54,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const authStore = useAuthStore();
|
||||
authStore.update();
|
||||
|
||||
const authenticating = ref(false);
|
||||
const remember = ref(false);
|
||||
const username = ref<null | string>(null);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<div>
|
||||
<p class="px-8 pt-8 text-center text-2xl">
|
||||
<div class="flex flex-col items-center">
|
||||
<p class="px-8 text-center text-2xl">
|
||||
{{ $t('setup.welcomeDesc') }}
|
||||
</p>
|
||||
<NuxtLink to="/setup/2">
|
||||
<NuxtLink to="/setup/2" class="mt-8">
|
||||
<BaseButton as="span">{{ $t('general.continue') }}</BaseButton>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<div>
|
||||
<p class="p-8 text-center text-lg">
|
||||
<p class="text-center text-lg">
|
||||
{{ $t('setup.createAdminDesc') }}
|
||||
</p>
|
||||
<div class="flex flex-col gap-3">
|
||||
<div class="mt-8 flex flex-col gap-3">
|
||||
<div class="flex flex-col">
|
||||
<FormNullTextField
|
||||
id="username"
|
||||
@@ -28,7 +28,7 @@
|
||||
:label="$t('general.confirmPassword')"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<div class="mt-4 flex justify-center">
|
||||
<BaseButton @click="submit">{{ $t('setup.createAccount') }}</BaseButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
<template>
|
||||
<div>
|
||||
<p class="p-8 text-center text-lg">
|
||||
<p class="text-center text-lg">
|
||||
{{ $t('setup.existingSetup') }}
|
||||
</p>
|
||||
<div class="mb-8 flex justify-center">
|
||||
<NuxtLink to="/setup/4">
|
||||
<BaseButton as="span">{{ $t('general.no') }}</BaseButton>
|
||||
<div class="mt-4 flex justify-center gap-3">
|
||||
<NuxtLink to="/setup/4" class="w-20">
|
||||
<BaseButton as="span" class="w-full justify-center">
|
||||
{{ $t('general.no') }}
|
||||
</BaseButton>
|
||||
</NuxtLink>
|
||||
<NuxtLink to="/setup/migrate">
|
||||
<BaseButton as="span">{{ $t('general.yes') }}</BaseButton>
|
||||
<NuxtLink to="/setup/migrate" class="w-20">
|
||||
<BaseButton as="span" class="w-full justify-center">
|
||||
{{ $t('general.yes') }}
|
||||
</BaseButton>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,21 +1,27 @@
|
||||
<template>
|
||||
<div>
|
||||
<p class="p-8 text-center text-lg">
|
||||
<p class="text-center text-lg">
|
||||
{{ $t('setup.setupConfigDesc') }}
|
||||
</p>
|
||||
<div class="flex flex-col gap-3">
|
||||
<div class="mt-8 flex flex-col gap-3">
|
||||
<div class="flex flex-col">
|
||||
<FormNullTextField
|
||||
id="host"
|
||||
v-model="host"
|
||||
:label="$t('general.host')"
|
||||
placeholder="vpn.example.com"
|
||||
:description="$t('setup.hostDesc')"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<FormNumberField id="port" v-model="port" :label="$t('general.port')" />
|
||||
<FormNumberField
|
||||
id="port"
|
||||
v-model="port"
|
||||
:label="$t('general.port')"
|
||||
:description="$t('setup.portDesc')"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<div class="mt-4 flex justify-center">
|
||||
<BaseButton @click="submit">{{ $t('general.continue') }}</BaseButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
<template>
|
||||
<div>
|
||||
<p class="p-8 text-center text-lg">
|
||||
<div class="flex flex-col items-center">
|
||||
<p class="text-center text-lg">
|
||||
{{ $t('setup.setupMigrationDesc') }}
|
||||
</p>
|
||||
<div>
|
||||
<div class="mt-8 flex gap-3">
|
||||
<Label for="migration">{{ $t('setup.migration') }}</Label>
|
||||
<input id="migration" type="file" @change="onChangeFile" />
|
||||
</div>
|
||||
<BaseButton @click="submit">{{ $t('setup.upload') }}</BaseButton>
|
||||
<div class="mt-4">
|
||||
<BaseButton @click="submit">{{ $t('setup.upload') }}</BaseButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="flex flex-col items-center">
|
||||
<p>{{ $t('setup.successful') }}</p>
|
||||
<NuxtLink to="/login">
|
||||
<NuxtLink to="/login" class="mt-4">
|
||||
<BaseButton as="span">{{ $t('login.signIn') }}</BaseButton>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user