chore: add i18n for onboarding flow and cleanup (#5285)

This commit is contained in:
Nivedin 2025-07-28 20:28:35 +05:30 committed by GitHub
parent 0b7d31a20c
commit 74efe58c7b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 179 additions and 68 deletions

View file

@ -9,6 +9,7 @@
"save": "Save"
},
"app": {
"back": "Back",
"collapse_sidebar": "Collapse Sidebar",
"continue_to_dashboard": "Continue to Dashboard",
"expand_sidebar": "Expand Sidebar",
@ -173,6 +174,53 @@
"toggle_description": "Get updates about the latest at Hoppscotch",
"unsubscribe": "Unsubscribe"
},
"onboarding": {
"add_atleast_one_auth_provider": "Please add at least one authentication provider to continue.",
"add_configurations": "Please add the configurations for the selected authentication methods.",
"add_oauth_config": "Add Auth Configurations",
"auth_setup": "Authentication Setup",
"auth_successfully_configured": "authentication has been successfully configured.",
"complete": "Complete",
"complete_description": "You have completed the onboarding process. You can now start using Hoppscotch.",
"complete_title": "Onboarding Complete",
"configurations": "Configurations",
"configurations_added_successfully": "Onboarding Configurations added successfully.",
"configurations_adding_failed": "Failed to add onboarding configs, please try again.",
"configurations_description": "Configure your Hoppscotch instance settings.",
"configuration_error": "Failed to add configurations",
"configurations_title": "Server Configurations",
"configuration_summary": "Configuration Summary",
"oauth": {
"description": "Set up OAuth providers like Google, GitHub, Microsoft, etc.",
"description_accordian": "Select the OAuth providers you want to enable and provide the necessary configurations.",
"title": "OAuth"
},
"onboarding_incomplete": {
"description": "You have not completed the onboarding process. Please set up at least one authentication provider to continue.",
"title": "Onboarding Incomplete"
},
"onboarding_fail_help": "If you are facing issues with the onboarding process, please contact support or check",
"please_fill_configurations": "Please fill the required field {fieldName}",
"save_auth_config": "Save Auth Config",
"setup_complete": {
"title": "Setup Complete",
"description": "You have successfully completed the onboarding process for your Hoppscotch instance.",
"description_sub": "The page will automatically redirect to the dashboard in a few seconds or you can reload once the server is restarted."
},
"server_restarting": "Server is restarting in {time} seconds...",
"smtp": {
"description": "Set up SMTP for email authentication.",
"description_accordian": "Configure the SMTP settings for sending emails.",
"title": "SMTP"
},
"smtp_advanced_config_enable": "Enable to configure your own SMTP credentials",
"select_auth_provider": "Please select the authentication methods you want to set up.",
"select_atleast_one": "Please select at least one authentication provider to continue.",
"start_onboarding": "Start Onboarding",
"welcome": "Welcome",
"welcome_screen_description": "Welcome to Hoppscotch! Let's get started with the setup.",
"welcome_screen_sub_description": "Please set up either SMTP or OAuth for authentication."
},
"settings": {
"settings": "Settings"
},

View file

@ -7,7 +7,7 @@
>
<div>
<h1 class="text-[1rem] font-normal">
Please select the authentication methods you want to set up.
{{ t('onboarding.select_auth_provider') }}
</h1>
</div>
<div>
@ -20,9 +20,11 @@
}"
@click="toggleSelectedOption('OAuth')"
>
<span class="text-[0.9rem] text-secondaryDark"> OAuth </span>
<span class="text-[0.9rem] text-secondaryDark">
{{ t('onboarding.oauth.title') }}
</span>
<span class="text-secondaryLight h-10">
Set up OAuth providers like Google, GitHub, Microsoft, etc.
{{ t('onboarding.oauth.description') }}
</span>
<div class="my-4">
<div class="flex items-center -space-x-2">
@ -52,9 +54,11 @@
}"
@click="toggleSelectedOption('SMTP')"
>
<span class="text-[0.9rem] text-secondaryDark"> SMTP </span>
<span class="text-[0.9rem] text-secondaryDark">
{{ t('onboarding.smtp.title') }}
</span>
<span class="text-secondaryLight h-10">
Set up SMTP for email authentication.
{{ t('onboarding.smtp.description') }}
</span>
<div class="my-4">
<div class="flex items-center -space-x-2">
@ -68,7 +72,7 @@
</div>
</div>
<HoppButtonPrimary
:label="'Add Auth Configs'"
:label="t('onboarding.add_oauth_config')"
@click="addAuthConfig"
:icon="IconLucideArrowRight"
:reverse="true"
@ -87,10 +91,12 @@
<span class="group-hover:opacity-80 transition-opacity">
<IconLucideArrowLeft class="svg-icons" />
</span>
<span class="group-hover:opacity-80 transition-opacity">Back</span>
<span class="group-hover:opacity-80 transition-opacity">
{{ t('app.back') }}
</span>
</button>
<h2>
Please add the configurations for the selected authentication methods.
{{ t('onboarding.add_configurations') }}
</h2>
<div class="my-5 overflow-y-auto max-h-[60vh]">
@ -107,7 +113,9 @@
<template v-slot:header="{ isOpen, toggleAccordion }">
<div class="w-full">
<div class="flex items-center justify-between flex-1 mb-2">
<span class="font-semibold text-[0.8rem]">OAuth </span>
<span class="font-semibold text-[0.8rem]"
>{{ t('onboarding.oauth.title') }}
</span>
<span>
<HoppSmartToggle
@ -123,9 +131,7 @@
</span>
</div>
<span class="text-tiny text-secondaryLight">
Select the OAuth providers you want to enable and provide
<br />
the necessary configurations.
{{ t('onboarding.oauth.description_accordian') }}
</span>
</div>
</template>
@ -146,7 +152,9 @@
<template v-slot:header="{ isOpen, toggleAccordion }">
<div class="w-full">
<div class="flex items-center justify-between flex-1 mb-2">
<span class="font-semibold text-[0.8rem]">SMTP</span>
<span class="font-semibold text-[0.8rem]">
{{ t('onboarding.smtp.title') }}
</span>
<span>
<HoppSmartToggle
:on="isOpen"
@ -162,7 +170,7 @@
</span>
</div>
<p class="text-secondaryLight text-tiny">
Configure the SMTP settings for sending emails.
{{ t('onboarding.smtp.description_accordian') }}
</p>
</div>
</template>
@ -176,10 +184,11 @@
</div>
</div>
<HoppButtonPrimary
:label="'Save Auth Configs'"
:label="t('onboarding.save_auth_config')"
@click="addOnboardingConfigs"
:reverse="true"
:icon="IconLucideSave"
:loading="submittingConfigs"
class="mt-4"
/>
</div>
@ -200,7 +209,9 @@ import IconLucideArrowRight from '~icons/lucide/arrow-right';
import IconLucideArrowLeft from '~icons/lucide/arrow-left';
import IconLucideSave from '~icons/lucide/save';
import { useToast } from '~/composables/toast';
import { useI18n } from '~/composables/i18n';
const t = useI18n();
const toast = useToast();
const props = withDefaults(
@ -296,7 +307,7 @@ const toggleSelectedOption = (option: 'OAuth' | 'SMTP') => {
const addAuthConfig = () => {
if (selectedOptions.value.length === 0) {
toast.error('Please select at least one authentication method.');
toast.error(t('onboarding.select_atleast_one'));
return;
}
authConfigStep.value = 2;

View file

@ -6,47 +6,66 @@
onBoardingSummary.configsAdded.length > 0
"
>
<h1 class="text-2xl font-bold text-white">Setup Complete 🎉</h1>
<h1 class="text-2xl font-bold text-white flex items-center space-x-2">
<span></span>
{{ t('onboarding.setup_complete.title') }}
<span class="">
<icon-lucide-badge-check class="svg-icons text-green-500 !h-8 !w-8" />
</span>
</h1>
<h2>
You have successfully completed the onboarding process for your
Hoppscotch instance.
{{ t('onboarding.setup_complete.description') }}
<br />
The page will automatically redirect to the dashboard in a few seconds
or you can reload once the server is restarted.
<span class="text-secondaryLight text-tiny">
{{ t('onboarding.setup_complete.description_sub') }}
</span>
</h2>
<div
class="my-4 p-4 bg-primaryLight rounded-lg border border-primaryDark shadow"
>
<h3 class="text-lg mb-6">Configuration Summary</h3>
<h3 class="text-lg mb-6">
{{ t('onboarding.configuration_summary') }}
</h3>
<div v-for="config in onBoardingSummary.configsAdded" class="my-2">
<div class="flex items-center space-x-2">
<icon-lucide-check class="svg-icons text-green-500" />
<p class="text-secondary">
<span class="capitalize"> {{ config.toLocaleLowerCase() }}</span>
authentication has been successfully configured.
{{ t('onboarding.auth_successfully_configured') }}
</p>
</div>
</div>
</div>
<HoppButtonPrimary
v-if="duration"
:label="`Server is restarting in ${duration} seconds...`"
:label="
t('onboarding.server_restarting', {
time: duration,
})
"
:disabled="duration > 0"
@click="emit('finish')"
class="w-min"
/>
<HoppButtonPrimary
v-else
label="Go to Dashboard"
:label="t('app.continue_to_dashboard')"
@click="emit('finish')"
class="w-min"
/>
</template>
<template v-else>
<h1 class="text-2xl font-bold text-white">Onboarding Incomplete</h1>
<div class="flex flex-col space-y-4 p-4 max-w-screen-md mx-auto w-full">
<h1 class="text-2xl font-bold text-white flex items-center space-x-2">
<span>
{{ t('onboarding.onboarding_incomplete.title') }}
</span>
<icon-lucide-alert-triangle
class="svg-icons text-yellow-500 !h-8 !w-8"
/>
</h1>
<h2>
There was an issue completing the onboarding process. Please check the
configurations and try again.
{{ t('onboarding.onboarding_incomplete.description') }}
</h2>
<HoppButtonPrimary
label="Retry Onboarding"
@ -54,7 +73,7 @@
class="w-min"
/>
<p class="text-secondaryLight text-tiny mt-2">
If you need help, please refer to the
{{ t('onboarding.onboarding_fail_help') }}
<a
href="https://docs.hoppscotch.io/documentation/self-host/community-edition"
target="_blank"
@ -62,6 +81,7 @@
>documentation</a
>.
</p>
</div>
</template>
</div>
</template>
@ -70,8 +90,10 @@
import { HoppButtonPrimary } from '@hoppscotch/ui';
import { onMounted, onUnmounted, ref } from 'vue';
import { useRouter } from 'vue-router';
import { useI18n } from '~/composables/i18n';
import { OnBoardingSummary } from '~/composables/useOnboardingConfigHandler';
const t = useI18n();
const router = useRouter();
const props = defineProps<{

View file

@ -56,7 +56,7 @@
{{ smtp.USE_CUSTOM_CONFIGS.text }}
</HoppSmartCheckbox>
<p class="text-secondaryLight text-tiny mt-2">
Enable to configure your own SMTP credentials
{{ t('onboarding.smtp_advanced_config_enable') }}
</p>
</div>
</template>
@ -69,6 +69,9 @@ import {
EnabledConfig,
MailerConfigKeys,
} from '~/composables/useOnboardingConfigHandler';
import { useI18n } from '~/composables/i18n';
const t = useI18n();
const props = defineProps<{
currentConfigs: Configs;

View file

@ -3,16 +3,26 @@
<div class="max-w-screen-md mx-auto p-8 flex flex-col space-y-4">
<div class="flex flex-col space-y-2 mb-4">
<img src="/logo.svg" alt="hoppscotch-logo" class="w-20 mb-4" />
<h1 class="text-3xl font-bold text-secondaryDark">Welcome</h1>
<h1 class="text-3xl font-bold text-secondaryDark">
{{ t('onboarding.welcome') }}
</h1>
<h2 class="mt-3">
This is the onboarding process for setting up your Hoppscotch
instance.
{{ t('onboarding.welcome_screen_description') }}
</h2>
<p class="text-secondaryLight">
Please set up either SMTP or OAuth for authentication.
{{ t('onboarding.welcome_screen_sub_description') }}
</p>
</div>
<HoppButtonPrimary label="Start Onboarding" @click="$emit('next')" />
<HoppButtonPrimary
:label="t('onboarding.start_onboarding')"
@click="$emit('next')"
/>
</div>
</div>
</template>
<script lang="ts" setup>
import { useI18n } from '~/composables/i18n';
const t = useI18n();
</script>

View file

@ -111,8 +111,8 @@ export function useOnboardingConfigHandler() {
const onBoardingSummary = ref<OnBoardingSummary>({
type: 'success',
message: t('onboarding.addConfigsSuccess'),
description: t('onboarding.addConfigsDescription'),
message: t('onboarding.setup_complete.title'),
description: t('onboarding.setup_complete.description'),
configsAdded: [] as string[],
});
@ -182,9 +182,10 @@ export function useOnboardingConfigHandler() {
if (addedConfigs.length === 0) {
return {
type: 'error',
message: t('onboarding.addConfigsError'),
description: t('onboarding.addConfigsDescription', {
error: error?.message || t('onboarding.addConfigsDefaultError'),
message: t('onboarding.onboarding_incomplete.title'),
description: t('onboarding.onboarding_incomplete.description', {
error:
error?.message || t('onboarding.onboarding_incomplete.description'),
}),
configsAdded: [],
};
@ -192,8 +193,8 @@ export function useOnboardingConfigHandler() {
return {
type: 'success',
message: t('onboarding.addConfigsSuccess'),
description: t('onboarding.addConfigsDescription'),
message: t('onboarding.setup_complete.title'),
description: t('onboarding.setup_complete.description'),
configsAdded: addedConfigs.filter((key) => key !== 'MAILER'),
};
};
@ -235,7 +236,7 @@ export function useOnboardingConfigHandler() {
*/
const validateConfigs = (configs: Partial<Record<string, string>>) => {
if (!configs || Object.keys(configs).length === 0) {
toast.error(t('onboarding.addConfigsError'));
toast.error(t('onboarding.configuration_error'));
return;
}
@ -250,7 +251,9 @@ export function useOnboardingConfigHandler() {
neededKeys.forEach((key) => {
if (!configs[key])
toast.error(
`Please fill the required field: ${makeReadableKey(key)}`
t('onboarding.please_fill_configurations', {
fieldName: makeReadableKey(key),
})
);
});
return;
@ -284,7 +287,8 @@ export function useOnboardingConfigHandler() {
const validated = validateConfigs(payload);
if (!validated || Object.keys(validated).length === 0) {
toast.error('Please add at least one config');
toast.error(t('onboarding.add_atleast_one_auth_provider'));
submittingConfigs.value = false;
return;
}
@ -299,13 +303,13 @@ export function useOnboardingConfigHandler() {
const res = await auth.addOnBoardingConfigs(configWithAuth);
if (res?.token) {
setLocalConfig('access_token', res.token);
toast.success('Onboarding configs added successfully');
toast.success(t('onboarding.configurations_added_successfully'));
onBoardingSummary.value = makeOnboardingSummary();
return res;
}
} catch (err) {
console.error('Failed to add onboarding configs', err);
toast.error('Failed to add onboarding configs');
toast.error(t('onboarding.configurations_adding_failed'));
onBoardingSummary.value = makeOnboardingSummary(err as Error);
} finally {
submittingConfigs.value = false;

View file

@ -45,7 +45,14 @@ export default <HoppModule>{
return next();
}
const isAdmin = res.data?.me.isAdmin;
if (
!onboardingStatus?.onboardingCompleted &&
!onboardingStatus?.canReRunOnboarding &&
to.name !== 'index' &&
to.name === 'onboarding'
) {
return next();
}
if (
onboardingStatus?.onboardingCompleted &&
@ -56,6 +63,8 @@ export default <HoppModule>{
return next({ name: 'index' });
}
const isAdmin = res.data?.me.isAdmin;
// Route Guards
if (!isGuestRoute(to.name) && !isAdmin) {
/**
@ -65,7 +74,7 @@ export default <HoppModule>{
return next({ name: 'index' });
}
if (isAdmin) {
if (isAdmin && onboardingStatus?.onboardingCompleted) {
// These route guards applies to the case where the user is logged in successfully and validated as an admin
const isInfraNotSetup = await getFirstTimeInfraSetupStatus();

View file

@ -3,10 +3,10 @@
<div
class="fixed top-0 left-0 p-5 flex items-center justify-between w-full"
>
<span class="text-md font-bold">HOPPSCOTCH</span>
<span class="text-md font-bold">{{ t('app.name') }}</span>
<HoppButtonPrimary
v-if="!isFirstTimeSetup"
label="Go to Dashboard"
:label="t('app.continue_to_dashboard')"
@click="goToDashboard"
/>
</div>
@ -41,9 +41,11 @@ import { useRouter } from 'vue-router';
import AuthSetup from '~/components/onboarding/AuthSetup.vue';
import CompleteOnboarding from '~/components/onboarding/CompleteScreen.vue';
import WelcomeScreen from '~/components/onboarding/WelcomeScreen.vue';
import { useI18n } from '~/composables/i18n';
import { OnBoardingSummary } from '~/composables/useOnboardingConfigHandler';
import { auth } from '~/helpers/auth';
const t = useI18n();
const router = useRouter();
// Steps
@ -99,8 +101,10 @@ watch(
);
// Push to URL when step changes
watch(step, (newStep) => {
watch(step, async (newStep) => {
if (newStep !== STEP.COMPLETE) {
router.replace({ name: 'onboarding', query: { step: newStep.toString() } });
}
});
// Load onboarding status