From 0b5dcf6ece649788a93a1305aaf7e8f64a5a6cf6 Mon Sep 17 00:00:00 2001 From: Michael Genson <71845777+michael-genson@users.noreply.github.com> Date: Mon, 19 Feb 2024 19:45:44 +0000 Subject: [PATCH 01/20] extract user registration form into a composable --- .../Domain/User/UserRegistrationForm.vue | 153 ++++++++++++++++++ .../use-users/user-registration-form.ts | 84 ++++++++++ frontend/lib/api/user/user-registration.ts | 2 - frontend/pages/register/index.vue | 142 ++++------------ 4 files changed, 269 insertions(+), 112 deletions(-) create mode 100644 frontend/components/Domain/User/UserRegistrationForm.vue create mode 100644 frontend/composables/use-users/user-registration-form.ts diff --git a/frontend/components/Domain/User/UserRegistrationForm.vue b/frontend/components/Domain/User/UserRegistrationForm.vue new file mode 100644 index 00000000000..b0ecfd9a75b --- /dev/null +++ b/frontend/components/Domain/User/UserRegistrationForm.vue @@ -0,0 +1,153 @@ + + + + {{ $globals.icons.user }} + {{ $t("user-registration.account-details") }} + + + + + + + + + + + + + + + {{ $tc("user.enable-advanced-content-description") }} + + + + + + + + + + diff --git a/frontend/composables/use-users/user-registration-form.ts b/frontend/composables/use-users/user-registration-form.ts new file mode 100644 index 00000000000..dfa644b821f --- /dev/null +++ b/frontend/composables/use-users/user-registration-form.ts @@ -0,0 +1,84 @@ +import { ref, Ref, useContext } from "@nuxtjs/composition-api"; +import { useAsyncValidator } from "~/composables/use-validators"; +import { VForm } from "~/types/vuetify"; +import { usePublicApi } from "~/composables/api/api-client"; + +const domAccountForm = ref(null); +const username = ref(""); +const email = ref(""); +const password1 = ref(""); +const password2 = ref(""); +const advancedOptions = ref(false); + +export const useUserRegistrationForm = () => { + const { i18n } = useContext(); + function safeValidate(form: Ref) { + if (form.value && form.value.validate) { + return form.value.validate(); + } + return false; + } + // ================================================================ + // Provide Group Details + const publicApi = usePublicApi(); + // ================================================================ + // Provide Account Details + + const usernameErrorMessages = ref([]); + const { validate: validateUsername, valid: validUsername } = useAsyncValidator( + username, + (v: string) => publicApi.validators.username(v), + i18n.tc("validation.username-is-taken"), + usernameErrorMessages + ); + const emailErrorMessages = ref([]); + const { validate: validateEmail, valid: validEmail } = useAsyncValidator( + email, + (v: string) => publicApi.validators.email(v), + i18n.tc("validation.email-is-taken"), + emailErrorMessages + ); + const accountDetails = { + username, + email, + advancedOptions, + validate: async () => { + if (!(validUsername.value && validEmail.value)) { + await Promise.all([validateUsername(), validateEmail()]); + } + + return (safeValidate(domAccountForm as Ref) && validUsername.value && validEmail.value); + }, + reset: () => { + accountDetails.username.value = ""; + accountDetails.email.value = ""; + accountDetails.advancedOptions.value = false; + }, + }; + // ================================================================ + // Provide Credentials + const passwordMatch = () => password1.value === password2.value || i18n.tc("user.password-must-match"); + const credentials = { + password1, + password2, + passwordMatch, + reset: () => { + credentials.password1.value = ""; + credentials.password2.value = ""; + } + }; + + return { + accountDetails, + credentials, + emailErrorMessages, + usernameErrorMessages, + // Fields + advancedOptions, + // Validators + validateUsername, + validateEmail, + // Dom Refs + domAccountForm, + }; +}; diff --git a/frontend/lib/api/user/user-registration.ts b/frontend/lib/api/user/user-registration.ts index ea722c5fbc5..e1921d4cf3e 100644 --- a/frontend/lib/api/user/user-registration.ts +++ b/frontend/lib/api/user/user-registration.ts @@ -8,8 +8,6 @@ const routes = { }; export class RegisterAPI extends BaseAPI { - /** Returns a list of available .zip files for import into Mealie. - */ async register(payload: CreateUserRegistration) { return await this.requests.post(routes.register, payload); } diff --git a/frontend/pages/register/index.vue b/frontend/pages/register/index.vue index 1cd1f74d88a..fd3ce361669 100644 --- a/frontend/pages/register/index.vue +++ b/frontend/pages/register/index.vue @@ -4,7 +4,7 @@ fluid class="d-flex justify-center align-center" :class="{ - 'bg-off-white': !$vuetify.theme.dark && !isDark.value, + 'bg-off-white': !$vuetify.theme.dark && !isDark, }" > @@ -136,73 +136,14 @@ - - {{ $globals.icons.user }} - {{ $t("user-registration.account-details") }} - - - - - - - - - - - - - - - {{ $tc("user.enable-advanced-content-description") }} - - - - + {{ $globals.icons.back }} {{ $t("general.back") }} - + {{ $globals.icons.forward }} {{ $t("general.next") }} @@ -258,6 +199,7 @@ import { defineComponent, onMounted, ref, useRouter, Ref, useContext, computed } from "@nuxtjs/composition-api"; import { useDark } from "@vueuse/core"; import { States, RegistrationType, useRegistration } from "./states"; +import { useUserRegistrationForm } from "~/composables/use-users/user-registration-form"; import { useRouteQuery } from "~/composables/use-router"; import { validators, useAsyncValidator } from "~/composables/use-validators"; import { useUserApi } from "~/composables/api"; @@ -268,6 +210,7 @@ import { usePasswordField } from "~/composables/use-passwords"; import { usePublicApi } from "~/composables/api/api-client"; import { useLocales } from "~/composables/use-locales"; import UserPasswordStrength from "~/components/Domain/User/UserPasswordStrength.vue"; +import UserRegistrationForm from "~/components/Domain/User/UserRegistrationForm.vue"; const inputAttrs = { filled: true, @@ -277,7 +220,7 @@ const inputAttrs = { }; export default defineComponent({ - components: { UserPasswordStrength }, + components: { UserPasswordStrength, UserRegistrationForm }, layout: "blank", setup() { const { i18n } = useContext(); @@ -370,48 +313,22 @@ export default defineComponent({ state.setState(States.ProvideAccountDetails); }, }; - // ================================================================ - // Provide Account Details - const domAccountForm = ref(null); - const username = ref(""); - const email = ref(""); - const advancedOptions = ref(false); - const usernameErrorMessages = ref([]); - const { validate: validateUsername, valid: validUsername } = useAsyncValidator( - username, - (v: string) => publicApi.validators.username(v), - i18n.tc("validation.username-is-taken"), - usernameErrorMessages - ); - const emailErrorMessages = ref([]); - const { validate: validateEmail, valid: validEmail } = useAsyncValidator( - email, - (v: string) => publicApi.validators.email(v), - i18n.tc("validation.email-is-taken"), - emailErrorMessages - ); - const accountDetails = { - username, - email, - advancedOptions, - next: () => { - if (!safeValidate(domAccountForm as Ref) || !validUsername.value || !validEmail.value) { + const pwFields = usePasswordField(); + const { + accountDetails, + credentials, + domAccountForm, + emailErrorMessages, + usernameErrorMessages, + validateUsername, + validateEmail, + } = useUserRegistrationForm(); + async function accountDetailsNext() { + if (!await accountDetails.validate()) { return; } state.setState(States.Confirmation); - }, - }; - // ================================================================ - // Provide Credentials - const password1 = ref(""); - const password2 = ref(""); - const pwFields = usePasswordField(); - const passwordMatch = () => password1.value === password2.value || i18n.tc("user.password-must-match"); - const credentials = { - password1, - password2, - passwordMatch, - }; + } // ================================================================ // Locale const { locale } = useLocales(); @@ -438,17 +355,17 @@ export default defineComponent({ { display: true, text: i18n.tc("user.email"), - value: email.value, + value: accountDetails.email.value, }, { display: true, text: i18n.tc("user.username"), - value: username.value, + value: accountDetails.username.value, }, { display: true, text: i18n.tc("user.enable-advanced-content"), - value: advancedOptions.value ? i18n.tc("general.yes") : i18n.tc("general.no"), + value: accountDetails.advancedOptions.value ? i18n.tc("general.yes") : i18n.tc("general.no"), }, ]; }); @@ -456,12 +373,12 @@ export default defineComponent({ const router = useRouter(); async function submitRegistration() { const payload: CreateUserRegistration = { - email: email.value, - username: username.value, - password: password1.value, - passwordConfirm: password2.value, + email: accountDetails.email.value, + username: accountDetails.username.value, + password: credentials.password1.value, + passwordConfirm: credentials.password2.value, locale: locale.value, - advanced: advancedOptions.value, + advanced: accountDetails.advancedOptions.value, }; if (state.ctx.type === RegistrationType.CreateGroup) { payload.group = groupName.value; @@ -472,12 +389,17 @@ export default defineComponent({ } const { response } = await api.register.register(payload); if (response?.status === 201) { + accountDetails.reset(); + credentials.reset(); alert.success(i18n.tc("user-registration.registration-success")); router.push("/login"); + } else { + alert.error(i18n.t("events.something-went-wrong") as string); } } return { accountDetails, + accountDetailsNext, confirmationData, credentials, emailErrorMessages, From b5fbee92947d9041a5688f5eff6ea907be340fb9 Mon Sep 17 00:00:00 2001 From: Michael Genson <71845777+michael-genson@users.noreply.github.com> Date: Mon, 19 Feb 2024 20:25:23 +0000 Subject: [PATCH 02/20] added base wizard component --- frontend/components/global/Wizard.vue | 257 ++++++++++++++++++++++++++ frontend/types/components.d.ts | 2 + 2 files changed, 259 insertions(+) create mode 100644 frontend/components/global/Wizard.vue diff --git a/frontend/components/global/Wizard.vue b/frontend/components/global/Wizard.vue new file mode 100644 index 00000000000..5898cc861fd --- /dev/null +++ b/frontend/components/global/Wizard.vue @@ -0,0 +1,257 @@ + + + + + + + Mealie + + + + + + + + + + + + + + + + + + + + + + {{ prevButtonIcon }} + + {{ prevButtonText }} + + + + + + + + + {{ nextButtonIcon }} + + {{ nextButtonText }} + + {{ nextButtonIcon }} + + + + + + + {{ $globals.icons.translate }} + {{ $t("language-dialog.choose-language") }} + + + + + + + + + diff --git a/frontend/types/components.d.ts b/frontend/types/components.d.ts index be102380138..3cfeee63732 100644 --- a/frontend/types/components.d.ts +++ b/frontend/types/components.d.ts @@ -32,6 +32,7 @@ import ReportTable from "@/components/global/ReportTable.vue"; import SafeMarkdown from "@/components/global/SafeMarkdown.vue"; import StatsCards from "@/components/global/StatsCards.vue"; import ToggleState from "@/components/global/ToggleState.vue"; +import Wizard from "@/components/global/Wizard.vue"; import DefaultLayout from "@/components/layout/DefaultLayout.vue"; declare module "vue" { @@ -70,6 +71,7 @@ declare module "vue" { SafeMarkdown: typeof SafeMarkdown; StatsCards: typeof StatsCards; ToggleState: typeof ToggleState; + Wizard: typeof Wizard; // Layout Components DefaultLayout: typeof DefaultLayout; } From 8e80a656cc09d046a5f4779e39e2d2cf8d418793 Mon Sep 17 00:00:00 2001 From: Michael Genson <71845777+michael-genson@users.noreply.github.com> Date: Mon, 19 Feb 2024 20:25:38 +0000 Subject: [PATCH 03/20] added partial setup implementation --- frontend/lang/messages/en-US.json | 6 +- frontend/pages/admin/setup.vue | 178 ++++++++++++++++++++++++++++++ frontend/pages/index.vue | 23 ++-- frontend/pages/login.vue | 25 +++-- 4 files changed, 213 insertions(+), 19 deletions(-) create mode 100644 frontend/pages/admin/setup.vue diff --git a/frontend/lang/messages/en-US.json b/frontend/lang/messages/en-US.json index 932a49bb303..da10d5e3efc 100644 --- a/frontend/lang/messages/en-US.json +++ b/frontend/lang/messages/en-US.json @@ -168,6 +168,7 @@ "units": "Units", "back": "Back", "next": "Next", + "start": "Start", "toggle-view": "Toggle View", "date": "Date", "id": "Id", @@ -1129,7 +1130,10 @@ "background-tasks": "Background Tasks", "background-tasks-description": "Here you can view all the running background tasks and their status", "no-logs-found": "No Logs Found", - "tasks": "Tasks" + "tasks": "Tasks", + "first-time-setup": "First Time Setup", + "welcome-to-mealie-get-started": "Welcome to Mealie! Let's get started", + "already-set-up-bring-to-homepage": "I'm already set up, just bring me to the homepage" }, "profile": { "welcome-user": "👋 Welcome, {0}", diff --git a/frontend/pages/admin/setup.vue b/frontend/pages/admin/setup.vue new file mode 100644 index 00000000000..9eebbdd4083 --- /dev/null +++ b/frontend/pages/admin/setup.vue @@ -0,0 +1,178 @@ + + + + + + {{ $i18n.tc('admin.welcome-to-mealie-get-started') }} + + + {{ $i18n.tc('admin.already-set-up-bring-to-homepage') }} + + + + + + + Page 2 + + + Confirm Page + + + End Page + + + + + + diff --git a/frontend/pages/index.vue b/frontend/pages/index.vue index 795b423388c..612ed71ed06 100644 --- a/frontend/pages/index.vue +++ b/frontend/pages/index.vue @@ -3,8 +3,9 @@ diff --git a/frontend/pages/login.vue b/frontend/pages/login.vue index 2e6bfcec6b2..1d9a17f6169 100644 --- a/frontend/pages/login.vue +++ b/frontend/pages/login.vue @@ -132,14 +132,7 @@ export default defineComponent({ const { $auth, i18n, $axios } = useContext(); const { loggedIn } = useLoggedInState(); const groupSlug = computed(() => $auth.user?.groupSlug); - - whenever( - () => loggedIn.value && groupSlug.value, - () => { - router.push(`/g/${groupSlug.value || ""}`); - }, - { immediate: true }, - ); + const isFirstLogin = ref(false); const form = reactive({ email: "", @@ -147,12 +140,22 @@ export default defineComponent({ remember: false, }); - const isFirstLogin = ref(false) - useAsync(async () => { const data = await $axios.get("/api/app/about/startup-info"); isFirstLogin.value = data.data.isFirstLogin; - }, useAsyncKey()); + }, useAsyncKey()); + + whenever( + () => loggedIn.value && groupSlug.value, + () => { + if (isFirstLogin.value && $auth.user?.admin) { + router.push("/admin/setup"); + } else { + router.push(`/g/${groupSlug.value || ""}`); + } + }, + { immediate: true }, + ); const loggingIn = ref(false); From cf23b79710811765a5c89a2c5459bae67f69ee28 Mon Sep 17 00:00:00 2001 From: Michael Genson <71845777+michael-genson@users.noreply.github.com> Date: Mon, 19 Feb 2024 20:28:03 +0000 Subject: [PATCH 04/20] removed unused attrs --- frontend/pages/admin/setup.vue | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/frontend/pages/admin/setup.vue b/frontend/pages/admin/setup.vue index 9eebbdd4083..7686aa7fe15 100644 --- a/frontend/pages/admin/setup.vue +++ b/frontend/pages/admin/setup.vue @@ -61,7 +61,7 @@ export default defineComponent({ components: { UserRegistrationForm }, layout: "blank", setup() { - const { $auth, $globals, $vuetify, i18n } = useContext(); + const { $auth, $globals, i18n } = useContext(); const { accountDetails } = useUserRegistrationForm(); const groupSlug = computed(() => $auth.user?.groupSlug); @@ -72,14 +72,6 @@ export default defineComponent({ router.push("/login"); } - const attrs = computed(() => { - return $vuetify.breakpoint.smAndDown ? { - maxWidth: undefined, - } : { - maxWidth: "800", - } - }) - type Config = { nextButtonText: string | undefined; nextButtonIcon: string | undefined; @@ -159,7 +151,6 @@ export default defineComponent({ } return { - attrs, Pages, currentPage, totalPages, From 8ea0a97d2f66091337b556d2a3da18b431bbb9fa Mon Sep 17 00:00:00 2001 From: Michael Genson <71845777+michael-genson@users.noreply.github.com> Date: Mon, 19 Feb 2024 20:31:32 +0000 Subject: [PATCH 05/20] added setup bypass --- frontend/pages/admin/setup.vue | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/frontend/pages/admin/setup.vue b/frontend/pages/admin/setup.vue index 7686aa7fe15..6af8831ba0a 100644 --- a/frontend/pages/admin/setup.vue +++ b/frontend/pages/admin/setup.vue @@ -27,11 +27,13 @@ {{ $i18n.tc('admin.welcome-to-mealie-get-started') }} {{ $i18n.tc('admin.already-set-up-bring-to-homepage') }} @@ -70,6 +72,8 @@ export default defineComponent({ if (!$auth.loggedIn) { router.push("/login"); + } else if (!$auth.user?.admin) { + router.push(groupSlug.value ? `/g/${groupSlug.value}` : "/login"); } type Config = { @@ -144,7 +148,7 @@ export default defineComponent({ currentPage.value += 1; break; case Pages.END: - router.push(groupSlug.value ? `/g/${groupSlug.value || ""}` : "/login"); + router.push(groupSlug.value ? `/g/${groupSlug.value}` : "/login"); break; } isSubmitting.value = false; @@ -157,6 +161,7 @@ export default defineComponent({ activeConfig, isSubmitting, handleSubmit, + groupSlug, } }, From da100d1e59ec08a9099145fbab4971ff75fe471c Mon Sep 17 00:00:00 2001 From: Michael Genson <71845777+michael-genson@users.noreply.github.com> Date: Mon, 19 Feb 2024 20:35:15 +0000 Subject: [PATCH 06/20] made setup page more readable --- frontend/pages/admin/setup.vue | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/frontend/pages/admin/setup.vue b/frontend/pages/admin/setup.vue index 6af8831ba0a..9cafdb4265f 100644 --- a/frontend/pages/admin/setup.vue +++ b/frontend/pages/admin/setup.vue @@ -63,6 +63,8 @@ export default defineComponent({ components: { UserRegistrationForm }, layout: "blank", setup() { + // ================================================================ + // Setup const { $auth, $globals, i18n } = useContext(); const { accountDetails } = useUserRegistrationForm(); @@ -94,6 +96,8 @@ export default defineComponent({ END = 4, } + // ================================================================ + // Page Navigation const currentPage = ref(0); const activeConfig = computed(() => { const config: Config = { @@ -131,6 +135,8 @@ export default defineComponent({ return config; }) + // ================================================================ + // Page Submission async function handleSubmit(page: number) { if (isSubmitting.value) { return; @@ -165,7 +171,7 @@ export default defineComponent({ } }, - header() { + head() { return { title: this.$i18n.tc("admin.first-time-setup"), }; From 3698b8342d37cd5ce66a8b10a4a5a2b402ad4576 Mon Sep 17 00:00:00 2001 From: Michael Genson <71845777+michael-genson@users.noreply.github.com> Date: Mon, 19 Feb 2024 23:06:27 +0000 Subject: [PATCH 07/20] add checkbox hints to autoform --- frontend/components/global/AutoForm.vue | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/frontend/components/global/AutoForm.vue b/frontend/components/global/AutoForm.vue index f92acf2e975..2f143f52ea6 100644 --- a/frontend/components/global/AutoForm.vue +++ b/frontend/components/global/AutoForm.vue @@ -15,12 +15,22 @@ v-if="inputField.type === fieldTypes.BOOLEAN" v-model="value[inputField.varName]" class="my-0 py-0" - :label="inputField.label" :name="inputField.varName" - :hint="inputField.hint || ''" :disabled="(inputField.disableUpdate && updateMode) || (!updateMode && inputField.disableCreate) || (disabledFields && disabledFields.includes(inputField.varName))" @change="emitBlur" - /> + > + + + + {{ inputField.label }} + + + {{ inputField.hint }} + + + + + Date: Mon, 19 Feb 2024 23:07:03 +0000 Subject: [PATCH 08/20] added common settings pages and initial submit logic --- .../use-setup/common-settings-form.ts | 30 +++ frontend/composables/use-setup/index.ts | 1 + frontend/composables/use-users/index.ts | 1 + frontend/lang/messages/en-US.json | 6 +- frontend/pages/admin/setup.vue | 193 +++++++++++++++++- frontend/pages/register/index.vue | 2 +- 6 files changed, 226 insertions(+), 7 deletions(-) create mode 100644 frontend/composables/use-setup/common-settings-form.ts create mode 100644 frontend/composables/use-setup/index.ts diff --git a/frontend/composables/use-setup/common-settings-form.ts b/frontend/composables/use-setup/common-settings-form.ts new file mode 100644 index 00000000000..12b3a7496e5 --- /dev/null +++ b/frontend/composables/use-setup/common-settings-form.ts @@ -0,0 +1,30 @@ +import { useContext } from "@nuxtjs/composition-api"; +import { fieldTypes } from "../forms"; +import { AutoFormItems } from "~/types/auto-forms"; + +export const useCommonSettingsForm = () => { + const { i18n } = useContext(); + + const commonSettingsForm: AutoFormItems = [ + { + section: i18n.tc("profile.group-settings"), + label: i18n.tc("group.enable-public-access"), + hint: i18n.tc("group.enable-public-access-description"), + varName: "makeGroupRecipesPublic", + type: fieldTypes.BOOLEAN, + rules: ["required"], + }, + { + section: i18n.tc("data-pages.data-management"), + label: i18n.tc("user-registration.use-seed-data"), + hint: i18n.tc("user-registration.use-seed-data-description"), + varName: "useSeedData", + type: fieldTypes.BOOLEAN, + rules: ["required"], + }, + ]; + + return { + commonSettingsForm, + } +} diff --git a/frontend/composables/use-setup/index.ts b/frontend/composables/use-setup/index.ts new file mode 100644 index 00000000000..13297ef4b8a --- /dev/null +++ b/frontend/composables/use-setup/index.ts @@ -0,0 +1 @@ +export { useCommonSettingsForm } from './common-settings-form'; diff --git a/frontend/composables/use-users/index.ts b/frontend/composables/use-users/index.ts index adacee24eb8..f1b1a6a8571 100644 --- a/frontend/composables/use-users/index.ts +++ b/frontend/composables/use-users/index.ts @@ -1 +1,2 @@ export { useUserForm } from "./user-form"; +export { useUserRegistrationForm } from "./user-registration-form"; diff --git a/frontend/lang/messages/en-US.json b/frontend/lang/messages/en-US.json index da10d5e3efc..6e6e0f1b7e7 100644 --- a/frontend/lang/messages/en-US.json +++ b/frontend/lang/messages/en-US.json @@ -84,6 +84,7 @@ "clear": "Clear", "close": "Close", "confirm": "Confirm", + "confirm-how-does-everything-look": "How does everything look?", "confirm-delete-generic": "Are you sure you want to delete this?", "copied_message": "Copied!", "create": "Create", @@ -237,6 +238,8 @@ "group-preferences": "Group Preferences", "private-group": "Private Group", "private-group-description": "Setting your group to private will default all public view options to default. This overrides an individual recipes public view settings.", + "enable-public-access": "Enable Public Access", + "enable-public-access-description": "Make group recipes public by default, and allow visitors to view recipes without logging-in", "allow-users-outside-of-your-group-to-see-your-recipes": "Allow users outside of your group to see your recipes", "allow-users-outside-of-your-group-to-see-your-recipes-description": "When enabled you can use a public share link to share specific recipes without authorizing the user. When disabled, you can only share recipes with users who are in your group or with a pre-generated private link", "show-nutrition-information": "Show nutrition information", @@ -1133,7 +1136,8 @@ "tasks": "Tasks", "first-time-setup": "First Time Setup", "welcome-to-mealie-get-started": "Welcome to Mealie! Let's get started", - "already-set-up-bring-to-homepage": "I'm already set up, just bring me to the homepage" + "already-set-up-bring-to-homepage": "I'm already set up, just bring me to the homepage", + "common-settings-for-new-sites": "Here are some common settings for new sites" }, "profile": { "welcome-user": "👋 Welcome, {0}", diff --git a/frontend/pages/admin/setup.vue b/frontend/pages/admin/setup.vue index 9cafdb4265f..9bc62595722 100644 --- a/frontend/pages/admin/setup.vue +++ b/frontend/pages/admin/setup.vue @@ -42,10 +42,26 @@ - Page 2 + + {{ $i18n.tc('admin.common-settings-for-new-sites') }} + + - Confirm Page + + {{ $t("general.confirm-how-does-everything-look") }} + + + + + + {{ item.text }} + {{ item.value }} + + + + + End Page @@ -56,7 +72,11 @@
+ {{ $tc("user.enable-advanced-content-description") }} +
- {{ $tc("user.enable-advanced-content-description") }} -