Remove appconfig in favor of runtimeconfig

This commit is contained in:
Julien Nahum 2024-01-03 17:38:11 +01:00
parent a51ccfebec
commit a6d88278be
18 changed files with 103 additions and 90 deletions

View File

@ -1,7 +0,0 @@
// https://nuxt.com/docs/guide/directory-structure/app-config
import opnformConfig from "~/opnform.config.js";
export default defineAppConfig({
...opnformConfig
})

View File

@ -3,7 +3,8 @@
<div class="max-w-7xl mx-auto px-8"> <div class="max-w-7xl mx-auto px-8">
<div class="flex items-center justify-between h-16"> <div class="flex items-center justify-between h-16">
<div class="flex items-center"> <div class="flex items-center">
<NuxtLink :to="{ name: user ? 'home' : 'index' }" class="flex-shrink-0 font-semibold hover:no-underline flex items-center"> <NuxtLink :to="{ name: user ? 'home' : 'index' }"
class="flex-shrink-0 font-semibold hover:no-underline flex items-center">
<img src="/img/logo.svg" alt="notion tools logo" class="w-8 h-8"> <img src="/img/logo.svg" alt="notion tools logo" class="w-8 h-8">
<span <span
@ -24,19 +25,23 @@
> >
AI Form Builder AI Form Builder
</NuxtLink> </NuxtLink>
<NuxtLink v-if="paidPlansEnabled && (user===null || (user && workspace && !workspace.is_pro)) && $route.name !== 'pricing'" :to="{name:'pricing'}" <NuxtLink
v-if="paidPlansEnabled && (user===null || (user && workspace && !workspace.is_pro)) && $route.name !== 'pricing'"
:to="{name:'pricing'}"
class="text-sm text-gray-600 dark:text-white hover:text-gray-800 cursor-pointer mt-1 mr-8" class="text-sm text-gray-600 dark:text-white hover:text-gray-800 cursor-pointer mt-1 mr-8"
> >
<span v-if="user">Upgrade</span> <span v-if="user">Upgrade</span>
<span v-else>Pricing</span> <span v-else>Pricing</span>
</NuxtLink> </NuxtLink>
<a v-if="hasCrisp" href="#" <a v-if="hasCrisp" href="#"
class="text-sm text-gray-600 dark:text-white hover:text-gray-800 cursor-pointer mt-1" @click.prevent="openCrisp" class="text-sm text-gray-600 dark:text-white hover:text-gray-800 cursor-pointer mt-1"
@click.prevent="openCrisp"
> >
Help Help
</a> </a>
<NuxtLink v-else :href="helpUrl" <NuxtLink v-else :href="helpUrl"
class="text-sm text-gray-600 dark:text-white hover:text-gray-800 cursor-pointer mt-1" target="_blank" class="text-sm text-gray-600 dark:text-white hover:text-gray-800 cursor-pointer mt-1"
target="_blank"
> >
Help Help
</NuxtLink> </NuxtLink>
@ -75,8 +80,10 @@
<NuxtLink v-if="userOnboarded" :to="{ name: 'templates-my-templates' }" <NuxtLink v-if="userOnboarded" :to="{ name: 'templates-my-templates' }"
class="block block px-4 py-2 text-md text-gray-700 hover:bg-gray-100 hover:text-gray-900 dark:text-gray-100 dark:hover:text-white dark:hover:bg-gray-600 flex items-center" class="block block px-4 py-2 text-md text-gray-700 hover:bg-gray-100 hover:text-gray-900 dark:text-gray-100 dark:hover:text-white dark:hover:bg-gray-600 flex items-center"
> >
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4 mr-2" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4 mr-2" fill="none" viewBox="0 0 24 24"
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z" /> stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round"
d="M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z"/>
</svg> </svg>
My Templates My Templates
</NuxtLink> </NuxtLink>
@ -119,7 +126,8 @@
Login Login
</NuxtLink> </NuxtLink>
<v-button v-track.nav_create_form_click size="small" :to="{ name: 'forms-create-guest' }" color="outline-blue" :arrow="true"> <v-button v-track.nav_create_form_click size="small" :to="{ name: 'forms-create-guest' }"
color="outline-blue" :arrow="true">
Create a form Create a form
</v-button> </v-button>
</div> </div>
@ -136,6 +144,7 @@
import {computed} from 'vue' import {computed} from 'vue'
import Dropdown from '~/components/global/Dropdown.vue' import Dropdown from '~/components/global/Dropdown.vue'
import WorkspaceDropdown from './WorkspaceDropdown.vue' import WorkspaceDropdown from './WorkspaceDropdown.vue'
import opnformConfig from "~/opnform.config.js";
export default { export default {
components: { components: {
@ -143,23 +152,26 @@ export default {
Dropdown Dropdown
}, },
setup () { async setup() {
const {openCrisp} = useCrisp() const {openCrisp} = useCrisp()
const authStore = useAuthStore() const authStore = useAuthStore()
return { return {
authStore, authStore,
openCrisp, openCrisp,
opnformConfig,
appStore: useAppStore(), appStore: useAppStore(),
formsStore: useFormsStore(), formsStore: useFormsStore(),
workspacesStore: useWorkspacesStore(), workspacesStore: useWorkspacesStore(),
config: useAppConfig(), config: useRuntimeConfig(),
user: computed(() => authStore.user), user: computed(() => authStore.user),
isIframe: useIsIframe(), isIframe: useIsIframe(),
} }
}, },
computed: { computed: {
helpUrl: () => this.config.links.help_url, helpUrl() {
return this.opnformConfig.links.help_url
},
form() { form() {
if (this.$route.name && this.$route.name.startsWith('forms.show_public')) { if (this.$route.name && this.$route.name.startsWith('forms.show_public')) {
return this.formsStore.getByKey(this.$route.params.slug) return this.formsStore.getByKey(this.$route.params.slug)
@ -170,7 +182,7 @@ export default {
return this.workspacesStore.getCurrent return this.workspacesStore.getCurrent
}, },
paidPlansEnabled() { paidPlansEnabled() {
return this.config.paid_plans_enabled return this.config.public.paidPlansEnabled
}, },
showAuth() { showAuth() {
return this.$route.name && !this.$route.name.startsWith('forms.show_public') return this.$route.name && !this.$route.name.startsWith('forms.show_public')
@ -194,7 +206,7 @@ export default {
return this.user && this.user.workspaces_count > 0 return this.user && this.user.workspaces_count > 0
}, },
hasCrisp() { hasCrisp() {
return this.config.crisp_website_id return this.config.crispWebsiteId
} }
}, },

View File

@ -124,7 +124,9 @@ export default {
}, },
computed: { computed: {
hCaptchaSiteKey: () => useAppConfig().hCaptchaSiteKey, hCaptchaSiteKey () {
return useRuntimeConfig().public.hCaptchaSiteKey
},
/** /**
* Create field groups (or Page) using page breaks if any * Create field groups (or Page) using page breaks if any
*/ */

View File

@ -96,6 +96,7 @@ import FormSecurityPrivacy from './form-components/FormSecurityPrivacy.vue'
import FormCustomSeo from './form-components/FormCustomSeo.vue' import FormCustomSeo from './form-components/FormCustomSeo.vue'
import FormAccess from './form-components/FormAccess.vue' import FormAccess from './form-components/FormAccess.vue'
import {validatePropertiesLogic} from "~/composables/forms/validatePropertiesLogic.js" import {validatePropertiesLogic} from "~/composables/forms/validatePropertiesLogic.js"
import opnformConfig from "~/opnform.config.js";
export default { export default {
name: 'FormEditor', name: 'FormEditor',
@ -145,10 +146,11 @@ export default {
appStore: useAppStore(), appStore: useAppStore(),
crisp: useCrisp(), crisp: useCrisp(),
amplitude: useAmplitude(), amplitude: useAmplitude(),
opnformConfig,
workspace, workspace,
formsStore, formsStore,
form, form,
user, user
} }
}, },
@ -200,7 +202,9 @@ export default {
} }
] ]
}, },
helpUrl: () => useAppConfig().links.help helpUrl () {
return this.opnformConfig.links.help
}
}, },
watch: {}, watch: {},

View File

@ -31,13 +31,13 @@
</template> </template>
<script> <script>
import { useWorkingFormStore } from '../../../../../stores/working_form'
import EditorOptionsPanel from '../../../editors/EditorOptionsPanel.vue' import EditorOptionsPanel from '../../../editors/EditorOptionsPanel.vue'
import FormNotificationsOption from './components/FormNotificationsOption.vue' import FormNotificationsOption from './components/FormNotificationsOption.vue'
import FormNotificationsSlack from './components/FormNotificationsSlack.vue' import FormNotificationsSlack from './components/FormNotificationsSlack.vue'
import FormNotificationsDiscord from './components/FormNotificationsDiscord.vue' import FormNotificationsDiscord from './components/FormNotificationsDiscord.vue'
import FormNotificationsSubmissionConfirmation from './components/FormNotificationsSubmissionConfirmation.vue' import FormNotificationsSubmissionConfirmation from './components/FormNotificationsSubmissionConfirmation.vue'
import FormNotificationsWebhook from './components/FormNotificationsWebhook.vue' import FormNotificationsWebhook from './components/FormNotificationsWebhook.vue'
import opnformConfig from "~/opnform.config.js";
export default { export default {
components: { FormNotificationsSubmissionConfirmation, FormNotificationsSlack, FormNotificationsDiscord, FormNotificationsOption, EditorOptionsPanel, FormNotificationsWebhook }, components: { FormNotificationsSubmissionConfirmation, FormNotificationsSlack, FormNotificationsDiscord, FormNotificationsOption, EditorOptionsPanel, FormNotificationsWebhook },
@ -47,22 +47,15 @@ export default {
const {content: form} = storeToRefs(workingFormStore) const {content: form} = storeToRefs(workingFormStore)
return { return {
workingFormStore, workingFormStore,
form form,
} opnformConfig
},
data () {
return {
} }
}, },
computed: { computed: {
zapierUrl: () => useAppConfig().links.zapier_integration zapierUrl () {
}, opnformConfig.links.zapier_integration
}
watch: {
},
mounted () {
}, },
} }
</script> </script>

View File

@ -91,14 +91,14 @@
</template> </template>
<script> <script>
export default { export default {
props: { props: {
show: { type: Boolean, required: true } show: { type: Boolean, required: true }
}, },
setup () { setup () {
return { return {
useAlert: useAlert() useAlert: useAlert(),
runtimeConfig: useRuntimeConfig()
} }
}, },
data: () => ({ data: () => ({
@ -111,7 +111,7 @@ export default {
computed: { computed: {
aiFeaturesEnabled () { aiFeaturesEnabled () {
return useAppConfig().ai_features_enabled return this.runtimeConfig.public.aiFeaturesEnabled
} }
}, },

View File

@ -1,10 +1,10 @@
import amplitude from 'amplitude-js' import amplitude from 'amplitude-js'
import config from '~/opnform.config.js'
export default () => { export const useAmplitude = () => {
const amplitudeClient = config.amplitude_code ? amplitude.getInstance() : null; const amplitudeCode = useRuntimeConfig().public.amplitudeCode
const amplitudeClient = amplitudeCode ? amplitude.getInstance() : null;
if (amplitudeClient) { if (amplitudeClient) {
amplitudeClient.init(config.amplitude_code) amplitudeClient.init(amplitudeCode)
} }
const logEvent = function (eventName, eventData) { const logEvent = function (eventName, eventData) {

View File

@ -1,4 +1,3 @@
import config from "~/opnform.config.js";
function addAuthHeader(request, options) { function addAuthHeader(request, options) {
const authStore = useAuthStore() const authStore = useAuthStore()
@ -24,8 +23,10 @@ export function getOpnRequestsOptions(request, opts) {
addAuthHeader(request, opts) addAuthHeader(request, opts)
addPasswordToFormRequest(request, opts) addPasswordToFormRequest(request, opts)
const config = useRuntimeConfig()
return { return {
baseURL: config.api_url, baseURL: config.public.apiBase,
onResponseError({response}) { onResponseError({response}) {
const authStore = useAuthStore() const authStore = useAuthStore()
const {status} = response const {status} = response

View File

@ -1,4 +1,5 @@
// https://nuxt.com/docs/api/configuration/nuxt-config // https://nuxt.com/docs/api/configuration/nuxt-config
import runtimeConfig from "./runtimeConfig";
import opnformConfig from "./opnform.config"; import opnformConfig from "./opnform.config";
import sitemap from "./sitemap"; import sitemap from "./sitemap";
@ -49,5 +50,6 @@ export default defineNuxtConfig({
}, },
'~/components', '~/components',
], ],
sitemap sitemap,
runtimeConfig
}) })

View File

@ -1,7 +1,6 @@
export default { export default {
"app_ame": "OpnForm", "app_ame": "OpnForm",
"app_url": "http://localhost:3000/",
"api_url": "https://opnform.test/api",
"locale": "en", "locale": "en",
"locales": {"en": "EN"}, "locales": {"en": "EN"},
"githubAuth": null, "githubAuth": null,
@ -18,14 +17,5 @@ export default {
"book_onboarding": "https://zcal.co/i/YQVGEULQ", "book_onboarding": "https://zcal.co/i/YQVGEULQ",
"feature_requests": "https://opnform.canny.io/feature-requests" "feature_requests": "https://opnform.canny.io/feature-requests"
}, },
"production": false, "production": false
"hCaptchaSiteKey": "4ee2dabb-4012-477e-8eb6-8017355f07cd",
"google_analytics_code": "",
"amplitude_code": "9952c8b914ce3f2bd494fce2dba18243",
"sentry_dsn": "https://f1829a9d456704e776eccc73e1b30369@o4504910866612224.ingest.sentry.io/4506014678646784",
"crisp_website_id": "94219d77-06ff-4aec-b07a-5bf26ec8fde1",
"ai_features_enabled": true,
"s3_enabled": false,
"paid_plans_enabled": true,
"custom_domains_enabled": false
} }

View File

@ -192,6 +192,7 @@ import AiFeature from '~/components/pages/welcome/AiFeature.vue'
import Testimonials from '../components/pages/welcome/Testimonials.vue' import Testimonials from '../components/pages/welcome/Testimonials.vue'
import TemplatesSlider from '../components/pages/welcome/TemplatesSlider.vue' import TemplatesSlider from '../components/pages/welcome/TemplatesSlider.vue'
import SeoMeta from '../mixins/seo-meta.js' import SeoMeta from '../mixins/seo-meta.js'
import opnformConfig from "~/opnform.config.js";
export default { export default {
components: {Testimonials, Features, MoreFeatures, PricingTable, AiFeature, TemplatesSlider}, components: {Testimonials, Features, MoreFeatures, PricingTable, AiFeature, TemplatesSlider},
@ -206,7 +207,8 @@ export default {
return { return {
authenticated: computed(() => authStore.check), authenticated: computed(() => authStore.check),
config: useAppConfig() config: opnformConfig,
runtimeConfig: useRuntimeConfig()
} }
}, },
@ -220,7 +222,7 @@ export default {
return this.config.links return this.config.links
}, },
paidPlansEnabled() { paidPlansEnabled() {
return this.config.paid_plans_enabled return this.runtimeConfig.public.paidPlansEnabled
}, },
} }
} }

View File

@ -249,7 +249,7 @@ export default {
middleware: [ middleware: [
function (to, from) { function (to, from) {
// Custom inline middleware // Custom inline middleware
if (!useAppConfig().paid_plans_enabled) { // If no paid plan so no need this page if (!useRuntimeConfig().public.paidPlansEnabled) { // If no paid plan so no need this page
return navigateTo('/', { redirectCode: 301 }) return navigateTo('/', { redirectCode: 301 })
} }
}, },

View File

@ -116,7 +116,6 @@
<script setup> <script setup>
import {watch} from "vue"; import {watch} from "vue";
import opnformConfig from "~/opnform.config.js";
import {fetchAllWorkspaces} from "~/stores/workspaces.js"; import {fetchAllWorkspaces} from "~/stores/workspaces.js";
const crisp = useCrisp() const crisp = useCrisp()
@ -133,7 +132,7 @@ let customDomains = ''
let customDomainsLoading = ref(false) let customDomainsLoading = ref(false)
let workspace = computed(() => workspacesStore.getCurrent) let workspace = computed(() => workspacesStore.getCurrent)
let customDomainsEnabled = computed(() => opnformConfig.custom_domains_enabled) let customDomainsEnabled = computed(() => useRuntimeConfig().public.customDomainsEnabled)
watch(() => workspace, () => { watch(() => workspace, () => {
initCustomDomains() initCustomDomains()

View File

@ -1,6 +1,4 @@
const {logEvent} = useAmplitude()
// Hook function used by event listener // Hook function used by event listener
function hookLogEvent (binding) { function hookLogEvent (binding) {
const modifiers = Object.keys(binding.modifiers) const modifiers = Object.keys(binding.modifiers)
@ -9,7 +7,7 @@ function hookLogEvent (binding) {
} }
const eventName = modifiers[0] const eventName = modifiers[0]
logEvent(eventName, binding.value) useAmplitude().logEvent(eventName, binding.value)
} }
export default defineNuxtPlugin(nuxtApp => { export default defineNuxtPlugin(nuxtApp => {

View File

@ -3,8 +3,9 @@ import config from "~/opnform.config.js";
export default defineNuxtPlugin(nuxtApp => { export default defineNuxtPlugin(nuxtApp => {
const isIframe = useIsIframe() const isIframe = useIsIframe()
if (config.crisp_website_id && !isIframe) { const crispWebsiteId = useRuntimeConfig().public.crispWebsiteId
Crisp.configure(config.crisp_website_id) if (crispWebsiteId && !isIframe) {
Crisp.configure(crispWebsiteId)
window.Crisp = Crisp window.Crisp = Crisp
} }
}); });

16
client/runtimeConfig.js vendored Normal file
View File

@ -0,0 +1,16 @@
export default {
// Keys within public, will be also exposed to the client-side
public: {
apiBase: '',
appUrl: '',
hCaptchaSiteKey: null,
googleAnalyticsCode: null,
amplitudeCode: null,
sentryDsn: null,
crispWebsiteId: null,
aiFeaturesEnabled: false,
s3Enabled: false,
paidPlansEnabled: false,
customDomainsEnabled: false
}
}

2
client/sitemap.js vendored
View File

@ -1,5 +1,5 @@
import opnformConfig from "./opnform.config.js";
import opnformConfig from "../opnform.config.js";
export default { export default {
// exclude all URLs that start with /secret // exclude all URLs that start with /secret
exclude: ['/settings/**', '/subscriptions/**', '/templates/my-templates'], exclude: ['/settings/**', '/subscriptions/**', '/templates/my-templates'],

View File

@ -1,6 +1,6 @@
import {defineStore} from 'pinia' import {defineStore} from 'pinia'
import {useContentStore} from "~/composables/stores/useContentStore.js"; import {useContentStore} from "~/composables/stores/useContentStore.js";
import opnformConfig from "~/opnform.config.js";
export const useNotionPagesStore = defineStore('notion_pages', () => { export const useNotionPagesStore = defineStore('notion_pages', () => {
const contentStore = useContentStore() const contentStore = useContentStore()
@ -8,7 +8,7 @@ export const useNotionPagesStore = defineStore('notion_pages', () => {
const load = (pageId) => { const load = (pageId) => {
contentStore.startLoading() contentStore.startLoading()
const apiUrl = useAppConfig().notion.worker const apiUrl = opnformConfig.notion.worker
return useOpnApi(`${apiUrl}/page/${pageId}`) return useOpnApi(`${apiUrl}/page/${pageId}`)
.then(({data})=> { .then(({data})=> {
const val = data.value const val = data.value