mirror of
https://github.com/simstudioai/sim.git
synced 2026-04-28 03:00:29 -04:00
fix(webflow): fix collection & site dropdown in webflow triggers (#2849)
* fix(webflow): fix collection & site dropdown in webflow triggers * added form submission trigger to webflow * fix(webflow): added form submission trigger and scope * fixed function signatures
This commit is contained in:
@@ -127,6 +127,7 @@ export const WebflowBlock: BlockConfig<WebflowResponse> = {
|
||||
...getTrigger('webflow_collection_item_created').subBlocks,
|
||||
...getTrigger('webflow_collection_item_changed').subBlocks,
|
||||
...getTrigger('webflow_collection_item_deleted').subBlocks,
|
||||
...getTrigger('webflow_form_submission').subBlocks,
|
||||
],
|
||||
tools: {
|
||||
access: [
|
||||
|
||||
@@ -1858,7 +1858,7 @@ export const auth = betterAuth({
|
||||
authorizationUrl: 'https://webflow.com/oauth/authorize',
|
||||
tokenUrl: 'https://api.webflow.com/oauth/access_token',
|
||||
userInfoUrl: 'https://api.webflow.com/v2/token/introspect',
|
||||
scopes: ['sites:read', 'sites:write', 'cms:read', 'cms:write'],
|
||||
scopes: ['sites:read', 'sites:write', 'cms:read', 'cms:write', 'forms:read'],
|
||||
responseType: 'code',
|
||||
redirectURI: `${getBaseUrl()}/api/auth/oauth2/callback/webflow`,
|
||||
getUserInfo: async (tokens) => {
|
||||
|
||||
@@ -251,6 +251,20 @@ export function shouldSkipWebhookEvent(webhook: any, body: any, requestId: strin
|
||||
}
|
||||
}
|
||||
|
||||
// Webflow collection filtering - filter by collectionId if configured
|
||||
if (webhook.provider === 'webflow') {
|
||||
const configuredCollectionId = providerConfig.collectionId
|
||||
if (configuredCollectionId) {
|
||||
const payloadCollectionId = body?.payload?.collectionId || body?.collectionId
|
||||
if (payloadCollectionId && payloadCollectionId !== configuredCollectionId) {
|
||||
logger.info(
|
||||
`[${requestId}] Webflow collection '${payloadCollectionId}' doesn't match configured collection '${configuredCollectionId}' for webhook ${webhook.id}, skipping`
|
||||
)
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
@@ -1400,7 +1400,7 @@ export async function createWebflowWebhookSubscription(
|
||||
): Promise<string | undefined> {
|
||||
try {
|
||||
const { path, providerConfig } = webhookData
|
||||
const { siteId, triggerId, collectionId, formId } = providerConfig || {}
|
||||
const { siteId, triggerId, collectionId, formName } = providerConfig || {}
|
||||
|
||||
if (!siteId) {
|
||||
webflowLogger.warn(`[${requestId}] Missing siteId for Webflow webhook creation.`, {
|
||||
@@ -1455,17 +1455,10 @@ export async function createWebflowWebhookSubscription(
|
||||
url: notificationUrl,
|
||||
}
|
||||
|
||||
if (collectionId && webflowTriggerType.startsWith('collection_item_')) {
|
||||
// Note: Webflow API only supports 'filter' for form_submission triggers.
|
||||
if (formName && webflowTriggerType === 'form_submission') {
|
||||
requestBody.filter = {
|
||||
resource_type: 'collection',
|
||||
resource_id: collectionId,
|
||||
}
|
||||
}
|
||||
|
||||
if (formId && webflowTriggerType === 'form_submission') {
|
||||
requestBody.filter = {
|
||||
resource_type: 'form',
|
||||
resource_id: formId,
|
||||
name: formName,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -800,15 +800,39 @@ export async function formatWebhookInput(
|
||||
}
|
||||
|
||||
if (foundWebhook.provider === 'webflow') {
|
||||
const providerConfig = (foundWebhook.providerConfig as Record<string, any>) || {}
|
||||
const triggerId = providerConfig.triggerId as string | undefined
|
||||
|
||||
// Form submission trigger
|
||||
if (triggerId === 'webflow_form_submission') {
|
||||
return {
|
||||
siteId: body?.siteId || '',
|
||||
formId: body?.formId || '',
|
||||
name: body?.name || '',
|
||||
id: body?.id || '',
|
||||
submittedAt: body?.submittedAt || '',
|
||||
data: body?.data || {},
|
||||
schema: body?.schema || {},
|
||||
formElementId: body?.formElementId || '',
|
||||
}
|
||||
}
|
||||
|
||||
// Collection item triggers (created, changed, deleted)
|
||||
// Webflow uses _cid for collection ID and _id for item ID
|
||||
const { _cid, _id, ...itemFields } = body || {}
|
||||
return {
|
||||
siteId: body?.siteId || '',
|
||||
formId: body?.formId || '',
|
||||
name: body?.name || '',
|
||||
id: body?.id || '',
|
||||
submittedAt: body?.submittedAt || '',
|
||||
data: body?.data || {},
|
||||
schema: body?.schema || {},
|
||||
formElementId: body?.formElementId || '',
|
||||
collectionId: _cid || body?.collectionId || '',
|
||||
payload: {
|
||||
id: _id || '',
|
||||
cmsLocaleId: itemFields?.cmsLocaleId || '',
|
||||
lastPublished: itemFields?.lastPublished || itemFields?.['last-published'] || '',
|
||||
lastUpdated: itemFields?.lastUpdated || itemFields?.['last-updated'] || '',
|
||||
createdOn: itemFields?.createdOn || itemFields?.['created-on'] || '',
|
||||
isArchived: itemFields?.isArchived || itemFields?._archived || false,
|
||||
isDraft: itemFields?.isDraft || itemFields?._draft || false,
|
||||
fieldData: itemFields,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { WebflowIcon } from '@/components/icons'
|
||||
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
|
||||
import type { TriggerConfig } from '../types'
|
||||
|
||||
const logger = createLogger('webflow-collection-item-changed-trigger')
|
||||
|
||||
export const webflowCollectionItemChangedTrigger: TriggerConfig = {
|
||||
id: 'webflow_collection_item_changed',
|
||||
name: 'Collection Item Changed',
|
||||
@@ -38,6 +42,58 @@ export const webflowCollectionItemChangedTrigger: TriggerConfig = {
|
||||
field: 'selectedTriggerId',
|
||||
value: 'webflow_collection_item_changed',
|
||||
},
|
||||
fetchOptions: async (blockId: string, _subBlockId: string) => {
|
||||
const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as
|
||||
| string
|
||||
| null
|
||||
if (!credentialId) {
|
||||
throw new Error('No Webflow credential selected')
|
||||
}
|
||||
try {
|
||||
const response = await fetch('/api/tools/webflow/sites', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ credential: credentialId }),
|
||||
})
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch Webflow sites')
|
||||
}
|
||||
const data = await response.json()
|
||||
if (data.sites && Array.isArray(data.sites)) {
|
||||
return data.sites.map((site: { id: string; name: string }) => ({
|
||||
id: site.id,
|
||||
label: site.name,
|
||||
}))
|
||||
}
|
||||
return []
|
||||
} catch (error) {
|
||||
logger.error('Error fetching Webflow sites:', error)
|
||||
throw error
|
||||
}
|
||||
},
|
||||
fetchOptionById: async (blockId: string, _subBlockId: string, optionId: string) => {
|
||||
const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as
|
||||
| string
|
||||
| null
|
||||
if (!credentialId) return null
|
||||
try {
|
||||
const response = await fetch('/api/tools/webflow/sites', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ credential: credentialId, siteId: optionId }),
|
||||
})
|
||||
if (!response.ok) return null
|
||||
const data = await response.json()
|
||||
const site = data.sites?.find((s: { id: string }) => s.id === optionId)
|
||||
if (site) {
|
||||
return { id: site.id, label: site.name }
|
||||
}
|
||||
return null
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
},
|
||||
dependsOn: ['triggerCredentials'],
|
||||
},
|
||||
{
|
||||
id: 'collectionId',
|
||||
@@ -52,6 +108,60 @@ export const webflowCollectionItemChangedTrigger: TriggerConfig = {
|
||||
field: 'selectedTriggerId',
|
||||
value: 'webflow_collection_item_changed',
|
||||
},
|
||||
fetchOptions: async (blockId: string, _subBlockId: string) => {
|
||||
const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as
|
||||
| string
|
||||
| null
|
||||
const siteId = useSubBlockStore.getState().getValue(blockId, 'siteId') as string | null
|
||||
if (!credentialId || !siteId) {
|
||||
return []
|
||||
}
|
||||
try {
|
||||
const response = await fetch('/api/tools/webflow/collections', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ credential: credentialId, siteId }),
|
||||
})
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch Webflow collections')
|
||||
}
|
||||
const data = await response.json()
|
||||
if (data.collections && Array.isArray(data.collections)) {
|
||||
return data.collections.map((collection: { id: string; name: string }) => ({
|
||||
id: collection.id,
|
||||
label: collection.name,
|
||||
}))
|
||||
}
|
||||
return []
|
||||
} catch (error) {
|
||||
logger.error('Error fetching Webflow collections:', error)
|
||||
throw error
|
||||
}
|
||||
},
|
||||
fetchOptionById: async (blockId: string, _subBlockId: string, optionId: string) => {
|
||||
const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as
|
||||
| string
|
||||
| null
|
||||
const siteId = useSubBlockStore.getState().getValue(blockId, 'siteId') as string | null
|
||||
if (!credentialId || !siteId) return null
|
||||
try {
|
||||
const response = await fetch('/api/tools/webflow/collections', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ credential: credentialId, siteId }),
|
||||
})
|
||||
if (!response.ok) return null
|
||||
const data = await response.json()
|
||||
const collection = data.collections?.find((c: { id: string }) => c.id === optionId)
|
||||
if (collection) {
|
||||
return { id: collection.id, label: collection.name }
|
||||
}
|
||||
return null
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
},
|
||||
dependsOn: ['triggerCredentials', 'siteId'],
|
||||
},
|
||||
{
|
||||
id: 'triggerSave',
|
||||
@@ -72,9 +182,9 @@ export const webflowCollectionItemChangedTrigger: TriggerConfig = {
|
||||
type: 'text',
|
||||
defaultValue: [
|
||||
'Connect your Webflow account using the "Select Webflow credential" button above.',
|
||||
'Enter your Webflow Site ID (found in the site URL or site settings).',
|
||||
'Optionally enter a Collection ID to monitor only specific collections.',
|
||||
'If no Collection ID is provided, the trigger will fire for items changed in any collection on the site.',
|
||||
'Select your Webflow site from the dropdown.',
|
||||
'Optionally select a collection to monitor only specific collections.',
|
||||
'If no collection is selected, the trigger will fire for items changed in any collection on the site.',
|
||||
'The webhook will trigger whenever an existing item is updated in the specified collection(s).',
|
||||
'Make sure your Webflow account has appropriate permissions for the specified site.',
|
||||
]
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { WebflowIcon } from '@/components/icons'
|
||||
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
|
||||
import type { TriggerConfig } from '../types'
|
||||
|
||||
const logger = createLogger('webflow-collection-item-created-trigger')
|
||||
|
||||
export const webflowCollectionItemCreatedTrigger: TriggerConfig = {
|
||||
id: 'webflow_collection_item_created',
|
||||
name: 'Collection Item Created',
|
||||
@@ -20,6 +24,7 @@ export const webflowCollectionItemCreatedTrigger: TriggerConfig = {
|
||||
{ label: 'Collection Item Created', id: 'webflow_collection_item_created' },
|
||||
{ label: 'Collection Item Changed', id: 'webflow_collection_item_changed' },
|
||||
{ label: 'Collection Item Deleted', id: 'webflow_collection_item_deleted' },
|
||||
{ label: 'Form Submission', id: 'webflow_form_submission' },
|
||||
],
|
||||
value: () => 'webflow_collection_item_created',
|
||||
required: true,
|
||||
@@ -51,6 +56,58 @@ export const webflowCollectionItemCreatedTrigger: TriggerConfig = {
|
||||
field: 'selectedTriggerId',
|
||||
value: 'webflow_collection_item_created',
|
||||
},
|
||||
fetchOptions: async (blockId: string, _subBlockId: string) => {
|
||||
const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as
|
||||
| string
|
||||
| null
|
||||
if (!credentialId) {
|
||||
throw new Error('No Webflow credential selected')
|
||||
}
|
||||
try {
|
||||
const response = await fetch('/api/tools/webflow/sites', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ credential: credentialId }),
|
||||
})
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch Webflow sites')
|
||||
}
|
||||
const data = await response.json()
|
||||
if (data.sites && Array.isArray(data.sites)) {
|
||||
return data.sites.map((site: { id: string; name: string }) => ({
|
||||
id: site.id,
|
||||
label: site.name,
|
||||
}))
|
||||
}
|
||||
return []
|
||||
} catch (error) {
|
||||
logger.error('Error fetching Webflow sites:', error)
|
||||
throw error
|
||||
}
|
||||
},
|
||||
fetchOptionById: async (blockId: string, _subBlockId: string, optionId: string) => {
|
||||
const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as
|
||||
| string
|
||||
| null
|
||||
if (!credentialId) return null
|
||||
try {
|
||||
const response = await fetch('/api/tools/webflow/sites', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ credential: credentialId, siteId: optionId }),
|
||||
})
|
||||
if (!response.ok) return null
|
||||
const data = await response.json()
|
||||
const site = data.sites?.find((s: { id: string }) => s.id === optionId)
|
||||
if (site) {
|
||||
return { id: site.id, label: site.name }
|
||||
}
|
||||
return null
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
},
|
||||
dependsOn: ['triggerCredentials'],
|
||||
},
|
||||
{
|
||||
id: 'collectionId',
|
||||
@@ -65,6 +122,60 @@ export const webflowCollectionItemCreatedTrigger: TriggerConfig = {
|
||||
field: 'selectedTriggerId',
|
||||
value: 'webflow_collection_item_created',
|
||||
},
|
||||
fetchOptions: async (blockId: string, _subBlockId: string) => {
|
||||
const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as
|
||||
| string
|
||||
| null
|
||||
const siteId = useSubBlockStore.getState().getValue(blockId, 'siteId') as string | null
|
||||
if (!credentialId || !siteId) {
|
||||
return []
|
||||
}
|
||||
try {
|
||||
const response = await fetch('/api/tools/webflow/collections', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ credential: credentialId, siteId }),
|
||||
})
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch Webflow collections')
|
||||
}
|
||||
const data = await response.json()
|
||||
if (data.collections && Array.isArray(data.collections)) {
|
||||
return data.collections.map((collection: { id: string; name: string }) => ({
|
||||
id: collection.id,
|
||||
label: collection.name,
|
||||
}))
|
||||
}
|
||||
return []
|
||||
} catch (error) {
|
||||
logger.error('Error fetching Webflow collections:', error)
|
||||
throw error
|
||||
}
|
||||
},
|
||||
fetchOptionById: async (blockId: string, _subBlockId: string, optionId: string) => {
|
||||
const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as
|
||||
| string
|
||||
| null
|
||||
const siteId = useSubBlockStore.getState().getValue(blockId, 'siteId') as string | null
|
||||
if (!credentialId || !siteId) return null
|
||||
try {
|
||||
const response = await fetch('/api/tools/webflow/collections', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ credential: credentialId, siteId }),
|
||||
})
|
||||
if (!response.ok) return null
|
||||
const data = await response.json()
|
||||
const collection = data.collections?.find((c: { id: string }) => c.id === optionId)
|
||||
if (collection) {
|
||||
return { id: collection.id, label: collection.name }
|
||||
}
|
||||
return null
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
},
|
||||
dependsOn: ['triggerCredentials', 'siteId'],
|
||||
},
|
||||
{
|
||||
id: 'triggerSave',
|
||||
@@ -85,9 +196,9 @@ export const webflowCollectionItemCreatedTrigger: TriggerConfig = {
|
||||
type: 'text',
|
||||
defaultValue: [
|
||||
'Connect your Webflow account using the "Select Webflow credential" button above.',
|
||||
'Enter your Webflow Site ID (found in the site URL or site settings).',
|
||||
'Optionally enter a Collection ID to monitor only specific collections.',
|
||||
'If no Collection ID is provided, the trigger will fire for items created in any collection on the site.',
|
||||
'Select your Webflow site from the dropdown.',
|
||||
'Optionally select a collection to monitor only specific collections.',
|
||||
'If no collection is selected, the trigger will fire for items created in any collection on the site.',
|
||||
'The webhook will trigger whenever a new item is created in the specified collection(s).',
|
||||
'Make sure your Webflow account has appropriate permissions for the specified site.',
|
||||
]
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { WebflowIcon } from '@/components/icons'
|
||||
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
|
||||
import type { TriggerConfig } from '../types'
|
||||
|
||||
const logger = createLogger('webflow-collection-item-deleted-trigger')
|
||||
|
||||
export const webflowCollectionItemDeletedTrigger: TriggerConfig = {
|
||||
id: 'webflow_collection_item_deleted',
|
||||
name: 'Collection Item Deleted',
|
||||
@@ -38,6 +42,58 @@ export const webflowCollectionItemDeletedTrigger: TriggerConfig = {
|
||||
field: 'selectedTriggerId',
|
||||
value: 'webflow_collection_item_deleted',
|
||||
},
|
||||
fetchOptions: async (blockId: string, _subBlockId: string) => {
|
||||
const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as
|
||||
| string
|
||||
| null
|
||||
if (!credentialId) {
|
||||
throw new Error('No Webflow credential selected')
|
||||
}
|
||||
try {
|
||||
const response = await fetch('/api/tools/webflow/sites', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ credential: credentialId }),
|
||||
})
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch Webflow sites')
|
||||
}
|
||||
const data = await response.json()
|
||||
if (data.sites && Array.isArray(data.sites)) {
|
||||
return data.sites.map((site: { id: string; name: string }) => ({
|
||||
id: site.id,
|
||||
label: site.name,
|
||||
}))
|
||||
}
|
||||
return []
|
||||
} catch (error) {
|
||||
logger.error('Error fetching Webflow sites:', error)
|
||||
throw error
|
||||
}
|
||||
},
|
||||
fetchOptionById: async (blockId: string, _subBlockId: string, optionId: string) => {
|
||||
const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as
|
||||
| string
|
||||
| null
|
||||
if (!credentialId) return null
|
||||
try {
|
||||
const response = await fetch('/api/tools/webflow/sites', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ credential: credentialId, siteId: optionId }),
|
||||
})
|
||||
if (!response.ok) return null
|
||||
const data = await response.json()
|
||||
const site = data.sites?.find((s: { id: string }) => s.id === optionId)
|
||||
if (site) {
|
||||
return { id: site.id, label: site.name }
|
||||
}
|
||||
return null
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
},
|
||||
dependsOn: ['triggerCredentials'],
|
||||
},
|
||||
{
|
||||
id: 'collectionId',
|
||||
@@ -52,6 +108,60 @@ export const webflowCollectionItemDeletedTrigger: TriggerConfig = {
|
||||
field: 'selectedTriggerId',
|
||||
value: 'webflow_collection_item_deleted',
|
||||
},
|
||||
fetchOptions: async (blockId: string, _subBlockId: string) => {
|
||||
const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as
|
||||
| string
|
||||
| null
|
||||
const siteId = useSubBlockStore.getState().getValue(blockId, 'siteId') as string | null
|
||||
if (!credentialId || !siteId) {
|
||||
return []
|
||||
}
|
||||
try {
|
||||
const response = await fetch('/api/tools/webflow/collections', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ credential: credentialId, siteId }),
|
||||
})
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch Webflow collections')
|
||||
}
|
||||
const data = await response.json()
|
||||
if (data.collections && Array.isArray(data.collections)) {
|
||||
return data.collections.map((collection: { id: string; name: string }) => ({
|
||||
id: collection.id,
|
||||
label: collection.name,
|
||||
}))
|
||||
}
|
||||
return []
|
||||
} catch (error) {
|
||||
logger.error('Error fetching Webflow collections:', error)
|
||||
throw error
|
||||
}
|
||||
},
|
||||
fetchOptionById: async (blockId: string, _subBlockId: string, optionId: string) => {
|
||||
const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as
|
||||
| string
|
||||
| null
|
||||
const siteId = useSubBlockStore.getState().getValue(blockId, 'siteId') as string | null
|
||||
if (!credentialId || !siteId) return null
|
||||
try {
|
||||
const response = await fetch('/api/tools/webflow/collections', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ credential: credentialId, siteId }),
|
||||
})
|
||||
if (!response.ok) return null
|
||||
const data = await response.json()
|
||||
const collection = data.collections?.find((c: { id: string }) => c.id === optionId)
|
||||
if (collection) {
|
||||
return { id: collection.id, label: collection.name }
|
||||
}
|
||||
return null
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
},
|
||||
dependsOn: ['triggerCredentials', 'siteId'],
|
||||
},
|
||||
{
|
||||
id: 'triggerSave',
|
||||
@@ -72,9 +182,9 @@ export const webflowCollectionItemDeletedTrigger: TriggerConfig = {
|
||||
type: 'text',
|
||||
defaultValue: [
|
||||
'Connect your Webflow account using the "Select Webflow credential" button above.',
|
||||
'Enter your Webflow Site ID (found in the site URL or site settings).',
|
||||
'Optionally enter a Collection ID to monitor only specific collections.',
|
||||
'If no Collection ID is provided, the trigger will fire for items deleted in any collection on the site.',
|
||||
'Select your Webflow site from the dropdown.',
|
||||
'Optionally select a collection to monitor only specific collections.',
|
||||
'If no collection is selected, the trigger will fire for items deleted in any collection on the site.',
|
||||
'The webhook will trigger whenever an item is deleted from the specified collection(s).',
|
||||
'Note: Once an item is deleted, only minimal information (ID, collection, site) is available.',
|
||||
'Make sure your Webflow account has appropriate permissions for the specified site.',
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { WebflowIcon } from '@/components/icons'
|
||||
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
|
||||
import type { TriggerConfig } from '../types'
|
||||
|
||||
const logger = createLogger('webflow-form-submission-trigger')
|
||||
|
||||
export const webflowFormSubmissionTrigger: TriggerConfig = {
|
||||
id: 'webflow_form_submission',
|
||||
name: 'Form Submission',
|
||||
@@ -17,9 +21,13 @@ export const webflowFormSubmissionTrigger: TriggerConfig = {
|
||||
type: 'oauth-input',
|
||||
description: 'This trigger requires webflow credentials to access your account.',
|
||||
serviceId: 'webflow',
|
||||
requiredScopes: [],
|
||||
requiredScopes: ['forms:read'],
|
||||
required: true,
|
||||
mode: 'trigger',
|
||||
condition: {
|
||||
field: 'selectedTriggerId',
|
||||
value: 'webflow_form_submission',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'siteId',
|
||||
@@ -30,15 +38,76 @@ export const webflowFormSubmissionTrigger: TriggerConfig = {
|
||||
required: true,
|
||||
options: [],
|
||||
mode: 'trigger',
|
||||
condition: {
|
||||
field: 'selectedTriggerId',
|
||||
value: 'webflow_form_submission',
|
||||
},
|
||||
fetchOptions: async (blockId: string, _subBlockId: string) => {
|
||||
const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as
|
||||
| string
|
||||
| null
|
||||
if (!credentialId) {
|
||||
throw new Error('No Webflow credential selected')
|
||||
}
|
||||
try {
|
||||
const response = await fetch('/api/tools/webflow/sites', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ credential: credentialId }),
|
||||
})
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch Webflow sites')
|
||||
}
|
||||
const data = await response.json()
|
||||
if (data.sites && Array.isArray(data.sites)) {
|
||||
return data.sites.map((site: { id: string; name: string }) => ({
|
||||
id: site.id,
|
||||
label: site.name,
|
||||
}))
|
||||
}
|
||||
return []
|
||||
} catch (error) {
|
||||
logger.error('Error fetching Webflow sites:', error)
|
||||
throw error
|
||||
}
|
||||
},
|
||||
fetchOptionById: async (blockId: string, _subBlockId: string, optionId: string) => {
|
||||
const credentialId = useSubBlockStore.getState().getValue(blockId, 'triggerCredentials') as
|
||||
| string
|
||||
| null
|
||||
if (!credentialId) return null
|
||||
try {
|
||||
const response = await fetch('/api/tools/webflow/sites', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ credential: credentialId, siteId: optionId }),
|
||||
})
|
||||
if (!response.ok) return null
|
||||
const data = await response.json()
|
||||
const site = data.sites?.find((s: { id: string }) => s.id === optionId)
|
||||
if (site) {
|
||||
return { id: site.id, label: site.name }
|
||||
}
|
||||
return null
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
},
|
||||
dependsOn: ['triggerCredentials'],
|
||||
},
|
||||
{
|
||||
id: 'formId',
|
||||
title: 'Form ID',
|
||||
id: 'formName',
|
||||
title: 'Form Name',
|
||||
type: 'short-input',
|
||||
placeholder: 'form-123abc (optional)',
|
||||
description: 'The ID of the specific form to monitor (optional - leave empty for all forms)',
|
||||
placeholder: 'Contact Form (optional)',
|
||||
description:
|
||||
'The name of the specific form to monitor (optional - leave empty for all forms)',
|
||||
required: false,
|
||||
mode: 'trigger',
|
||||
condition: {
|
||||
field: 'selectedTriggerId',
|
||||
value: 'webflow_form_submission',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'triggerSave',
|
||||
@@ -47,6 +116,10 @@ export const webflowFormSubmissionTrigger: TriggerConfig = {
|
||||
hideFromPreview: true,
|
||||
mode: 'trigger',
|
||||
triggerId: 'webflow_form_submission',
|
||||
condition: {
|
||||
field: 'selectedTriggerId',
|
||||
value: 'webflow_form_submission',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'triggerInstructions',
|
||||
@@ -55,9 +128,9 @@ export const webflowFormSubmissionTrigger: TriggerConfig = {
|
||||
type: 'text',
|
||||
defaultValue: [
|
||||
'Connect your Webflow account using the "Select Webflow credential" button above.',
|
||||
'Enter your Webflow Site ID (found in the site URL or site settings).',
|
||||
'Optionally enter a Form ID to monitor only a specific form.',
|
||||
'If no Form ID is provided, the trigger will fire for any form submission on the site.',
|
||||
'Select your Webflow site from the dropdown.',
|
||||
'Optionally enter the Form Name to monitor only a specific form.',
|
||||
'If no Form Name is provided, the trigger will fire for any form submission on the site.',
|
||||
'The webhook will trigger whenever a form is submitted on the specified site.',
|
||||
'Form data will be included in the payload with all submitted field values.',
|
||||
'Make sure your Webflow account has appropriate permissions for the specified site.',
|
||||
@@ -68,6 +141,10 @@ export const webflowFormSubmissionTrigger: TriggerConfig = {
|
||||
)
|
||||
.join(''),
|
||||
mode: 'trigger',
|
||||
condition: {
|
||||
field: 'selectedTriggerId',
|
||||
value: 'webflow_form_submission',
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
|
||||
Reference in New Issue
Block a user