Self hosted domain redirect (#756)
* Integration pages from Notion * Self hosted domain redirect * Refactor root-redirect middleware and update 404 page layout - Simplified the `root-redirect.js` middleware by removing the specific route checks, allowing for a more general redirect based on the `self_hosted` feature flag. - Updated the 404 error page in `[...all].vue` by removing the unnecessary `NuxtLayout` wrapper and replacing `NuxtLink` with a custom `UButton` for navigation, enhancing the overall layout and user experience. These changes aim to streamline the redirect logic and improve the presentation of the 404 error page. * Refactor feature flag handling and update middleware - Updated the condition in `Navbar.vue` to correctly evaluate the feature flags for rendering the AI form builder link. - Removed the `feature-flags.global.js` middleware as it was no longer needed, streamlining the middleware structure. - Enhanced the `root-redirect.js` middleware to utilize `h3`'s `sendRedirect` for server-side redirection, improving the redirect logic. - Modified the `ai-form-builder.vue` page to include the new `root-redirect` middleware, ensuring proper redirection based on feature flags. These changes aim to improve the handling of feature flags and redirection logic, enhancing the overall application flow. --------- Co-authored-by: Julien Nahum <julien@nahum.net>
This commit is contained in:
parent
cc2b0e989d
commit
b2b04d7f2a
|
|
@ -7,4 +7,5 @@ NUXT_PUBLIC_ENV=
|
||||||
NUXT_PUBLIC_GOOGLE_ANALYTICS_CODE=
|
NUXT_PUBLIC_GOOGLE_ANALYTICS_CODE=
|
||||||
NUXT_PUBLIC_H_CAPTCHA_SITE_KEY=
|
NUXT_PUBLIC_H_CAPTCHA_SITE_KEY=
|
||||||
NUXT_PUBLIC_RE_CAPTCHA_SITE_KEY=
|
NUXT_PUBLIC_RE_CAPTCHA_SITE_KEY=
|
||||||
NUXT_API_SECRET=secret
|
NUXT_API_SECRET=secret
|
||||||
|
NUXT_PUBLIC_ROOT_REDIRECT_URL=
|
||||||
|
|
@ -53,7 +53,7 @@
|
||||||
</a>
|
</a>
|
||||||
</template>
|
</template>
|
||||||
<NuxtLink
|
<NuxtLink
|
||||||
v-if="($route.name !== 'ai-form-builder' && user === null) && (!useFeatureFlag('self_hosted') || useFeatureFlag('ai_features'))"
|
v-if="($route.name !== 'ai-form-builder' && user === null) && (!useFeatureFlag('self_hosted') && useFeatureFlag('ai_features'))"
|
||||||
:to="{ name: 'ai-form-builder' }"
|
:to="{ name: 'ai-form-builder' }"
|
||||||
:class="navLinkClasses"
|
:class="navLinkClasses"
|
||||||
class="hidden lg:inline"
|
class="hidden lg:inline"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { sendRedirect } from 'h3'
|
||||||
|
|
||||||
|
export default defineNuxtRouteMiddleware(() => {
|
||||||
|
if (!useFeatureFlag('self_hosted')) return
|
||||||
|
const redirectUrl = useRuntimeConfig().public.rootRedirectUrl
|
||||||
|
|
||||||
|
// Only run if env var is set and is a valid URL
|
||||||
|
if (!redirectUrl || !/^https?:\/\//.test(redirectUrl)) return
|
||||||
|
|
||||||
|
// Server-side: use h3's sendRedirect
|
||||||
|
if (import.meta.server) {
|
||||||
|
|
||||||
|
const event = useRequestEvent()
|
||||||
|
if (event) {
|
||||||
|
return sendRedirect(event, redirectUrl, 301)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client-side handling
|
||||||
|
return navigateTo(redirectUrl, { external: true })
|
||||||
|
})
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="flex mt-6">
|
||||||
|
<div class="w-full md:w-2/3 md:mx-auto md:max-w-md">
|
||||||
|
<img
|
||||||
|
alt="Nice plant as we have nothing else to show!"
|
||||||
|
src="/img/icons/plant.png"
|
||||||
|
class="w-56 mb-5"
|
||||||
|
>
|
||||||
|
|
||||||
|
<h1 class="mb-6 font-semibold text-3xl text-gray-900">
|
||||||
|
Page not found (404)
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<div class="links">
|
||||||
|
<UButton
|
||||||
|
:to="{ name: 'index' }"
|
||||||
|
class="hover:underline"
|
||||||
|
>
|
||||||
|
Go Home
|
||||||
|
</UButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
definePageMeta({
|
||||||
|
middleware: ['root-redirect']
|
||||||
|
})
|
||||||
|
|
||||||
|
useOpnSeoMeta({
|
||||||
|
title: "404 - Page not found",
|
||||||
|
})
|
||||||
|
|
||||||
|
const event = useRequestEvent()
|
||||||
|
setResponseStatus(event, 404, 'Page Not Found')
|
||||||
|
</script>
|
||||||
|
|
@ -629,7 +629,7 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
const authStore = useAuthStore()
|
const authStore = useAuthStore()
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
middleware: ["self-hosted",]
|
middleware: ['root-redirect','self-hosted']
|
||||||
})
|
})
|
||||||
useOpnSeoMeta({
|
useOpnSeoMeta({
|
||||||
title: "Free AI form builder",
|
title: "Free AI form builder",
|
||||||
|
|
|
||||||
|
|
@ -323,6 +323,9 @@ export default {
|
||||||
defineRouteRules({
|
defineRouteRules({
|
||||||
swr: 3600,
|
swr: 3600,
|
||||||
})
|
})
|
||||||
|
definePageMeta({
|
||||||
|
middleware: ['root-redirect']
|
||||||
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
authenticated: computed(() => authStore.check),
|
authenticated: computed(() => authStore.check),
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ defineRouteRules({
|
||||||
})
|
})
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
stickyNavbar: true,
|
stickyNavbar: true,
|
||||||
middleware: ["self-hosted"]
|
middleware: ['root-redirect','self-hosted']
|
||||||
})
|
})
|
||||||
|
|
||||||
useOpnSeoMeta({
|
useOpnSeoMeta({
|
||||||
|
|
|
||||||
|
|
@ -174,7 +174,7 @@ defineRouteRules({
|
||||||
})
|
})
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
stickyNavbar: true,
|
stickyNavbar: true,
|
||||||
middleware: ["self-hosted"]
|
middleware: ['root-redirect','self-hosted']
|
||||||
})
|
})
|
||||||
|
|
||||||
const crisp = useCrisp()
|
const crisp = useCrisp()
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
import { useFeatureFlagsStore } from '~/stores/featureFlags'
|
import { useFeatureFlagsStore } from '~/stores/featureFlags'
|
||||||
|
|
||||||
export default defineNuxtRouteMiddleware(async () => {
|
export default defineNuxtPlugin(async () => {
|
||||||
const featureFlagsStore = useFeatureFlagsStore()
|
const featureFlagsStore = useFeatureFlagsStore()
|
||||||
|
|
||||||
// Load flags if they haven't been loaded yet
|
// Load flags if they haven't been loaded yet
|
||||||
if (!featureFlagsStore.isLoaded) {
|
if (!featureFlagsStore.isLoaded) {
|
||||||
await featureFlagsStore.fetchFlags()
|
await featureFlagsStore.fetchFlags()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
function parseNumber(value, defaultValue = 0) {
|
function parseNumber(value, defaultValue = 0) {
|
||||||
const parsedValue = parseFloat(value)
|
const parsedValue = parseFloat(value)
|
||||||
return isNaN(parsedValue) ? defaultValue : parsedValue
|
return isNaN(parsedValue) ? defaultValue : parsedValue
|
||||||
|
|
@ -15,6 +14,7 @@ export default {
|
||||||
gtmCode: process.env.NUXT_PUBLIC_GTM_CODE || null,
|
gtmCode: process.env.NUXT_PUBLIC_GTM_CODE || null,
|
||||||
amplitudeCode: process.env.NUXT_PUBLIC_AMPLITUDE_CODE || null,
|
amplitudeCode: process.env.NUXT_PUBLIC_AMPLITUDE_CODE || null,
|
||||||
crispWebsiteId: process.env.NUXT_PUBLIC_CRISP_WEBSITE_ID || null,
|
crispWebsiteId: process.env.NUXT_PUBLIC_CRISP_WEBSITE_ID || null,
|
||||||
|
rootRedirectUrl: process.env.NUXT_PUBLIC_ROOT_REDIRECT_URL || null,
|
||||||
|
|
||||||
featureBaseOrganization: process.env.NUXT_PUBLIC_FEATURE_BASE_ORGANISATION || null,
|
featureBaseOrganization: process.env.NUXT_PUBLIC_FEATURE_BASE_ORGANISATION || null,
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,26 +21,26 @@ There are dedicated configuration pages available for more detailed setup instru
|
||||||
|
|
||||||
### Configuration Environment Variables
|
### Configuration Environment Variables
|
||||||
|
|
||||||
| Variable Name | Description |
|
| Variable Name | Description |
|
||||||
| -------------------------- | --------------------------------------------- |
|
| --------------------------- | -------------------------------------------------------------------------------------------------------- |
|
||||||
| `JWT_TTL` | Time to live for JSON Web Tokens (JWT). |
|
| `JWT_TTL` | Time to live for JSON Web Tokens (JWT). |
|
||||||
| `JWT_SECRET` | Secret key used to sign JWTs. |
|
| `JWT_SECRET` | Secret key used to sign JWTs. |
|
||||||
| `H_CAPTCHA_SITE_KEY` | Site key for hCaptcha integration. |
|
| `H_CAPTCHA_SITE_KEY` | Site key for hCaptcha integration. |
|
||||||
| `H_CAPTCHA_SECRET_KEY` | Secret key for hCaptcha integration. |
|
| `H_CAPTCHA_SECRET_KEY` | Secret key for hCaptcha integration. |
|
||||||
| `RE_CAPTCHA_SITE_KEY` | Site key for reCAPTCHA integration. |
|
| `RE_CAPTCHA_SITE_KEY` | Site key for reCAPTCHA integration. |
|
||||||
| `RE_CAPTCHA_SECRET_KEY` | Secret key for reCAPTCHA integration. |
|
| `RE_CAPTCHA_SECRET_KEY` | Secret key for reCAPTCHA integration. |
|
||||||
| `OPEN_AI_API_KEY` | API key for accessing OpenAI services. |
|
| `OPEN_AI_API_KEY` | API key for accessing OpenAI services. |
|
||||||
| `UNSPLASH_ACCESS_KEY` | Access key for Unsplash API. |
|
| `UNSPLASH_ACCESS_KEY` | Access key for Unsplash API. |
|
||||||
| `UNSPLASH_SECRET_KEY` | Secret key for Unsplash API. |
|
| `UNSPLASH_SECRET_KEY` | Secret key for Unsplash API. |
|
||||||
| `GOOGLE_CLIENT_ID` | Client ID for Google OAuth. |
|
| `GOOGLE_CLIENT_ID` | Client ID for Google OAuth. |
|
||||||
| `GOOGLE_CLIENT_SECRET` | Client secret for Google OAuth. |
|
| `GOOGLE_CLIENT_SECRET` | Client secret for Google OAuth. |
|
||||||
| `GOOGLE_REDIRECT_URL` | Redirect URL for Google OAuth. |
|
| `GOOGLE_REDIRECT_URL` | Redirect URL for Google OAuth. |
|
||||||
| `GOOGLE_AUTH_REDIRECT_URL` | Authentication redirect URL for Google OAuth. |
|
| `GOOGLE_AUTH_REDIRECT_URL` | Authentication redirect URL for Google OAuth. |
|
||||||
| `GOOGLE_FONTS_API_KEY` | API key for accessing Google Fonts. |
|
| `GOOGLE_FONTS_API_KEY` | API key for accessing Google Fonts. |
|
||||||
| `FRONT_URL` | Public facing URL of the front-end. |
|
| `FRONT_URL` | Public facing URL of the front-end. |
|
||||||
| `FRONT_API_SECRET` | Shared secret with the front-end. |
|
| `FRONT_API_SECRET` | Shared secret with the front-end. |
|
||||||
| `TELEGRAM_BOT_ID` | ID of your Telegram bot for notifications. |
|
| `TELEGRAM_BOT_ID` | ID of your Telegram bot for notifications. |
|
||||||
| `TELEGRAM_BOT_TOKEN` | Authentication token for your Telegram bot. |
|
| `TELEGRAM_BOT_TOKEN` | Authentication token for your Telegram bot. |
|
||||||
| `JWT_SKIP_IP_UA_VALIDATION` | Set to `true` to disable JWT IP and User Agent validation (defaults to `false`). Useful for dynamic IPs. |
|
| `JWT_SKIP_IP_UA_VALIDATION` | Set to `true` to disable JWT IP and User Agent validation (defaults to `false`). Useful for dynamic IPs. |
|
||||||
|
|
||||||
### User Options Environment Variables
|
### User Options Environment Variables
|
||||||
|
|
@ -57,13 +57,14 @@ There are dedicated configuration pages available for more detailed setup instru
|
||||||
|
|
||||||
### Front-end Environment Variables
|
### Front-end Environment Variables
|
||||||
|
|
||||||
| Variable Name | Description |
|
| Variable Name | Description |
|
||||||
| --------------------------------- | ---------------------------------------------------- |
|
| --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `NUXT_PUBLIC_APP_URL` | Public facing URL of the Nuxt application. |
|
| `NUXT_PUBLIC_APP_URL` | Public facing URL of the Nuxt application. |
|
||||||
| `NUXT_PUBLIC_API_BASE` | Base URL for the Laravel API. |
|
| `NUXT_PUBLIC_API_BASE` | Base URL for the Laravel API. |
|
||||||
| `NUXT_PUBLIC_H_CAPTCHA_SITE_KEY` | Site key for hCaptcha integration on the front-end. |
|
| `NUXT_PUBLIC_H_CAPTCHA_SITE_KEY` | Site key for hCaptcha integration on the front-end. |
|
||||||
| `NUXT_PUBLIC_RE_CAPTCHA_SITE_KEY` | Site key for reCAPTCHA integration on the front-end. |
|
| `NUXT_PUBLIC_RE_CAPTCHA_SITE_KEY` | Site key for reCAPTCHA integration on the front-end. |
|
||||||
| `NUXT_API_SECRET` | Shared secret key between Nuxt and Laravel backend. |
|
| `NUXT_API_SECRET` | Shared secret key between Nuxt and Laravel backend. |
|
||||||
|
| `NUXT_PUBLIC_ROOT_REDIRECT_URL` | If set, permanently redirects users visiting the root path (/), /integrations, or any non-existent (404) page to the specified URL. Useful for self-hosted subdomains to avoid exposing the default landing page. |
|
||||||
|
|
||||||
import CloudVersion from "/snippets/cloud-version.mdx";
|
import CloudVersion from "/snippets/cloud-version.mdx";
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue