Merge branch 'main' into vue-3

This commit is contained in:
Forms Dev
2023-12-07 16:04:55 +05:30
42 changed files with 1371 additions and 188 deletions

View File

@@ -8,8 +8,11 @@
</svg>
</template>
<p class="mt-4 text-gray-500 text-sm">
Customize the image 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>
<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"
/>
<text-input v-model="form.seo_meta.page_title" name="page_title" class="mt-4"
label="Page Title" help="Under or approximately 60 characters"
/>
@@ -48,6 +51,20 @@ export default {
set (value) {
this.workingFormStore.set(value)
}
},
workspace () {
return this.$store.getters['open/workspaces/getCurrent']()
},
customDomainOptions () {
return this.workspace.custom_domains.map((domain) => {
return {
name: domain,
value: domain
}
})
},
customDomainAllowed () {
return window.config.custom_domains_enabled
}
},
watch: {},

View File

@@ -1,103 +1,116 @@
<template>
<div>
<div v-if="loadingDuplicate || loadingDelete" class="pr-4 pt-2">
<loader class="h-6 w-6 mx-auto"/>
<loader class="h-6 w-6 mx-auto" />
</div>
<dropdown v-else class="inline" dusk="nav-dropdown">
<template #trigger="{toggle}">
<v-button color="white" class="mr-2" @click="toggle">
<svg class="w-4 h-4 inline -mt-1" viewBox="0 0 16 4" fill="none"
xmlns="http://www.w3.org/2000/svg">
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M8.00016 2.83366C8.4604 2.83366 8.8335 2.46056 8.8335 2.00033C8.8335 1.54009 8.4604 1.16699 8.00016 1.16699C7.53993 1.16699 7.16683 1.54009 7.16683 2.00033C7.16683 2.46056 7.53993 2.83366 8.00016 2.83366Z"
stroke="#344054" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round"/>
d="M8.00016 2.83366C8.4604 2.83366 8.8335 2.46056 8.8335 2.00033C8.8335 1.54009 8.4604 1.16699 8.00016 1.16699C7.53993 1.16699 7.16683 1.54009 7.16683 2.00033C7.16683 2.46056 7.53993 2.83366 8.00016 2.83366Z"
stroke="#344054" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round"
/>
<path
d="M13.8335 2.83366C14.2937 2.83366 14.6668 2.46056 14.6668 2.00033C14.6668 1.54009 14.2937 1.16699 13.8335 1.16699C13.3733 1.16699 13.0002 1.54009 13.0002 2.00033C13.0002 2.46056 13.3733 2.83366 13.8335 2.83366Z"
stroke="#344054" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round"/>
d="M13.8335 2.83366C14.2937 2.83366 14.6668 2.46056 14.6668 2.00033C14.6668 1.54009 14.2937 1.16699 13.8335 1.16699C13.3733 1.16699 13.0002 1.54009 13.0002 2.00033C13.0002 2.46056 13.3733 2.83366 13.8335 2.83366Z"
stroke="#344054" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round"
/>
<path
d="M2.16683 2.83366C2.62707 2.83366 3.00016 2.46056 3.00016 2.00033C3.00016 1.54009 2.62707 1.16699 2.16683 1.16699C1.70659 1.16699 1.3335 1.54009 1.3335 2.00033C1.3335 2.46056 1.70659 2.83366 2.16683 2.83366Z"
stroke="#344054" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round"/>
d="M2.16683 2.83366C2.62707 2.83366 3.00016 2.46056 3.00016 2.00033C3.00016 1.54009 2.62707 1.16699 2.16683 1.16699C1.70659 1.16699 1.3335 1.54009 1.3335 2.00033C1.3335 2.46056 1.70659 2.83366 2.16683 2.83366Z"
stroke="#344054" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round"
/>
</svg>
</v-button>
</template>
<router-link v-if="isMainPage && user" :to="{name:'forms.show_public', params: {slug: form.slug}}" target="_blank"
class="block px-4 py-2 text-md text-gray-700 dark:text-white hover:bg-gray-100 hover:text-gray-900 dark:text-gray-100 dark:hover:text-white dark:hover:bg-gray-600 flex items-center"
v-track.view_form_click="{form_id:form.id, form_slug:form.slug}"
>
<a v-if="isMainPage && user" v-track.view_form_click="{form_id:form.id, form_slug:form.slug}" :href="form.share_url"
target="_blank"
class="block px-4 py-2 text-md text-gray-700 dark:text-white 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 class="w-4 h-4 mr-2" viewBox="0 0 24 24" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path d="M1 12C1 12 5 4 12 4C19 4 23 12 23 12C23 12 19 20 12 20C5 20 1 12 1 12Z"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path
xmlns="http://www.w3.org/2000/svg"
>
<path d="M1 12C1 12 5 4 12 4C19 4 23 12 23 12C23 12 19 20 12 20C5 20 1 12 1 12Z"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
/>
<path
d="M12 15C13.6569 15 15 13.6569 15 12C15 10.3431 13.6569 9 12 9C10.3431 9 9 10.3431 9 12C9 13.6569 10.3431 15 12 15Z"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
/>
</svg>
View form
</router-link>
<router-link v-if="isMainPage" :to="{name:'forms.edit', params: {slug: form.slug}}"
class="block block px-4 py-2 text-md text-gray-700 dark:text-white hover:bg-gray-100 hover:text-gray-900 dark:text-gray-100 dark:hover:text-white dark:hover:bg-gray-600 flex items-center"
v-track.edit_form_click="{form_id:form.id, form_slug:form.slug}"
>
</a>
<router-link v-if="isMainPage" v-track.edit_form_click="{form_id:form.id, form_slug:form.slug}"
:to="{name:'forms.edit', params: {slug: form.slug}}"
class="block block px-4 py-2 text-md text-gray-700 dark:text-white 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 class="w-4 h-4 mr-2" width="18" height="17" viewBox="0 0 18 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M8.99998 15.6662H16.5M1.5 15.6662H2.89545C3.3031 15.6662 3.50693 15.6662 3.69874 15.6202C3.8688 15.5793 4.03138 15.512 4.1805 15.4206C4.34869 15.3175 4.49282 15.1734 4.78107 14.8852L15.25 4.4162C15.9404 3.72585 15.9404 2.60656 15.25 1.9162C14.5597 1.22585 13.4404 1.22585 12.75 1.9162L2.28105 12.3852C1.9928 12.6734 1.84867 12.8175 1.7456 12.9857C1.65422 13.1348 1.58688 13.2974 1.54605 13.4675C1.5 13.6593 1.5 13.8631 1.5 14.2708V15.6662Z"
stroke="currentColor" stroke-width="1.67" stroke-linecap="round" stroke-linejoin="round"/>
stroke="currentColor" stroke-width="1.67" stroke-linecap="round" stroke-linejoin="round"
/>
</svg>
Edit
</router-link>
<a href="#" v-if="isMainPage"
class="block block px-4 py-2 text-md text-gray-700 dark:text-white hover:bg-gray-100 hover:text-gray-900 dark:text-gray-100 dark:hover:text-white dark:hover:bg-gray-600 flex items-center"
@click.prevent="copyLink"
>
<a v-if="isMainPage" href="#"
class="block block px-4 py-2 text-md text-gray-700 dark:text-white hover:bg-gray-100 hover:text-gray-900 dark:text-gray-100 dark:hover:text-white dark:hover:bg-gray-600 flex items-center"
@click.prevent="copyLink"
>
<svg class="w-4 h-4 mr-2" viewBox="0 0 16 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.00016 8.33317H4.66683C2.82588 8.33317 1.3335 6.84079 1.3335 4.99984C1.3335 3.15889 2.82588 1.6665 4.66683 1.6665H6.00016M10.0002 8.33317H11.3335C13.1744 8.33317 14.6668 6.84079 14.6668 4.99984C14.6668 3.15889 13.1744 1.6665 11.3335 1.6665H10.0002M4.66683 4.99984L11.3335 4.99984" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6.00016 8.33317H4.66683C2.82588 8.33317 1.3335 6.84079 1.3335 4.99984C1.3335 3.15889 2.82588 1.6665 4.66683 1.6665H6.00016M10.0002 8.33317H11.3335C13.1744 8.33317 14.6668 6.84079 14.6668 4.99984C14.6668 3.15889 13.1744 1.6665 11.3335 1.6665H10.0002M4.66683 4.99984L11.3335 4.99984" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
</svg>
Copy link to share
</a>
<a href="#"
class="block block px-4 py-2 text-md text-gray-700 dark:text-white hover:bg-gray-100 hover:text-gray-900 dark:text-gray-100 dark:hover:text-white dark:hover:bg-gray-600 flex items-center"
v-track.duplicate_form_click="{form_id:form.id, form_slug:form.slug}"
@click.prevent="duplicateForm"
>
<a v-track.duplicate_form_click="{form_id:form.id, form_slug:form.slug}"
href="#"
class="block block px-4 py-2 text-md text-gray-700 dark:text-white hover:bg-gray-100 hover:text-gray-900 dark:text-gray-100 dark:hover:text-white dark:hover:bg-gray-600 flex items-center"
@click.prevent="duplicateForm"
>
<svg class="w-4 h-4 mr-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
stroke="currentColor"
>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M8 7v8a2 2 0 002 2h6M8 7V5a2 2 0 012-2h4.586a1 1 0 01.707.293l4.414 4.414a1 1 0 01.293.707V15a2 2 0 01-2 2h-2M8 7H6a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2v-2"
/>
/>
</svg>
Duplicate form
</a>
<a href="#" v-if="!isMainPage" v-track.create_template_click="{form_id:form.id, form_slug:form.slug}"
<a v-if="!isMainPage" v-track.create_template_click="{form_id:form.id, form_slug:form.slug}" href="#"
class="block block px-4 py-2 text-md text-gray-700 dark:text-white hover:bg-gray-100 hover:text-gray-900 dark:text-gray-100 dark:hover:text-white dark:hover:bg-gray-600 flex items-center"
@click.prevent="showFormTemplateModal=true"
>
<svg class="w-4 h-4 mr-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke="currentColor" stroke-width="2">
stroke="currentColor" stroke-width="2"
>
<path stroke-linecap="round" stroke-linejoin="round"
d="M17 14v6m-3-3h6M6 10h2a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v2a2 2 0 002 2zm10 0h2a2 2 0 002-2V6a2 2 0 00-2-2h-2a2 2 0 00-2 2v2a2 2 0 002 2zM6 20h2a2 2 0 002-2v-2a2 2 0 00-2-2H6a2 2 0 00-2 2v2a2 2 0 002 2z"/>
d="M17 14v6m-3-3h6M6 10h2a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v2a2 2 0 002 2zm10 0h2a2 2 0 002-2V6a2 2 0 00-2-2h-2a2 2 0 00-2 2v2a2 2 0 002 2zM6 20h2a2 2 0 002-2v-2a2 2 0 00-2-2H6a2 2 0 00-2 2v2a2 2 0 002 2z"
/>
</svg>
Create Template
</a>
<a href="#"
class="block block px-4 py-2 text-md text-red-600 hover:bg-red-50 flex items-center"
v-track.delete_form_click="{form_id:form.id, form_slug:form.slug}"
@click.prevent="showDeleteFormModal=true"
>
<a v-track.delete_form_click="{form_id:form.id, form_slug:form.slug}"
href="#"
class="block block px-4 py-2 text-md text-red-600 hover:bg-red-50 flex items-center"
@click.prevent="showDeleteFormModal=true"
>
<svg class="w-4 h-4 mr-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
stroke="currentColor"
>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
/>
/>
</svg>
Delete form
</a>
</dropdown>
<!-- Delete Form Modal -->
<modal :show="showDeleteFormModal" icon-color="red" @close="showDeleteFormModal=false" max-width="sm">
<modal :show="showDeleteFormModal" icon-color="red" max-width="sm" @close="showDeleteFormModal=false">
<template #icon>
<svg class="w-10 h-10" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
stroke="currentColor"
>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
/>
@@ -111,13 +124,17 @@
If you want to permanently delete this form and all of its data, you can do so below.
</p>
<div class="flex mt-4">
<v-button class="sm:w-1/2 mr-4" color="white" @click.prevent="showDeleteFormModal=false">Cancel</v-button>
<v-button class="sm:w-1/2" color="red" :loading="loadingDelete" @click.prevent="deleteForm">Yes, delete it</v-button>
<v-button class="sm:w-1/2 mr-4" color="white" @click.prevent="showDeleteFormModal=false">
Cancel
</v-button>
<v-button class="sm:w-1/2" color="red" :loading="loadingDelete" @click.prevent="deleteForm">
Yes, delete it
</v-button>
</div>
</div>
</modal>
<form-template-modal v-if="!isMainPage && user" :form="form" :show="showFormTemplateModal" @close="showFormTemplateModal=false"/>
<form-template-modal v-if="!isMainPage && user" :form="form" :show="showFormTemplateModal" @close="showFormTemplateModal=false" />
</div>
</template>
@@ -146,12 +163,12 @@ export default {
}
},
data: () => ({
loadingDuplicate: false,
loadingDelete: false,
showDeleteFormModal: false,
showFormTemplateModal: false
}),
data: () => ({
loadingDuplicate: false,
loadingDelete: false,
showDeleteFormModal: false,
showFormTemplateModal: false
}),
computed: {
formEndpoint: () => '/api/open/forms/{id}',

View File

@@ -3,8 +3,12 @@
<div class="w-full">
<div class="rounded-lg bg-gray-50 dark:bg-gray-800 px-6 py-8 sm:p-10 lg:flex lg:items-center">
<div class="flex-1">
<h3 class="inline-flex px-4 py-1 rounded-full text-md font-bold tracking-wide uppercase bg-white text-gray-800">Custom plan</h3>
<div class="mt-4 text-md text-gray-600 dark:text-gray-400">Get a custom file upload limit, enterprise-level support, custom contract, payment via invoice/PO etc.</div>
<h3 class="inline-flex px-4 py-1 rounded-full text-md font-bold tracking-wide uppercase bg-white text-gray-800">
Custom plan
</h3>
<div class="mt-4 text-md text-gray-600 dark:text-gray-400">
Get a custom file upload limit, enterprise-level support, custom contract, dedicated application instance in a specific region, payment via invoice/PO etc.
</div>
</div>
<div class="mt-6 rounded-md lg:mt-0 lg:ml-10 lg:flex-shrink-0">
<v-button color="white" class="w-full mt-4" @click.prevent="customPlanClick">

View File

@@ -145,7 +145,7 @@ export default {
'Slack notifications',
'Discord notifications',
'Editable submissions',
'Custom domain (soon)',
'1 Custom domain',
'Custom code',
'Larger file uploads (50mb)',
'Remove OpnForm branding',

View File

@@ -0,0 +1,16 @@
export default async (to, from, next) => {
if (!window.config.custom_domains_enabled) {
next()
}
const isCustomDomain = getDomain(window.location.href) !== getDomain(window.config.app_url)
if (isCustomDomain && !['forms.show_public'].includes(to.name)) {
// If route isn't a public form, redirect
window.location.href = 'https://opnform.com/?utm_source=failed_custom_domain_redirect'
} else {
next()
}
}
function getDomain (url) {
return (new URL(url)).hostname
}

View File

@@ -52,5 +52,13 @@ export default {
return this.content
}
}
},
watch: {
value (val) {
if (val !== this.compVal) {
this.compVal = val
}
}
}
}

View File

@@ -23,7 +23,7 @@
<extra-menu :form="form" />
<v-button v-track.view_form_click="{form_id:form.id, form_slug:form.slug}" target="_blank"
:to="{name:'forms.show_public', params: {slug: form.slug}}" color="white"
:href="form.share_url" color="white"
class="mr-2 text-blue-600 hidden sm:block"
>
<svg class="w-6 h-6 inline -mt-1" viewBox="0 0 24 24" fill="none"
@@ -210,7 +210,7 @@ export default {
computed: {
workingForm: {
get () {
get () {
return this.workingFormStore.content
},
/* We add a setter */

View File

@@ -1,50 +1,92 @@
<template>
<div>
<h3 class="font-semibold text-2xl text-gray-900">Workspace settings</h3>
<small class="text-gray-600">Manage your workspaces.</small>
<div v-if="loading" class="w-full text-blue-500 text-center">
<loader class="h-10 w-10 p-5"/>
</div>
<div v-else>
<div v-for="workspace in workspaces" :key="workspace.id"
class="mt-4 p-4 flex group bg-white hover:bg-gray-50 dark:bg-notion-dark items-center"
>
<div class="flex space-x-4 flex-grow items-center cursor-pointer" role="button" @click.prevent="switchWorkspace(workspace)">
<img v-if="isUrl(workspace.icon)" :src="workspace.icon" :alt="workspace.name + ' icon'"
class="rounded-full h-12 w-12"
>
<div v-else class="rounded-2xl bg-gray-100 h-12 w-12 text-2xl pt-2 text-center overflow-hidden"
v-text="workspace.icon"
/>
<div class="space-y-4 py-1">
<div class="font-bold truncate">{{workspace.name}}</div>
</div>
</div>
<div v-if="workspaces.length > 1"
class="block md:hidden group-hover:block text-red-500 p-2 rounded hover:bg-red-50" role="button"
@click="deleteWorkspace(workspace)">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/>
</svg>
</div>
<div class="flex flex-wrap items-center gap-y-4 flex-wrap-reverse">
<div class="flex-grow">
<h3 class="font-semibold text-2xl text-gray-900">
Workspace settings
</h3>
<small class="text-gray-600">Manage your workspaces.</small>
</div>
<v-button :loading="loading" class="mt-4" @click="workspaceModal=true">
<svg class="inline text-white mr-1 h-4 w-4" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.99996 1.16699V12.8337M1.16663 7.00033H12.8333" stroke="currentColor" stroke-width="1.67" stroke-linecap="round" stroke-linejoin="round"/>
<v-button color="outline-blue" :loading="loading" @click="workspaceModal=true">
<svg class="inline -mt-1 mr-1 h-4 w-4" viewBox="0 0 14 14" fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M6.99996 1.16699V12.8337M1.16663 7.00033H12.8333" stroke="currentColor" stroke-width="1.67"
stroke-linecap="round" stroke-linejoin="round"
/>
</svg>
Create new workspace
</v-button>
</div>
<div v-if="loading" class="w-full text-blue-500 text-center">
<loader class="h-10 w-10 p-5" />
</div>
<div v-else-if="workspace">
<div class="mt-4 flex group bg-white items-center">
<div class="flex space-x-4 flex-grow items-center">
<img v-if="isUrl(workspace.icon)" :src="workspace.icon" :alt="workspace.name + ' icon'"
class="rounded-full h-12 w-12"
>
<div v-else class="rounded-2xl bg-gray-100 h-12 w-12 text-2xl pt-2 text-center overflow-hidden"
v-text="workspace.icon"
/>
<div class="space-y-4 py-1">
<div class="font-bold truncate">
{{ workspace.name }}
</div>
</div>
</div>
</div>
<template v-if="customDomainsEnabled">
<text-area-input v-model="customDomains" name="custom_domain" class="mt-4" :required="false"
:disabled="!workspace.is_pro"
label="Workspace Custom Domains" wrapper-class="" placeholder="yourdomain.com - 1 per line"
/>
<p class="text-gray-500 text-sm">
Read our <a href="#"
@click.prevent="$crisp.push(['do', 'helpdesk:article:open', ['en', 'how-to-use-my-own-domain-9m77g7']])"
>custom
domain instructions</a> to learn how to use your own domain.
</p>
</template>
<div class="flex flex-wrap justify-between gap-2 mt-4">
<v-button v-if="customDomainsEnabled" class="w-full sm:w-auto" :loading="customDomainsLoading" @click="saveChanges">
<svg class="w-4 h-4 text-white inline mr-1 -mt-1" viewBox="0 0 24 24" fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M17 21V13H7V21M7 3V8H15M19 21H5C4.46957 21 3.96086 20.7893 3.58579 20.4142C3.21071 20.0391 3 19.5304 3 19V5C3 4.46957 3.21071 3.96086 3.58579 3.58579C3.96086 3.21071 4.46957 3 5 3H16L21 8V19C21 19.5304 20.7893 20.0391 20.4142 20.4142C20.0391 20.7893 19.5304 21 19 21Z"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
/>
</svg>
Save Domains
</v-button>
<v-button v-if="workspaces.length > 1" color="white" class="group w-full sm:w-auto" :loading="loading"
@click="deleteWorkspace(workspace)"
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 -mt-1 inline group-hover:text-red-700" fill="none"
viewBox="0 0 24 24" stroke="currentColor"
>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
/>
</svg>
Remove workspace
</v-button>
</div>
</div>
<!-- Workspace modal -->
<modal :show="workspaceModal" @close="workspaceModal=false" max-width="lg">
<modal :show="workspaceModal" max-width="lg" @close="workspaceModal=false">
<template #icon>
<svg class="w-8 h-8" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M12 8V16M8 12H16M22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12Z"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
/>
</svg>
</template>
<template #title>
@@ -62,13 +104,13 @@
</div>
<div class="w-full mt-6">
<v-button :loading="form.busy" class="w-full my-3">Save</v-button>
<v-button :loading="form.busy" class="w-full my-3">
Save
</v-button>
</div>
</form>
</div>
</modal>
</div>
</template>
@@ -78,9 +120,13 @@ import Form from 'vform'
import { useFormsStore } from '../../stores/forms'
import { useWorkspacesStore } from '../../stores/workspaces'
import SeoMeta from '../../mixins/seo-meta.js'
import TextAreaInput from '../../components/forms/TextAreaInput.vue'
import axios from 'axios'
import * as domain from 'domain'
export default {
components: {},
components: { TextAreaInput },
mixins: [SeoMeta],
scrollToTop: false,
mixins: [SeoMeta],
@@ -101,29 +147,59 @@ export default {
name: '',
emoji: ''
}),
workspaceModal: false
workspaceModal: false,
customDomains: '',
customDomainsLoading: false
}),
mounted() {
mounted () {
this.workspacesStore.loadIfEmpty()
this.initCustomDomains()
},
computed: {},
computed: {
workspace () {
return this.workspacesStore.getCurrent()
},
customDomainsEnabled () {
return window.config.custom_domains_enabled
}
},
methods: {
switchWorkspace(workspace) {
this.workspacesStore.setCurrentId(workspace.id)
this.$router.push({name: 'home'})
this.formsStore.load(workspace.id)
saveChanges () {
if (this.customDomainsLoading) return
this.customDomainsLoading = true
// Update the workspace custom domain
axios.put('/api/open/workspaces/' + this.workspace.id + '/custom-domains', {
custom_domains: this.customDomains.split('\n')
.map(domain => domain.trim())
.filter(domain => domain && domain.length > 0)
}).then((response) => {
this.workspacesStore.addOrUpdate(response.data)
this.alertSuccess('Custom domains saved.')
}).catch((error) => {
this.alertError('Failed to update custom domains: ' + error.response.data.message)
}).finally(() => {
this.customDomainsLoading = false
})
},
deleteWorkspace(workspace) {
initCustomDomains () {
if (!this.workspace) return
this.customDomains = this.workspace.custom_domains.join('\n')
},
deleteWorkspace (workspace) {
if (this.workspaces.length <= 1) {
this.alertError('You cannot delete your only workspace.')
return
}
this.alertConfirm('Do you really want to delete this workspace? All forms created in this workspace will be removed.', () => {
this.workspacesStore.delete(workspace.id).then(() => {
this.alertSuccess('Workspace successfully removed.')
})
})
},
isUrl(str) {
isUrl (str) {
const pattern = new RegExp('^(https?:\\/\\/)?' + // protocol
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name
'((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address
@@ -137,6 +213,12 @@ export default {
this.workspacesStore.load()
this.workspaceModal = false
}
},
watch: {
workspace () {
this.initCustomDomains()
}
}
}
</script>

View File

@@ -5,7 +5,7 @@ import { useAppStore } from '../stores/app'
import { defineComponent, nextTick } from 'vue'
// The middleware for every page of the application.
const globalMiddleware = ['check-auth', 'notion-connection']
const globalMiddleware = ['locale', 'check-auth', 'custom-domains']
// Load middleware modules dynamically.
const requireContext = import.meta.glob('../middleware/**/*.js', { eager: true })

View File

@@ -57,6 +57,10 @@ export const useWorkspacesStore = defineStore('workspaces', {
},
remove (itemId) {
this.content = this.content.filter((val) => val.id !== itemId)
if (this.currentId === itemId) {
this.currentId = this.content.length > 0 ? this.content[0].id : null
localStorage.setItem(localStorageCurrentWorkspaceKey, this.currentId)
}
},
startLoading () {
this.loading = true

View File

@@ -1,6 +1,7 @@
@php
$config = [
'appName' => config('app.name'),
'app_url' => config('app.url'),
'locale' => $locale = app()->getLocale(),
'locales' => config('app.locales'),
'githubAuth' => config('services.github.client_id'),
@@ -16,7 +17,8 @@
'crisp_website_id' => config('services.crisp_website_id'),
'ai_features_enabled' => !is_null(config('services.openai.api_key')),
's3_enabled' => config('filesystems.default') === 's3',
'paid_plans_enabled' => !is_null(config('cashier.key'))
'paid_plans_enabled' => !is_null(config('cashier.key')),
'custom_domains_enabled' => config('custom-domains.enabled'),
];
@endphp
<!DOCTYPE html>