Fix sentry tracked issues
This commit is contained in:
parent
ebdd06cbe6
commit
c97be832d7
|
@ -130,7 +130,7 @@ export default {
|
||||||
}) ?? null
|
}) ?? null
|
||||||
},
|
},
|
||||||
onInput (event) {
|
onInput (event) {
|
||||||
this.inputVal = event.target.value.replace(/[^0-9]/g, '')
|
this.inputVal = event?.target?.value.replace(/[^0-9]/g, '')
|
||||||
},
|
},
|
||||||
onChangeCountryCode () {
|
onChangeCountryCode () {
|
||||||
if (!this.selectedCountryCode && this.countries.length > 0) {
|
if (!this.selectedCountryCode && this.countries.length > 0) {
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<editor-options-panel name="Link Settings - SEO" :already-opened="false" :has-pro-tag="true">
|
<editor-options-panel name="Link Settings - SEO" :already-opened="false" :has-pro-tag="true">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
<svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
|
||||||
|
stroke="currentColor">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round"
|
<path stroke-linecap="round" stroke-linejoin="round"
|
||||||
d="M2.25 15.75l5.159-5.159a2.25 2.25 0 013.182 0l5.159 5.159m-1.5-1.5l1.409-1.409a2.25 2.25 0 013.182 0l2.909 2.909m-18 3.75h16.5a1.5 1.5 0 001.5-1.5V6a1.5 1.5 0 00-1.5-1.5H3.75A1.5 1.5 0 002.25 6v12a1.5 1.5 0 001.5 1.5zm10.5-11.25h.008v.008h-.008V8.25zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0z"
|
d="M2.25 15.75l5.159-5.159a2.25 2.25 0 013.182 0l5.159 5.159m-1.5-1.5l1.409-1.409a2.25 2.25 0 013.182 0l2.909 2.909m-18 3.75h16.5a1.5 1.5 0 001.5-1.5V6a1.5 1.5 0 00-1.5-1.5H3.75A1.5 1.5 0 002.25 6v12a1.5 1.5 0 001.5 1.5zm10.5-11.25h.008v.008h-.008V8.25zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0z"
|
||||||
/>
|
/>
|
||||||
|
@ -10,7 +11,8 @@
|
||||||
<p class="mt-4 text-gray-500 text-sm">
|
<p class="mt-4 text-gray-500 text-sm">
|
||||||
Customize the link, images and text that appear when you share your form on other sites (Open Graph).
|
Customize the link, images and text that appear when you share your form on other sites (Open Graph).
|
||||||
</p>
|
</p>
|
||||||
<select-input v-if="customDomainAllowed" v-model="form.custom_domain" :disabled="customDomainOptions.length <= 0" :options="customDomainOptions" name="type"
|
<select-input v-if="customDomainAllowed" v-model="form.custom_domain" :disabled="customDomainOptions.length <= 0"
|
||||||
|
:options="customDomainOptions" name="type"
|
||||||
class="mt-4" label="Form Domain" placeholder="yourdomain.com"
|
class="mt-4" label="Form Domain" placeholder="yourdomain.com"
|
||||||
/>
|
/>
|
||||||
<text-input v-model="form.seo_meta.page_title" name="page_title" class="mt-4"
|
<text-input v-model="form.seo_meta.page_title" name="page_title" class="mt-4"
|
||||||
|
@ -26,50 +28,49 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { useWorkingFormStore } from '../../../../../stores/working_form'
|
import {useWorkingFormStore} from '../../../../../stores/working_form'
|
||||||
import EditorOptionsPanel from '../../../editors/EditorOptionsPanel.vue'
|
import EditorOptionsPanel from '../../../editors/EditorOptionsPanel.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: { EditorOptionsPanel },
|
components: {EditorOptionsPanel},
|
||||||
props: {},
|
props: {},
|
||||||
setup () {
|
setup() {
|
||||||
const workingFormStore = useWorkingFormStore()
|
const workingFormStore = useWorkingFormStore()
|
||||||
return {
|
return {
|
||||||
workspacesStore: useWorkspacesStore(),
|
workspacesStore: useWorkspacesStore(),
|
||||||
workingFormStore
|
workingFormStore
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data () {
|
data() {
|
||||||
return {
|
return {}
|
||||||
}
|
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
form: {
|
form: {
|
||||||
get () {
|
get() {
|
||||||
return this.workingFormStore.content
|
return this.workingFormStore.content
|
||||||
},
|
},
|
||||||
/* We add a setter */
|
/* We add a setter */
|
||||||
set (value) {
|
set(value) {
|
||||||
this.workingFormStore.set(value)
|
this.workingFormStore.set(value)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
workspace () {
|
workspace() {
|
||||||
return this.workspacesStore.getCurrent
|
return this.workspacesStore.getCurrent
|
||||||
},
|
},
|
||||||
customDomainOptions () {
|
customDomainOptions() {
|
||||||
return this.workspace.custom_domains.map((domain) => {
|
return this.workspace.custom_domains ? this.workspace.custom_domains.map((domain) => {
|
||||||
return {
|
return {
|
||||||
name: domain,
|
name: domain,
|
||||||
value: domain
|
value: domain
|
||||||
}
|
}
|
||||||
})
|
}) : []
|
||||||
},
|
},
|
||||||
customDomainAllowed () {
|
customDomainAllowed() {
|
||||||
return useRuntimeConfig().public.customDomainsEnabled
|
return useRuntimeConfig().public.customDomainsEnabled
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {},
|
watch: {},
|
||||||
mounted () {
|
mounted() {
|
||||||
['page_title', 'page_description', 'page_thumbnail'].forEach((keyname) => {
|
['page_title', 'page_description', 'page_thumbnail'].forEach((keyname) => {
|
||||||
if (this.form.seo_meta[keyname] === undefined) {
|
if (this.form.seo_meta[keyname] === undefined) {
|
||||||
this.form.seo_meta[keyname] = null
|
this.form.seo_meta[keyname] = null
|
||||||
|
|
|
@ -38,14 +38,14 @@ export default {
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
parsedFiles() {
|
parsedFiles() {
|
||||||
return this.value.map((file) => {
|
return this.value ? this.value.map((file) => {
|
||||||
return {
|
return {
|
||||||
file_name: file.file_name,
|
file_name: file.file_name,
|
||||||
file_url: file.file_url,
|
file_url: file.file_url,
|
||||||
displayed_file_name: this.displayedFileName(file.file_name),
|
displayed_file_name: this.displayedFileName(file.file_name),
|
||||||
is_image: !this.failedImages.includes(file.file_url) && this.isImage(file.file_name)
|
is_image: !this.failedImages.includes(file.file_url) && this.isImage(file.file_name)
|
||||||
}
|
}
|
||||||
})
|
}): []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<forgot-password-modal :show="showForgotModal" @close="showForgotModal=false" />
|
<forgot-password-modal :show="showForgotModal" @close="showForgotModal=false"/>
|
||||||
|
|
||||||
<form class="mt-4" @submit.prevent="login" @keydown="form.onKeydown($event)">
|
<form class="mt-4" @submit.prevent="login" @keydown="form.onKeydown($event)">
|
||||||
<!-- Email -->
|
<!-- Email -->
|
||||||
<text-input name="email" :form="form" label="Email" :required="true" placeholder="Your email address" />
|
<text-input name="email" :form="form" label="Email" :required="true" placeholder="Your email address"/>
|
||||||
|
|
||||||
<!-- Password -->
|
<!-- Password -->
|
||||||
<text-input native-type="password" placeholder="Your password"
|
<text-input native-type="password" placeholder="Your password"
|
||||||
|
@ -18,7 +18,8 @@
|
||||||
</v-checkbox>
|
</v-checkbox>
|
||||||
|
|
||||||
<div class="w-full md:w-1/2 text-right">
|
<div class="w-full md:w-1/2 text-right">
|
||||||
<a href="#" class="text-xs hover:underline text-gray-500 sm:text-sm hover:text-gray-700" @click.prevent="showForgotModal=true">
|
<a href="#" class="text-xs hover:underline text-gray-500 sm:text-sm hover:text-gray-700"
|
||||||
|
@click.prevent="showForgotModal=true">
|
||||||
Forgot your password?
|
Forgot your password?
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -58,7 +59,7 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
setup () {
|
setup() {
|
||||||
return {
|
return {
|
||||||
authStore: useAuthStore(),
|
authStore: useAuthStore(),
|
||||||
formsStore: useFormsStore(),
|
formsStore: useFormsStore(),
|
||||||
|
@ -76,10 +77,9 @@ export default {
|
||||||
}),
|
}),
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
async login () {
|
login() {
|
||||||
// Submit the form.
|
// Submit the form.
|
||||||
const data = await this.form.post('login')
|
this.form.post('login').then(async (data) => {
|
||||||
|
|
||||||
// Save the token.
|
// Save the token.
|
||||||
this.authStore.setToken(data.token)
|
this.authStore.setToken(data.token)
|
||||||
|
|
||||||
|
@ -94,9 +94,12 @@ export default {
|
||||||
|
|
||||||
// Redirect home.
|
// Redirect home.
|
||||||
this.redirect()
|
this.redirect()
|
||||||
|
}).catch(() => {
|
||||||
|
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
redirect () {
|
redirect() {
|
||||||
if (this.isQuick) {
|
if (this.isQuick) {
|
||||||
this.$emit('afterQuickLogin')
|
this.$emit('afterQuickLogin')
|
||||||
return
|
return
|
||||||
|
@ -106,10 +109,10 @@ export default {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
if (intendedUrlCookie.value) {
|
if (intendedUrlCookie.value) {
|
||||||
router.push({ path: intendedUrlCookie.value })
|
router.push({path: intendedUrlCookie.value})
|
||||||
useCookie('intended_url').value = null
|
useCookie('intended_url').value = null
|
||||||
} else {
|
} else {
|
||||||
router.push({ name: 'home' })
|
router.push({name: 'home'})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,7 +103,7 @@ export default {
|
||||||
if (this.loadingNewLink) return
|
if (this.loadingNewLink) return
|
||||||
this.loadingNewLink = true
|
this.loadingNewLink = true
|
||||||
opnFetch(this.formEndpoint.replace('{id}', this.form.id) + '/regenerate-link/' + option, {method:'PUT'}).then((data) => {
|
opnFetch(this.formEndpoint.replace('{id}', this.form.id) + '/regenerate-link/' + option, {method:'PUT'}).then((data) => {
|
||||||
this.formsStore.addOrUpdate(data.form)
|
this.formsStore.save(data.form)
|
||||||
this.$router.push({name: 'forms-slug-show-share', params: {slug: data.form.slug}})
|
this.$router.push({name: 'forms-slug-show-share', params: {slug: data.form.slug}})
|
||||||
useAlert().success(data.message)
|
useAlert().success(data.message)
|
||||||
this.loadingNewLink = false
|
this.loadingNewLink = false
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
|
<div>
|
||||||
<NuxtLayout>
|
<NuxtLayout>
|
||||||
<div class="flex mt-6">
|
<div class="flex mt-6">
|
||||||
<div class="w-full md:w-2/3 md:mx-auto md:max-w-md">
|
<div class="w-full md:w-2/3 md:mx-auto md:max-w-md">
|
||||||
|
@ -16,6 +17,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</NuxtLayout>
|
</NuxtLayout>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
|
|
@ -8,99 +8,90 @@
|
||||||
{{ error }}
|
{{ error }}
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="text-center mt-4 py-6">
|
<div v-else class="text-center mt-4 py-6">
|
||||||
<Loader class="h-6 w-6 text-nt-blue mx-auto" />
|
<Loader class="h-6 w-6 text-nt-blue mx-auto"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
import { computed } from 'vue'
|
import {computed} from 'vue'
|
||||||
import Breadcrumb from '~/components/global/Breadcrumb.vue'
|
|
||||||
import FormEditor from "~/components/open/forms/components/FormEditor.vue";
|
import FormEditor from "~/components/open/forms/components/FormEditor.vue";
|
||||||
import {hash} from "~/lib/utils.js";
|
import {hash} from "~/lib/utils.js";
|
||||||
|
|
||||||
export default {
|
const formsStore = useFormsStore()
|
||||||
name: 'EditForm',
|
const workingFormStore = useWorkingFormStore()
|
||||||
components: { Breadcrumb, FormEditor },
|
const workspacesStore = useWorkspacesStore()
|
||||||
|
|
||||||
beforeRouteLeave (to, from, next) {
|
if (!formsStore.allLoaded) {
|
||||||
if (this.isDirty()) {
|
formsStore.startLoading()
|
||||||
|
}
|
||||||
|
const updatedForm = storeToRefs(workingFormStore).content
|
||||||
|
const form = computed(() => formsStore.getByKey(useRoute().params.slug))
|
||||||
|
const formsLoading = computed(() => formsStore.loading)
|
||||||
|
|
||||||
|
const error = ref(null)
|
||||||
|
const formInitialHash = ref(null)
|
||||||
|
|
||||||
|
function isDirty() {
|
||||||
|
return formInitialHash.value && updatedForm.value && formInitialHash.value !== hash(JSON.stringify(updatedForm.value.data() ?? null))
|
||||||
|
}
|
||||||
|
|
||||||
|
function initUpdatedForm() {
|
||||||
|
if (!form || !form.value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedForm.value = useForm(form.value)
|
||||||
|
if (!updatedForm.value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
formInitialHash.value = hash(JSON.stringify(updatedForm.value.data()))
|
||||||
|
|
||||||
|
if (updatedForm.value && (!updatedForm.value.notification_settings || Array.isArray(updatedForm.value.notification_settings))) {
|
||||||
|
updatedForm.value.notification_settings = {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a form.id watcher that updates working form
|
||||||
|
watch(form, (form) => {
|
||||||
|
if (form.value) {
|
||||||
|
initUpdatedForm()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
onBeforeRouteLeave((to, from, next) => {
|
||||||
|
if (isDirty()) {
|
||||||
return useAlert().confirm('Changes you made may not be saved. Are you sure want to leave?', () => {
|
return useAlert().confirm('Changes you made may not be saved. Are you sure want to leave?', () => {
|
||||||
window.onbeforeunload = null
|
window.onbeforeunload = null
|
||||||
next()
|
next()
|
||||||
}, () => {})
|
}, () => {
|
||||||
|
})
|
||||||
}
|
}
|
||||||
next()
|
next()
|
||||||
},
|
})
|
||||||
|
|
||||||
setup () {
|
onBeforeMount(() => {
|
||||||
const formsStore = useFormsStore()
|
if (process.client) {
|
||||||
const workingFormStore = useWorkingFormStore()
|
|
||||||
const workspacesStore = useWorkspacesStore()
|
|
||||||
|
|
||||||
if (!formsStore.allLoaded) {
|
|
||||||
formsStore.startLoading()
|
|
||||||
}
|
|
||||||
const updatedForm = storeToRefs(workingFormStore).content
|
|
||||||
const form = computed(() => formsStore.getByKey(useRoute().params.slug))
|
|
||||||
|
|
||||||
// Create a form.id watcher that updates working form
|
|
||||||
watch(form, (form) => {
|
|
||||||
if (form) {
|
|
||||||
updatedForm.value = useForm(form)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
useOpnSeoMeta({
|
|
||||||
title: 'Edit ' + ((form && form.value) ? form.value.title : 'Your Form')
|
|
||||||
})
|
|
||||||
definePageMeta({
|
|
||||||
middleware: "auth"
|
|
||||||
})
|
|
||||||
|
|
||||||
return {
|
|
||||||
formsStore,
|
|
||||||
workingFormStore,
|
|
||||||
workspacesStore,
|
|
||||||
updatedForm,
|
|
||||||
form,
|
|
||||||
formsLoading: computed(() => formsStore.loading),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
error: null,
|
|
||||||
formInitialHash: null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
},
|
|
||||||
|
|
||||||
async beforeMount() {
|
|
||||||
window.onbeforeunload = () => {
|
window.onbeforeunload = () => {
|
||||||
if (this.isDirty()) {
|
if (isDirty()) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.form && !this.formsStore.allLoaded) {
|
|
||||||
await this.formsStore.loadAll(this.workspacesStore.currentId)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updatedForm = useForm(this.form)
|
if (!form.value && !formsStore.allLoaded) {
|
||||||
this.formInitialHash = hash(JSON.stringify(this.updatedForm.data()))
|
formsStore.loadAll(workspacesStore.currentId).then(()=>{
|
||||||
|
initUpdatedForm()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
initUpdatedForm()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
if (this.updatedForm && (!this.updatedForm.notification_settings || Array.isArray(this.updatedForm.notification_settings))) {
|
useOpnSeoMeta({
|
||||||
this.updatedForm.notification_settings = {}
|
title: 'Edit ' + ((form && form.value) ? form.value.title : 'Your Form')
|
||||||
}
|
})
|
||||||
},
|
definePageMeta({
|
||||||
|
middleware: "auth"
|
||||||
methods: {
|
})
|
||||||
isDirty () {
|
|
||||||
return this.formInitialHash && this.formInitialHash !== hash(JSON.stringify(this.updatedForm.data()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -189,7 +189,7 @@ onMounted(() => {
|
||||||
|
|
||||||
watch(() => form?.value?.id, (id) => {
|
watch(() => form?.value?.id, (id) => {
|
||||||
if (id) {
|
if (id) {
|
||||||
workingFormStore.set(form)
|
workingFormStore.set(form.value)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -160,7 +160,7 @@ const saveChanges = () => {
|
||||||
.map(domain => domain ? domain.trim() : null)
|
.map(domain => domain ? domain.trim() : null)
|
||||||
.filter(domain => domain && domain.length > 0)
|
.filter(domain => domain && domain.length > 0)
|
||||||
}).then((data) => {
|
}).then((data) => {
|
||||||
workspacesStore.addOrUpdate(data)
|
workspacesStore.save(data)
|
||||||
useAlert().success('Custom domains saved.')
|
useAlert().success('Custom domains saved.')
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
useAlert().error('Failed to update custom domains: ' + error.response.data.message)
|
useAlert().error('Failed to update custom domains: ' + error.response.data.message)
|
||||||
|
|
|
@ -54,6 +54,14 @@ export default defineNuxtPlugin({
|
||||||
replaysOnErrorSampleRate: config.public.SENTRY_ERROR_REPLAY_SAMPLE_RATE,
|
replaysOnErrorSampleRate: config.public.SENTRY_ERROR_REPLAY_SAMPLE_RATE,
|
||||||
|
|
||||||
beforeSend(event) {
|
beforeSend(event) {
|
||||||
|
if (event.exception.values.length) {
|
||||||
|
// Don't send validation exceptions to Sentry
|
||||||
|
if (event.exception.values[0].type === 'FetchError' &&
|
||||||
|
event.exception.values[0].value.includes('422')
|
||||||
|
) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
return event;
|
return event;
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue