Improve Integration Cards (#643)
* Add integration action components and update integration JSON files - Introduced new action components for Email, Slack, Discord, Webhook, and Google Sheets integrations, enhancing the user interface for managing these integrations. - Updated the `integrations.json` files to include `actions_file_name` for each integration, linking them to their respective action components. - Improved the `GoogleSheetsIntegrationActions.vue` component by replacing direct provider information display with a badge for better UI consistency. These changes aim to streamline integration management and improve the overall user experience. * Minor UI fixes --------- Co-authored-by: Julien Nahum <julien@nahum.net>
This commit is contained in:
parent
49c2d6bf04
commit
c1ee072b71
|
|
@ -4,6 +4,7 @@
|
|||
"icon": "heroicons:envelope-20-solid",
|
||||
"section_name": "Notifications",
|
||||
"file_name": "EmailIntegration",
|
||||
"actions_file_name": "EmailIntegrationActions",
|
||||
"is_pro": false,
|
||||
"crisp_help_page_slug": "can-i-receive-notifications-on-form-submissions-134svqv"
|
||||
},
|
||||
|
|
@ -12,6 +13,7 @@
|
|||
"icon": "mdi:slack",
|
||||
"section_name": "Notifications",
|
||||
"file_name": "SlackIntegration",
|
||||
"actions_file_name": "SlackIntegrationActions",
|
||||
"is_pro": true
|
||||
},
|
||||
"discord": {
|
||||
|
|
@ -19,6 +21,7 @@
|
|||
"icon": "ic:baseline-discord",
|
||||
"section_name": "Notifications",
|
||||
"file_name": "DiscordIntegration",
|
||||
"actions_file_name": "DiscordIntegrationActions",
|
||||
"is_pro": true
|
||||
},
|
||||
"webhook": {
|
||||
|
|
@ -26,6 +29,7 @@
|
|||
"icon": "material-symbols:webhook",
|
||||
"section_name": "Automation",
|
||||
"file_name": "WebhookIntegration",
|
||||
"actions_file_name": "WebhookIntegrationActions",
|
||||
"is_pro": false
|
||||
},
|
||||
"zapier": {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
<template>
|
||||
<div class="flex flex-1 items-center">
|
||||
<div
|
||||
v-if="integration"
|
||||
class="hidden md:block space-y-1"
|
||||
>
|
||||
<UBadge
|
||||
:label="mentionAsText(integration.data.message)"
|
||||
color="gray"
|
||||
size="xs"
|
||||
class="max-w-[300px] truncate"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { mentionAsText } from '~/lib/utils.js'
|
||||
|
||||
const props = defineProps({
|
||||
integration: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
form: {
|
||||
type: Object,
|
||||
required: true,
|
||||
}
|
||||
})
|
||||
|
||||
const formIntegrationsStore = useFormIntegrationsStore()
|
||||
let interval = null
|
||||
|
||||
onMounted(() => {
|
||||
if (!props.integration.data || props.integration.data.length === 0) {
|
||||
interval = setInterval(() => formIntegrationsStore.fetchFormIntegrations(props.form.id), 3000)
|
||||
setTimeout(() => { clearInterval(interval) }, 30000)
|
||||
}
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (interval) {
|
||||
clearInterval(interval)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
<template>
|
||||
<div class="flex flex-1 items-center">
|
||||
<div
|
||||
v-if="integration"
|
||||
class="hidden md:block space-y-1"
|
||||
>
|
||||
<UBadge
|
||||
:label="mentionAsText(integration.data.subject)"
|
||||
color="gray"
|
||||
size="xs"
|
||||
class="max-w-[300px] block truncate"
|
||||
/>
|
||||
<div class="flex items-center gap-1">
|
||||
<UBadge
|
||||
:label="firstEmail"
|
||||
color="white"
|
||||
size="xs"
|
||||
class="max-w-[300px] block truncate"
|
||||
/>
|
||||
<UBadge
|
||||
v-if="additionalEmailsCount > 0"
|
||||
:label="`+${additionalEmailsCount}`"
|
||||
color="white"
|
||||
size="xs"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { mentionAsText } from '~/lib/utils.js'
|
||||
|
||||
const props = defineProps({
|
||||
integration: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
form: {
|
||||
type: Object,
|
||||
required: true,
|
||||
}
|
||||
})
|
||||
|
||||
const formIntegrationsStore = useFormIntegrationsStore()
|
||||
let interval = null
|
||||
|
||||
onMounted(() => {
|
||||
if (!props.integration.data || props.integration.data.length === 0) {
|
||||
interval = setInterval(() => formIntegrationsStore.fetchFormIntegrations(props.form.id), 3000)
|
||||
setTimeout(() => { clearInterval(interval) }, 30000)
|
||||
}
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (interval) {
|
||||
clearInterval(interval)
|
||||
}
|
||||
})
|
||||
|
||||
const firstEmail = computed(() => {
|
||||
const emails = mentionAsText(props.integration.data.send_to).split('\n').filter(Boolean)
|
||||
return emails[0] || ''
|
||||
})
|
||||
|
||||
const additionalEmailsCount = computed(() => {
|
||||
const emails = mentionAsText(props.integration.data.send_to).split('\n').filter(Boolean)
|
||||
return Math.max(0, emails.length - 1)
|
||||
})
|
||||
</script>
|
||||
|
|
@ -4,14 +4,12 @@
|
|||
v-if="integration.provider"
|
||||
class="hidden md:block space-y-1"
|
||||
>
|
||||
<div
|
||||
class="font-medium mr-2"
|
||||
>
|
||||
{{ integration.provider.name }}
|
||||
</div>
|
||||
<div class="text-sm">
|
||||
{{ integration.provider.email }}
|
||||
</div>
|
||||
<UBadge
|
||||
:label="mentionAsText(integration.provider.email)"
|
||||
color="gray"
|
||||
size="xs"
|
||||
class="max-w-[300px] truncate"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
|
|
@ -39,6 +37,8 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
import { mentionAsText } from '~/lib/utils.js'
|
||||
|
||||
const props = defineProps({
|
||||
integration: {
|
||||
type: Object,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
class="text-gray-500 border shadow rounded-md p-5 mt-4 relative flex items-center"
|
||||
>
|
||||
<div
|
||||
class="flex items-center"
|
||||
class="flex items-center w-full md:max-w-[240px]"
|
||||
:class="{'flex-grow': !actionsComponent}"
|
||||
>
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
<template>
|
||||
<div class="flex flex-1 items-center">
|
||||
<div
|
||||
v-if="integration"
|
||||
class="hidden md:block space-y-1"
|
||||
>
|
||||
<UBadge
|
||||
:label="mentionAsText(integration.data.message)"
|
||||
color="gray"
|
||||
size="xs"
|
||||
class="max-w-[300px] block truncate"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { mentionAsText } from '~/lib/utils.js'
|
||||
|
||||
const props = defineProps({
|
||||
integration: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
form: {
|
||||
type: Object,
|
||||
required: true,
|
||||
}
|
||||
})
|
||||
|
||||
const formIntegrationsStore = useFormIntegrationsStore()
|
||||
let interval = null
|
||||
|
||||
onMounted(() => {
|
||||
if (!props.integration.data || props.integration.data.length === 0) {
|
||||
interval = setInterval(() => formIntegrationsStore.fetchFormIntegrations(props.form.id), 3000)
|
||||
setTimeout(() => { clearInterval(interval) }, 30000)
|
||||
}
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (interval) {
|
||||
clearInterval(interval)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
<template>
|
||||
<div class="flex flex-1 items-center">
|
||||
<div
|
||||
v-if="integration"
|
||||
class="hidden md:block space-y-1"
|
||||
>
|
||||
<UBadge
|
||||
:label="integration.data.webhook_url"
|
||||
color="gray"
|
||||
size="xs"
|
||||
class="max-w-[300px] block truncate"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
integration: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
form: {
|
||||
type: Object,
|
||||
required: true,
|
||||
}
|
||||
})
|
||||
|
||||
const formIntegrationsStore = useFormIntegrationsStore()
|
||||
let interval = null
|
||||
|
||||
onMounted(() => {
|
||||
if (!props.integration.data || props.integration.data.length === 0) {
|
||||
interval = setInterval(() => formIntegrationsStore.fetchFormIntegrations(props.form.id), 3000)
|
||||
setTimeout(() => { clearInterval(interval) }, 30000)
|
||||
}
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (interval) {
|
||||
clearInterval(interval)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
"icon": "heroicons:envelope-20-solid",
|
||||
"section_name": "Notifications",
|
||||
"file_name": "EmailIntegration",
|
||||
"actions_file_name": "EmailIntegrationActions",
|
||||
"is_pro": false,
|
||||
"crisp_help_page_slug": "can-i-receive-notifications-on-form-submissions-134svqv"
|
||||
},
|
||||
|
|
@ -12,6 +13,7 @@
|
|||
"icon": "mdi:slack",
|
||||
"section_name": "Notifications",
|
||||
"file_name": "SlackIntegration",
|
||||
"actions_file_name": "SlackIntegrationActions",
|
||||
"is_pro": true
|
||||
},
|
||||
"discord": {
|
||||
|
|
@ -19,6 +21,7 @@
|
|||
"icon": "ic:baseline-discord",
|
||||
"section_name": "Notifications",
|
||||
"file_name": "DiscordIntegration",
|
||||
"actions_file_name": "DiscordIntegrationActions",
|
||||
"is_pro": true
|
||||
},
|
||||
"webhook": {
|
||||
|
|
@ -26,6 +29,7 @@
|
|||
"icon": "material-symbols:webhook",
|
||||
"section_name": "Automation",
|
||||
"file_name": "WebhookIntegration",
|
||||
"actions_file_name": "WebhookIntegrationActions",
|
||||
"is_pro": false
|
||||
},
|
||||
"zapier": {
|
||||
|
|
|
|||
|
|
@ -109,3 +109,15 @@ export const customDomainUsed = function () {
|
|||
|
||||
return host !== appDomain && getDomain(host) !== appDomain
|
||||
}
|
||||
|
||||
export const mentionAsText = (content) => {
|
||||
if (!content) return ''
|
||||
|
||||
// Parse the content and style mentions
|
||||
return content.replace(
|
||||
/<span\s+mention-field-id="([^"]+)"\s+mention-field-name="([^"]+)"[^>]*>([^<]+)<\/span>/g,
|
||||
(match, fieldId, fieldName, text) => {
|
||||
return `${text}`
|
||||
}
|
||||
)
|
||||
}
|
||||
Loading…
Reference in New Issue