chore: import upstream snapshot with attribution
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
# Triggers Scope
|
||||
|
||||
These rules apply to trigger definitions under `apps/sim/triggers/**`.
|
||||
|
||||
- Research the service webhook model before implementing triggers.
|
||||
- Keep each service under `triggers/{service}/` with barrel exports and event-specific files.
|
||||
- Use shared helpers for setup instructions, extra fields, and output definitions when multiple triggers in the same service need them.
|
||||
- Ensure the primary trigger supports switching between trigger types when the integration pattern requires it.
|
||||
- Keep trigger outputs explicit and useful for downstream blocks.
|
||||
- Register triggers in `triggers/registry.ts` and keep IDs aligned with the integration naming scheme.
|
||||
@@ -0,0 +1 @@
|
||||
export { airtableWebhookTrigger } from './webhook'
|
||||
@@ -0,0 +1,166 @@
|
||||
import { AirtableIcon } from '@/components/icons'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
export const airtableWebhookTrigger: TriggerConfig = {
|
||||
id: 'airtable_webhook',
|
||||
name: 'Airtable Webhook',
|
||||
provider: 'airtable',
|
||||
description:
|
||||
'Trigger workflow from Airtable record changes like create, update, and delete events (requires Airtable credentials)',
|
||||
version: '1.0.0',
|
||||
icon: AirtableIcon,
|
||||
|
||||
subBlocks: [
|
||||
{
|
||||
id: 'triggerCredentials',
|
||||
title: 'Credentials',
|
||||
type: 'oauth-input',
|
||||
description: 'This trigger requires airtable credentials to access your account.',
|
||||
serviceId: 'airtable',
|
||||
requiredScopes: [],
|
||||
required: true,
|
||||
mode: 'trigger',
|
||||
},
|
||||
{
|
||||
id: 'baseId',
|
||||
title: 'Base ID',
|
||||
type: 'short-input',
|
||||
placeholder: 'appXXXXXXXXXXXXXX',
|
||||
description: 'The ID of the Airtable Base this webhook will monitor.',
|
||||
required: true,
|
||||
mode: 'trigger',
|
||||
},
|
||||
{
|
||||
id: 'tableId',
|
||||
title: 'Table ID',
|
||||
type: 'short-input',
|
||||
placeholder: 'tblXXXXXXXXXXXXXX',
|
||||
description: 'The ID of the table within the Base that the webhook will monitor.',
|
||||
required: true,
|
||||
mode: 'trigger',
|
||||
},
|
||||
{
|
||||
id: 'includeCellValues',
|
||||
title: 'Include Full Record Data',
|
||||
type: 'switch',
|
||||
description: 'Enable to receive the complete record data in the payload, not just changes.',
|
||||
defaultValue: false,
|
||||
mode: 'trigger',
|
||||
},
|
||||
{
|
||||
id: 'triggerInstructions',
|
||||
title: 'Setup Instructions',
|
||||
hideFromPreview: true,
|
||||
type: 'text',
|
||||
defaultValue: [
|
||||
'Connect your Airtable account using the "Select Airtable credential" button above.',
|
||||
'Ensure you have provided the correct Base ID and Table ID above.',
|
||||
'You can find your Base ID and Table ID in the Airtable URL: <code>https://airtable.com/[baseId]/[tableId]/...</code>. See <a href="https://support.airtable.com/docs/finding-airtable-ids" target="_blank" rel="noopener noreferrer">Finding Airtable IDs</a> for details.',
|
||||
'The webhook will trigger whenever records are created, updated, or deleted in the specified table.',
|
||||
'Make sure your Airtable account has appropriate permissions for the specified base.',
|
||||
]
|
||||
.map(
|
||||
(instruction, index) =>
|
||||
`<div class="mb-3"><strong>${index + 1}.</strong> ${instruction}</div>`
|
||||
)
|
||||
.join(''),
|
||||
mode: 'trigger',
|
||||
},
|
||||
],
|
||||
|
||||
outputs: {
|
||||
payloads: {
|
||||
type: 'array',
|
||||
description: 'The payloads of the Airtable changes',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
timestamp: { type: 'string', description: 'Timestamp of the change' },
|
||||
baseTransactionNumber: { type: 'number', description: 'Transaction number' },
|
||||
},
|
||||
},
|
||||
},
|
||||
latestPayload: {
|
||||
type: 'object',
|
||||
description: 'The most recent payload from Airtable',
|
||||
properties: {
|
||||
timestamp: { type: 'string', description: 'ISO 8601 timestamp of the change' },
|
||||
baseTransactionNumber: { type: 'number', description: 'Transaction number' },
|
||||
payloadFormat: { type: 'string', description: 'Payload format version (e.g., v0)' },
|
||||
actionMetadata: {
|
||||
type: 'object',
|
||||
description: 'Metadata about who made the change',
|
||||
properties: {
|
||||
source: {
|
||||
type: 'string',
|
||||
description: 'Source of the change (e.g., client, publicApi)',
|
||||
},
|
||||
sourceMetadata: {
|
||||
type: 'object',
|
||||
description: 'Source metadata including user info',
|
||||
properties: {
|
||||
user: {
|
||||
type: 'object',
|
||||
description: 'User who made the change',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'User ID' },
|
||||
email: { type: 'string', description: 'User email' },
|
||||
name: { type: 'string', description: 'User name' },
|
||||
permissionLevel: { type: 'string', description: 'User permission level' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
changedTablesById: {
|
||||
type: 'object',
|
||||
description: 'Tables that were changed (keyed by table ID)',
|
||||
properties: {
|
||||
changedRecordsById: {
|
||||
type: 'object',
|
||||
description: 'Changed records keyed by record ID',
|
||||
properties: {
|
||||
current: {
|
||||
type: 'object',
|
||||
description: 'Current state of the record',
|
||||
properties: {
|
||||
cellValuesByFieldId: {
|
||||
type: 'object',
|
||||
description: 'Cell values keyed by field ID',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
createdRecordsById: { type: 'object', description: 'Created records by ID' },
|
||||
destroyedRecordIds: { type: 'array', description: 'Array of destroyed record IDs' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
airtableChanges: {
|
||||
type: 'array',
|
||||
description: 'Changes made to the Airtable table',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
tableId: { type: 'string', description: 'Table ID' },
|
||||
recordId: { type: 'string', description: 'Record ID' },
|
||||
changeType: {
|
||||
type: 'string',
|
||||
description: 'Type of change (created, changed, destroyed)',
|
||||
},
|
||||
cellValuesByFieldId: { type: 'object', description: 'Cell values by field ID' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import { AshbyIcon } from '@/components/icons'
|
||||
import { buildApplicationSubmitOutputs, buildAshbySubBlocks } from '@/triggers/ashby/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Ashby Application Submitted Trigger
|
||||
*
|
||||
* This is the PRIMARY trigger - it includes the dropdown for selecting trigger type.
|
||||
* Fires when a candidate submits an application or is manually added.
|
||||
*/
|
||||
export const ashbyApplicationSubmitTrigger: TriggerConfig = {
|
||||
id: 'ashby_application_submit',
|
||||
name: 'Ashby Application Submitted',
|
||||
provider: 'ashby',
|
||||
description: 'Trigger workflow when a new application is submitted',
|
||||
version: '1.0.0',
|
||||
icon: AshbyIcon,
|
||||
|
||||
subBlocks: buildAshbySubBlocks({
|
||||
triggerId: 'ashby_application_submit',
|
||||
eventType: 'Application Submitted',
|
||||
includeDropdown: true,
|
||||
}),
|
||||
|
||||
outputs: buildApplicationSubmitOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import { AshbyIcon } from '@/components/icons'
|
||||
import { buildAshbySubBlocks, buildCandidateDeleteOutputs } from '@/triggers/ashby/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Ashby Candidate Deleted Trigger
|
||||
*
|
||||
* Fires when a candidate record is deleted from Ashby.
|
||||
*/
|
||||
export const ashbyCandidateDeleteTrigger: TriggerConfig = {
|
||||
id: 'ashby_candidate_delete',
|
||||
name: 'Ashby Candidate Deleted',
|
||||
provider: 'ashby',
|
||||
description: 'Trigger workflow when a candidate is deleted',
|
||||
version: '1.0.0',
|
||||
icon: AshbyIcon,
|
||||
|
||||
subBlocks: buildAshbySubBlocks({
|
||||
triggerId: 'ashby_candidate_delete',
|
||||
eventType: 'Candidate Deleted',
|
||||
}),
|
||||
|
||||
outputs: buildCandidateDeleteOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import { AshbyIcon } from '@/components/icons'
|
||||
import { buildAshbySubBlocks, buildCandidateHireOutputs } from '@/triggers/ashby/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Ashby Candidate Hired Trigger
|
||||
*
|
||||
* Fires when a candidate is hired. Also triggers applicationUpdate
|
||||
* and candidateStageChange webhooks.
|
||||
*/
|
||||
export const ashbyCandidateHireTrigger: TriggerConfig = {
|
||||
id: 'ashby_candidate_hire',
|
||||
name: 'Ashby Candidate Hired',
|
||||
provider: 'ashby',
|
||||
description: 'Trigger workflow when a candidate is hired',
|
||||
version: '1.0.0',
|
||||
icon: AshbyIcon,
|
||||
|
||||
subBlocks: buildAshbySubBlocks({
|
||||
triggerId: 'ashby_candidate_hire',
|
||||
eventType: 'Candidate Hired',
|
||||
}),
|
||||
|
||||
outputs: buildCandidateHireOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import { AshbyIcon } from '@/components/icons'
|
||||
import { buildAshbySubBlocks, buildCandidateStageChangeOutputs } from '@/triggers/ashby/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Ashby Candidate Stage Change Trigger
|
||||
*
|
||||
* Fires when a candidate moves to a different interview stage.
|
||||
* Also triggered by candidateHire events.
|
||||
*/
|
||||
export const ashbyCandidateStageChangeTrigger: TriggerConfig = {
|
||||
id: 'ashby_candidate_stage_change',
|
||||
name: 'Ashby Candidate Stage Change',
|
||||
provider: 'ashby',
|
||||
description: 'Trigger workflow when a candidate changes interview stages',
|
||||
version: '1.0.0',
|
||||
icon: AshbyIcon,
|
||||
|
||||
subBlocks: buildAshbySubBlocks({
|
||||
triggerId: 'ashby_candidate_stage_change',
|
||||
eventType: 'Candidate Stage Change',
|
||||
}),
|
||||
|
||||
outputs: buildCandidateStageChangeOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
export { ashbyApplicationSubmitTrigger } from './application_submit'
|
||||
export { ashbyCandidateDeleteTrigger } from './candidate_delete'
|
||||
export { ashbyCandidateHireTrigger } from './candidate_hire'
|
||||
export { ashbyCandidateStageChangeTrigger } from './candidate_stage_change'
|
||||
export { ashbyJobCreateTrigger } from './job_create'
|
||||
export { ashbyOfferCreateTrigger } from './offer_create'
|
||||
@@ -0,0 +1,31 @@
|
||||
import { AshbyIcon } from '@/components/icons'
|
||||
import { buildAshbySubBlocks, buildJobCreateOutputs } from '@/triggers/ashby/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Ashby Job Created Trigger
|
||||
*
|
||||
* Fires when a new job posting is created in Ashby.
|
||||
*/
|
||||
export const ashbyJobCreateTrigger: TriggerConfig = {
|
||||
id: 'ashby_job_create',
|
||||
name: 'Ashby Job Created',
|
||||
provider: 'ashby',
|
||||
description: 'Trigger workflow when a new job is created',
|
||||
version: '1.0.0',
|
||||
icon: AshbyIcon,
|
||||
|
||||
subBlocks: buildAshbySubBlocks({
|
||||
triggerId: 'ashby_job_create',
|
||||
eventType: 'Job Created',
|
||||
}),
|
||||
|
||||
outputs: buildJobCreateOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import { AshbyIcon } from '@/components/icons'
|
||||
import { buildAshbySubBlocks, buildOfferCreateOutputs } from '@/triggers/ashby/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Ashby Offer Created Trigger
|
||||
*
|
||||
* Fires when a new offer is created for a candidate.
|
||||
*/
|
||||
export const ashbyOfferCreateTrigger: TriggerConfig = {
|
||||
id: 'ashby_offer_create',
|
||||
name: 'Ashby Offer Created',
|
||||
provider: 'ashby',
|
||||
description: 'Trigger workflow when a new offer is created',
|
||||
version: '1.0.0',
|
||||
icon: AshbyIcon,
|
||||
|
||||
subBlocks: buildAshbySubBlocks({
|
||||
triggerId: 'ashby_offer_create',
|
||||
eventType: 'Offer Created',
|
||||
}),
|
||||
|
||||
outputs: buildOfferCreateOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,313 @@
|
||||
import type { SubBlockConfig } from '@/blocks/types'
|
||||
import type { TriggerOutput } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Dropdown options for the Ashby trigger type selector.
|
||||
*/
|
||||
export const ashbyTriggerOptions = [
|
||||
{ label: 'Application Submitted', id: 'ashby_application_submit' },
|
||||
{ label: 'Candidate Stage Change', id: 'ashby_candidate_stage_change' },
|
||||
{ label: 'Candidate Hired', id: 'ashby_candidate_hire' },
|
||||
{ label: 'Candidate Deleted', id: 'ashby_candidate_delete' },
|
||||
{ label: 'Job Created', id: 'ashby_job_create' },
|
||||
{ label: 'Offer Created', id: 'ashby_offer_create' },
|
||||
]
|
||||
|
||||
/**
|
||||
* Maps Sim trigger IDs to Ashby webhookType / event action values.
|
||||
* Used by webhook.create body and matchEvent filtering.
|
||||
*/
|
||||
export const ASHBY_TRIGGER_ACTION_MAP: Record<string, string> = {
|
||||
ashby_application_submit: 'applicationSubmit',
|
||||
ashby_candidate_stage_change: 'candidateStageChange',
|
||||
ashby_candidate_hire: 'candidateHire',
|
||||
ashby_candidate_delete: 'candidateDelete',
|
||||
ashby_job_create: 'jobCreate',
|
||||
ashby_offer_create: 'offerCreate',
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an Ashby webhook event matches the configured trigger.
|
||||
* Ashby sends a ping event on webhook create/edit; this filter rejects
|
||||
* any event whose `action` does not equal the expected webhookType.
|
||||
*/
|
||||
export function isAshbyEventMatch(triggerId: string, action: string): boolean {
|
||||
const expected = ASHBY_TRIGGER_ACTION_MAP[triggerId]
|
||||
if (!expected) return false
|
||||
return expected === action
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates setup instructions for Ashby webhooks.
|
||||
* Webhooks are automatically created/deleted via the Ashby API.
|
||||
*/
|
||||
export function ashbySetupInstructions(eventType: string): string {
|
||||
const instructions = [
|
||||
'Enter your Ashby API Key above. You can find your API key in Ashby at <strong>Settings > API Keys</strong>.',
|
||||
`The webhook for <strong>${eventType}</strong> events will be automatically created in Ashby when you save the trigger.`,
|
||||
'The webhook will be automatically deleted if you remove this trigger.',
|
||||
]
|
||||
|
||||
return instructions
|
||||
.map(
|
||||
(instruction, index) =>
|
||||
`<div class="mb-3"><strong>${index + 1}.</strong> ${instruction}</div>`
|
||||
)
|
||||
.join('')
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the complete subBlocks array for an Ashby trigger.
|
||||
* Ashby webhooks are managed via API, so no webhook URL is displayed.
|
||||
*
|
||||
* Structure: [dropdown?] -> apiKey -> instructions
|
||||
*/
|
||||
export function buildAshbySubBlocks(options: {
|
||||
triggerId: string
|
||||
eventType: string
|
||||
includeDropdown?: boolean
|
||||
}): SubBlockConfig[] {
|
||||
const { triggerId, eventType, includeDropdown = false } = options
|
||||
const blocks: SubBlockConfig[] = []
|
||||
|
||||
if (includeDropdown) {
|
||||
blocks.push({
|
||||
id: 'selectedTriggerId',
|
||||
title: 'Trigger Type',
|
||||
type: 'dropdown',
|
||||
mode: 'trigger',
|
||||
options: ashbyTriggerOptions,
|
||||
value: () => triggerId,
|
||||
required: true,
|
||||
})
|
||||
}
|
||||
|
||||
blocks.push({
|
||||
id: 'apiKey',
|
||||
title: 'API Key',
|
||||
type: 'short-input',
|
||||
placeholder: 'Enter your Ashby API key',
|
||||
password: true,
|
||||
required: true,
|
||||
paramVisibility: 'user-only',
|
||||
mode: 'trigger',
|
||||
condition: { field: 'selectedTriggerId', value: triggerId },
|
||||
})
|
||||
|
||||
blocks.push({
|
||||
id: 'triggerInstructions',
|
||||
title: 'Setup Instructions',
|
||||
hideFromPreview: true,
|
||||
type: 'text',
|
||||
defaultValue: ashbySetupInstructions(eventType),
|
||||
mode: 'trigger',
|
||||
condition: { field: 'selectedTriggerId', value: triggerId },
|
||||
})
|
||||
|
||||
return blocks
|
||||
}
|
||||
|
||||
/**
|
||||
* Core fields present in all Ashby webhook payloads.
|
||||
*/
|
||||
const coreOutputs = {
|
||||
action: {
|
||||
type: 'string',
|
||||
description: 'The webhook event type (e.g., applicationSubmit, candidateHire)',
|
||||
},
|
||||
} as const
|
||||
|
||||
/**
|
||||
* Build outputs for applicationSubmit events.
|
||||
* Payload: { action, data: { application: { id, createdAt, updatedAt, status,
|
||||
* candidate: { id, name }, currentInterviewStage: { id, title },
|
||||
* job: { id, title } } } }
|
||||
*/
|
||||
export function buildApplicationSubmitOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
...coreOutputs,
|
||||
application: {
|
||||
id: { type: 'string', description: 'Application UUID' },
|
||||
createdAt: { type: 'string', description: 'Application creation timestamp (ISO 8601)' },
|
||||
updatedAt: {
|
||||
type: 'string',
|
||||
description: 'Application last update timestamp (ISO 8601)',
|
||||
},
|
||||
status: {
|
||||
type: 'string',
|
||||
description: 'Application status (Active, Hired, Archived, Lead)',
|
||||
},
|
||||
candidate: {
|
||||
id: { type: 'string', description: 'Candidate UUID' },
|
||||
name: { type: 'string', description: 'Candidate name' },
|
||||
},
|
||||
currentInterviewStage: {
|
||||
id: { type: 'string', description: 'Current interview stage UUID' },
|
||||
title: { type: 'string', description: 'Current interview stage title' },
|
||||
stageType: {
|
||||
type: 'string',
|
||||
description: 'Current interview stage type (e.g., Lead, Applied, Interview, Offer)',
|
||||
},
|
||||
},
|
||||
job: {
|
||||
id: { type: 'string', description: 'Job UUID' },
|
||||
title: { type: 'string', description: 'Job title' },
|
||||
},
|
||||
},
|
||||
} as Record<string, TriggerOutput>
|
||||
}
|
||||
|
||||
/**
|
||||
* Build outputs for candidateStageChange events.
|
||||
* Payload matches the application object structure (same as applicationUpdate).
|
||||
* Payload: { action, data: { application: { id, createdAt, updatedAt, status,
|
||||
* candidate: { id, name }, currentInterviewStage: { id, title, type },
|
||||
* job: { id, title } } } }
|
||||
*/
|
||||
export function buildCandidateStageChangeOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
...coreOutputs,
|
||||
application: {
|
||||
id: { type: 'string', description: 'Application UUID' },
|
||||
createdAt: { type: 'string', description: 'Application creation timestamp (ISO 8601)' },
|
||||
updatedAt: {
|
||||
type: 'string',
|
||||
description: 'Application last update timestamp (ISO 8601)',
|
||||
},
|
||||
status: {
|
||||
type: 'string',
|
||||
description: 'Application status (Active, Hired, Archived, Lead)',
|
||||
},
|
||||
candidate: {
|
||||
id: { type: 'string', description: 'Candidate UUID' },
|
||||
name: { type: 'string', description: 'Candidate name' },
|
||||
},
|
||||
currentInterviewStage: {
|
||||
id: { type: 'string', description: 'Current interview stage UUID' },
|
||||
title: { type: 'string', description: 'Current interview stage title' },
|
||||
stageType: {
|
||||
type: 'string',
|
||||
description: 'Current interview stage type (e.g., Lead, Applied, Interview, Offer)',
|
||||
},
|
||||
},
|
||||
job: {
|
||||
id: { type: 'string', description: 'Job UUID' },
|
||||
title: { type: 'string', description: 'Job title' },
|
||||
},
|
||||
},
|
||||
} as Record<string, TriggerOutput>
|
||||
}
|
||||
|
||||
/**
|
||||
* Build outputs for candidateHire events.
|
||||
* Per Ashby docs, candidateHire payloads include application details and most
|
||||
* recent accepted offer information.
|
||||
*/
|
||||
export function buildCandidateHireOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
...coreOutputs,
|
||||
application: {
|
||||
id: { type: 'string', description: 'Application UUID' },
|
||||
createdAt: { type: 'string', description: 'Application creation timestamp (ISO 8601)' },
|
||||
updatedAt: {
|
||||
type: 'string',
|
||||
description: 'Application last update timestamp (ISO 8601)',
|
||||
},
|
||||
status: { type: 'string', description: 'Application status (Hired)' },
|
||||
candidate: {
|
||||
id: { type: 'string', description: 'Candidate UUID' },
|
||||
name: { type: 'string', description: 'Candidate name' },
|
||||
},
|
||||
currentInterviewStage: {
|
||||
id: { type: 'string', description: 'Current interview stage UUID' },
|
||||
title: { type: 'string', description: 'Current interview stage title' },
|
||||
stageType: {
|
||||
type: 'string',
|
||||
description: 'Current interview stage type (e.g., Lead, Applied, Interview, Offer)',
|
||||
},
|
||||
},
|
||||
job: {
|
||||
id: { type: 'string', description: 'Job UUID' },
|
||||
title: { type: 'string', description: 'Job title' },
|
||||
},
|
||||
},
|
||||
offer: {
|
||||
id: { type: 'string', description: 'Accepted offer UUID' },
|
||||
applicationId: { type: 'string', description: 'Associated application UUID' },
|
||||
acceptanceStatus: { type: 'string', description: 'Offer acceptance status' },
|
||||
offerStatus: { type: 'string', description: 'Offer process status' },
|
||||
decidedAt: {
|
||||
type: 'string',
|
||||
description: 'Offer decision timestamp (ISO 8601)',
|
||||
},
|
||||
latestVersion: {
|
||||
id: { type: 'string', description: 'Latest offer version UUID' },
|
||||
},
|
||||
},
|
||||
} as Record<string, TriggerOutput>
|
||||
}
|
||||
|
||||
/**
|
||||
* Build outputs for candidateDelete events.
|
||||
* Payload: { action, data: { candidate: { id } } }
|
||||
*/
|
||||
export function buildCandidateDeleteOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
...coreOutputs,
|
||||
candidate: {
|
||||
id: { type: 'string', description: 'Deleted candidate UUID' },
|
||||
},
|
||||
} as Record<string, TriggerOutput>
|
||||
}
|
||||
|
||||
/**
|
||||
* Build outputs for jobCreate events.
|
||||
* Payload: { action, data: { job: { id, title, confidential, status, employmentType } } }
|
||||
*/
|
||||
export function buildJobCreateOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
...coreOutputs,
|
||||
job: {
|
||||
id: { type: 'string', description: 'Job UUID' },
|
||||
title: { type: 'string', description: 'Job title' },
|
||||
confidential: { type: 'boolean', description: 'Whether the job is confidential' },
|
||||
status: { type: 'string', description: 'Job status (Open, Closed, Draft, Archived)' },
|
||||
employmentType: {
|
||||
type: 'string',
|
||||
description: 'Employment type (FullTime, PartTime, Intern, Contract)',
|
||||
},
|
||||
},
|
||||
} as Record<string, TriggerOutput>
|
||||
}
|
||||
|
||||
/**
|
||||
* Build outputs for offerCreate events.
|
||||
* Payload: { action, data: { offer: { id, decidedAt, applicationId, acceptanceStatus,
|
||||
* offerStatus, latestVersion: { id } } } }
|
||||
*/
|
||||
export function buildOfferCreateOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
...coreOutputs,
|
||||
offer: {
|
||||
id: { type: 'string', description: 'Offer UUID' },
|
||||
applicationId: { type: 'string', description: 'Associated application UUID' },
|
||||
acceptanceStatus: {
|
||||
type: 'string',
|
||||
description: 'Offer acceptance status (Accepted, Declined, Pending, Created, Cancelled)',
|
||||
},
|
||||
offerStatus: {
|
||||
type: 'string',
|
||||
description:
|
||||
'Offer process status (WaitingOnApprovalStart, WaitingOnOfferApproval, WaitingOnApprovalDefinition, WaitingOnCandidateResponse, CandidateRejected, CandidateAccepted, OfferCancelled)',
|
||||
},
|
||||
decidedAt: {
|
||||
type: 'string',
|
||||
description:
|
||||
'Offer decision timestamp (ISO 8601). Typically null at creation; populated after candidate responds.',
|
||||
},
|
||||
latestVersion: {
|
||||
id: { type: 'string', description: 'Latest offer version UUID' },
|
||||
},
|
||||
},
|
||||
} as Record<string, TriggerOutput>
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { AttioIcon } from '@/components/icons'
|
||||
import { buildAttioTriggerSubBlocks, buildCommentOutputs } from '@/triggers/attio/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Attio Comment Created Trigger
|
||||
*
|
||||
* Triggers when a comment is created in Attio.
|
||||
*/
|
||||
export const attioCommentCreatedTrigger: TriggerConfig = {
|
||||
id: 'attio_comment_created',
|
||||
name: 'Attio Comment Created',
|
||||
provider: 'attio',
|
||||
description: 'Trigger workflow when a new comment is created in Attio',
|
||||
version: '1.0.0',
|
||||
icon: AttioIcon,
|
||||
|
||||
subBlocks: buildAttioTriggerSubBlocks('attio_comment_created'),
|
||||
|
||||
outputs: buildCommentOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Attio-Signature': 'hmac-sha256-signature',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { AttioIcon } from '@/components/icons'
|
||||
import { buildAttioTriggerSubBlocks, buildCommentOutputs } from '@/triggers/attio/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Attio Comment Deleted Trigger
|
||||
*
|
||||
* Triggers when a comment is deleted in Attio.
|
||||
*/
|
||||
export const attioCommentDeletedTrigger: TriggerConfig = {
|
||||
id: 'attio_comment_deleted',
|
||||
name: 'Attio Comment Deleted',
|
||||
provider: 'attio',
|
||||
description: 'Trigger workflow when a comment is deleted in Attio',
|
||||
version: '1.0.0',
|
||||
icon: AttioIcon,
|
||||
|
||||
subBlocks: buildAttioTriggerSubBlocks('attio_comment_deleted'),
|
||||
|
||||
outputs: buildCommentOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Attio-Signature': 'hmac-sha256-signature',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { AttioIcon } from '@/components/icons'
|
||||
import { buildAttioTriggerSubBlocks, buildCommentOutputs } from '@/triggers/attio/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Attio Comment Resolved Trigger
|
||||
*
|
||||
* Triggers when a comment thread is resolved in Attio.
|
||||
*/
|
||||
export const attioCommentResolvedTrigger: TriggerConfig = {
|
||||
id: 'attio_comment_resolved',
|
||||
name: 'Attio Comment Resolved',
|
||||
provider: 'attio',
|
||||
description: 'Trigger workflow when a comment thread is resolved in Attio',
|
||||
version: '1.0.0',
|
||||
icon: AttioIcon,
|
||||
|
||||
subBlocks: buildAttioTriggerSubBlocks('attio_comment_resolved'),
|
||||
|
||||
outputs: buildCommentOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Attio-Signature': 'hmac-sha256-signature',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { AttioIcon } from '@/components/icons'
|
||||
import { buildAttioTriggerSubBlocks, buildCommentOutputs } from '@/triggers/attio/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Attio Comment Unresolved Trigger
|
||||
*
|
||||
* Triggers when a comment thread is unresolved in Attio.
|
||||
*/
|
||||
export const attioCommentUnresolvedTrigger: TriggerConfig = {
|
||||
id: 'attio_comment_unresolved',
|
||||
name: 'Attio Comment Unresolved',
|
||||
provider: 'attio',
|
||||
description: 'Trigger workflow when a comment thread is unresolved in Attio',
|
||||
version: '1.0.0',
|
||||
icon: AttioIcon,
|
||||
|
||||
subBlocks: buildAttioTriggerSubBlocks('attio_comment_unresolved'),
|
||||
|
||||
outputs: buildCommentOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Attio-Signature': 'hmac-sha256-signature',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
export { attioCommentCreatedTrigger } from './comment_created'
|
||||
export { attioCommentDeletedTrigger } from './comment_deleted'
|
||||
export { attioCommentResolvedTrigger } from './comment_resolved'
|
||||
export { attioCommentUnresolvedTrigger } from './comment_unresolved'
|
||||
export { attioListCreatedTrigger } from './list_created'
|
||||
export { attioListDeletedTrigger } from './list_deleted'
|
||||
export { attioListEntryCreatedTrigger } from './list_entry_created'
|
||||
export { attioListEntryDeletedTrigger } from './list_entry_deleted'
|
||||
export { attioListEntryUpdatedTrigger } from './list_entry_updated'
|
||||
export { attioListUpdatedTrigger } from './list_updated'
|
||||
export { attioNoteCreatedTrigger } from './note_created'
|
||||
export { attioNoteDeletedTrigger } from './note_deleted'
|
||||
export { attioNoteUpdatedTrigger } from './note_updated'
|
||||
export { attioRecordCreatedTrigger } from './record_created'
|
||||
export { attioRecordDeletedTrigger } from './record_deleted'
|
||||
export { attioRecordMergedTrigger } from './record_merged'
|
||||
export { attioRecordUpdatedTrigger } from './record_updated'
|
||||
export { attioTaskCreatedTrigger } from './task_created'
|
||||
export { attioTaskDeletedTrigger } from './task_deleted'
|
||||
export { attioTaskUpdatedTrigger } from './task_updated'
|
||||
export { attioWebhookTrigger } from './webhook'
|
||||
export { attioWorkspaceMemberCreatedTrigger } from './workspace_member_created'
|
||||
@@ -0,0 +1,29 @@
|
||||
import { AttioIcon } from '@/components/icons'
|
||||
import { buildAttioTriggerSubBlocks, buildListOutputs } from '@/triggers/attio/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Attio List Created Trigger
|
||||
*
|
||||
* Triggers when a list is created in Attio.
|
||||
*/
|
||||
export const attioListCreatedTrigger: TriggerConfig = {
|
||||
id: 'attio_list_created',
|
||||
name: 'Attio List Created',
|
||||
provider: 'attio',
|
||||
description: 'Trigger workflow when a list is created in Attio',
|
||||
version: '1.0.0',
|
||||
icon: AttioIcon,
|
||||
|
||||
subBlocks: buildAttioTriggerSubBlocks('attio_list_created'),
|
||||
|
||||
outputs: buildListOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Attio-Signature': 'hmac-sha256-signature',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { AttioIcon } from '@/components/icons'
|
||||
import { buildAttioTriggerSubBlocks, buildListOutputs } from '@/triggers/attio/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Attio List Deleted Trigger
|
||||
*
|
||||
* Triggers when a list is deleted in Attio.
|
||||
*/
|
||||
export const attioListDeletedTrigger: TriggerConfig = {
|
||||
id: 'attio_list_deleted',
|
||||
name: 'Attio List Deleted',
|
||||
provider: 'attio',
|
||||
description: 'Trigger workflow when a list is deleted in Attio',
|
||||
version: '1.0.0',
|
||||
icon: AttioIcon,
|
||||
|
||||
subBlocks: buildAttioTriggerSubBlocks('attio_list_deleted'),
|
||||
|
||||
outputs: buildListOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Attio-Signature': 'hmac-sha256-signature',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { AttioIcon } from '@/components/icons'
|
||||
import { buildAttioTriggerSubBlocks, buildListEntryOutputs } from '@/triggers/attio/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Attio List Entry Created Trigger
|
||||
*
|
||||
* Triggers when a list entry is created in Attio.
|
||||
*/
|
||||
export const attioListEntryCreatedTrigger: TriggerConfig = {
|
||||
id: 'attio_list_entry_created',
|
||||
name: 'Attio List Entry Created',
|
||||
provider: 'attio',
|
||||
description: 'Trigger workflow when a new list entry is created in Attio',
|
||||
version: '1.0.0',
|
||||
icon: AttioIcon,
|
||||
|
||||
subBlocks: buildAttioTriggerSubBlocks('attio_list_entry_created'),
|
||||
|
||||
outputs: buildListEntryOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Attio-Signature': 'hmac-sha256-signature',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { AttioIcon } from '@/components/icons'
|
||||
import { buildAttioTriggerSubBlocks, buildListEntryOutputs } from '@/triggers/attio/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Attio List Entry Deleted Trigger
|
||||
*
|
||||
* Triggers when a list entry is deleted in Attio.
|
||||
*/
|
||||
export const attioListEntryDeletedTrigger: TriggerConfig = {
|
||||
id: 'attio_list_entry_deleted',
|
||||
name: 'Attio List Entry Deleted',
|
||||
provider: 'attio',
|
||||
description: 'Trigger workflow when a list entry is deleted in Attio',
|
||||
version: '1.0.0',
|
||||
icon: AttioIcon,
|
||||
|
||||
subBlocks: buildAttioTriggerSubBlocks('attio_list_entry_deleted'),
|
||||
|
||||
outputs: buildListEntryOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Attio-Signature': 'hmac-sha256-signature',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { AttioIcon } from '@/components/icons'
|
||||
import { buildAttioTriggerSubBlocks, buildListEntryUpdatedOutputs } from '@/triggers/attio/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Attio List Entry Updated Trigger
|
||||
*
|
||||
* Triggers when a list entry is updated in Attio.
|
||||
*/
|
||||
export const attioListEntryUpdatedTrigger: TriggerConfig = {
|
||||
id: 'attio_list_entry_updated',
|
||||
name: 'Attio List Entry Updated',
|
||||
provider: 'attio',
|
||||
description: 'Trigger workflow when a list entry is updated in Attio',
|
||||
version: '1.0.0',
|
||||
icon: AttioIcon,
|
||||
|
||||
subBlocks: buildAttioTriggerSubBlocks('attio_list_entry_updated'),
|
||||
|
||||
outputs: buildListEntryUpdatedOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Attio-Signature': 'hmac-sha256-signature',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { AttioIcon } from '@/components/icons'
|
||||
import { buildAttioTriggerSubBlocks, buildListOutputs } from '@/triggers/attio/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Attio List Updated Trigger
|
||||
*
|
||||
* Triggers when a list is updated in Attio.
|
||||
*/
|
||||
export const attioListUpdatedTrigger: TriggerConfig = {
|
||||
id: 'attio_list_updated',
|
||||
name: 'Attio List Updated',
|
||||
provider: 'attio',
|
||||
description: 'Trigger workflow when a list is updated in Attio',
|
||||
version: '1.0.0',
|
||||
icon: AttioIcon,
|
||||
|
||||
subBlocks: buildAttioTriggerSubBlocks('attio_list_updated'),
|
||||
|
||||
outputs: buildListOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Attio-Signature': 'hmac-sha256-signature',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { AttioIcon } from '@/components/icons'
|
||||
import { buildAttioTriggerSubBlocks, buildNoteOutputs } from '@/triggers/attio/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Attio Note Created Trigger
|
||||
*
|
||||
* Triggers when a note is created in Attio.
|
||||
*/
|
||||
export const attioNoteCreatedTrigger: TriggerConfig = {
|
||||
id: 'attio_note_created',
|
||||
name: 'Attio Note Created',
|
||||
provider: 'attio',
|
||||
description: 'Trigger workflow when a new note is created in Attio',
|
||||
version: '1.0.0',
|
||||
icon: AttioIcon,
|
||||
|
||||
subBlocks: buildAttioTriggerSubBlocks('attio_note_created'),
|
||||
|
||||
outputs: buildNoteOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Attio-Signature': 'hmac-sha256-signature',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { AttioIcon } from '@/components/icons'
|
||||
import { buildAttioTriggerSubBlocks, buildNoteOutputs } from '@/triggers/attio/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Attio Note Deleted Trigger
|
||||
*
|
||||
* Triggers when a note is deleted in Attio.
|
||||
*/
|
||||
export const attioNoteDeletedTrigger: TriggerConfig = {
|
||||
id: 'attio_note_deleted',
|
||||
name: 'Attio Note Deleted',
|
||||
provider: 'attio',
|
||||
description: 'Trigger workflow when a note is deleted in Attio',
|
||||
version: '1.0.0',
|
||||
icon: AttioIcon,
|
||||
|
||||
subBlocks: buildAttioTriggerSubBlocks('attio_note_deleted'),
|
||||
|
||||
outputs: buildNoteOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Attio-Signature': 'hmac-sha256-signature',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { AttioIcon } from '@/components/icons'
|
||||
import { buildAttioTriggerSubBlocks, buildNoteOutputs } from '@/triggers/attio/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Attio Note Updated Trigger
|
||||
*
|
||||
* Triggers when a note is updated in Attio.
|
||||
*/
|
||||
export const attioNoteUpdatedTrigger: TriggerConfig = {
|
||||
id: 'attio_note_updated',
|
||||
name: 'Attio Note Updated',
|
||||
provider: 'attio',
|
||||
description: 'Trigger workflow when a note is updated in Attio',
|
||||
version: '1.0.0',
|
||||
icon: AttioIcon,
|
||||
|
||||
subBlocks: buildAttioTriggerSubBlocks('attio_note_updated'),
|
||||
|
||||
outputs: buildNoteOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Attio-Signature': 'hmac-sha256-signature',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import { AttioIcon } from '@/components/icons'
|
||||
import {
|
||||
attioTriggerOptions,
|
||||
buildAttioTriggerSubBlocks,
|
||||
buildRecordOutputs,
|
||||
} from '@/triggers/attio/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Attio Record Created Trigger
|
||||
*
|
||||
* This is the PRIMARY trigger - it includes the dropdown for selecting trigger type.
|
||||
* Triggers when a new record is created in Attio.
|
||||
*/
|
||||
export const attioRecordCreatedTrigger: TriggerConfig = {
|
||||
id: 'attio_record_created',
|
||||
name: 'Attio Record Created',
|
||||
provider: 'attio',
|
||||
description: 'Trigger workflow when a new record is created in Attio',
|
||||
version: '1.0.0',
|
||||
icon: AttioIcon,
|
||||
|
||||
subBlocks: [
|
||||
{
|
||||
id: 'selectedTriggerId',
|
||||
title: 'Trigger Type',
|
||||
type: 'dropdown',
|
||||
mode: 'trigger',
|
||||
options: attioTriggerOptions,
|
||||
value: () => 'attio_record_created',
|
||||
required: true,
|
||||
},
|
||||
...buildAttioTriggerSubBlocks('attio_record_created'),
|
||||
],
|
||||
|
||||
outputs: buildRecordOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Attio-Signature': 'hmac-sha256-signature',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { AttioIcon } from '@/components/icons'
|
||||
import { buildAttioTriggerSubBlocks, buildRecordOutputs } from '@/triggers/attio/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Attio Record Deleted Trigger
|
||||
*
|
||||
* Triggers when a record is deleted in Attio.
|
||||
*/
|
||||
export const attioRecordDeletedTrigger: TriggerConfig = {
|
||||
id: 'attio_record_deleted',
|
||||
name: 'Attio Record Deleted',
|
||||
provider: 'attio',
|
||||
description: 'Trigger workflow when a record is deleted in Attio',
|
||||
version: '1.0.0',
|
||||
icon: AttioIcon,
|
||||
|
||||
subBlocks: buildAttioTriggerSubBlocks('attio_record_deleted'),
|
||||
|
||||
outputs: buildRecordOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Attio-Signature': 'hmac-sha256-signature',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { AttioIcon } from '@/components/icons'
|
||||
import { buildAttioTriggerSubBlocks, buildRecordMergedEventOutputs } from '@/triggers/attio/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Attio Record Merged Trigger
|
||||
*
|
||||
* Triggers when two records are merged in Attio.
|
||||
*/
|
||||
export const attioRecordMergedTrigger: TriggerConfig = {
|
||||
id: 'attio_record_merged',
|
||||
name: 'Attio Record Merged',
|
||||
provider: 'attio',
|
||||
description: 'Trigger workflow when two records are merged in Attio',
|
||||
version: '1.0.0',
|
||||
icon: AttioIcon,
|
||||
|
||||
subBlocks: buildAttioTriggerSubBlocks('attio_record_merged'),
|
||||
|
||||
outputs: buildRecordMergedEventOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Attio-Signature': 'hmac-sha256-signature',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { AttioIcon } from '@/components/icons'
|
||||
import { buildAttioTriggerSubBlocks, buildRecordUpdatedOutputs } from '@/triggers/attio/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Attio Record Updated Trigger
|
||||
*
|
||||
* Triggers when a record is updated in Attio.
|
||||
*/
|
||||
export const attioRecordUpdatedTrigger: TriggerConfig = {
|
||||
id: 'attio_record_updated',
|
||||
name: 'Attio Record Updated',
|
||||
provider: 'attio',
|
||||
description: 'Trigger workflow when a record is updated in Attio',
|
||||
version: '1.0.0',
|
||||
icon: AttioIcon,
|
||||
|
||||
subBlocks: buildAttioTriggerSubBlocks('attio_record_updated'),
|
||||
|
||||
outputs: buildRecordUpdatedOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Attio-Signature': 'hmac-sha256-signature',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { AttioIcon } from '@/components/icons'
|
||||
import { buildAttioTriggerSubBlocks, buildTaskOutputs } from '@/triggers/attio/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Attio Task Created Trigger
|
||||
*
|
||||
* Triggers when a task is created in Attio.
|
||||
*/
|
||||
export const attioTaskCreatedTrigger: TriggerConfig = {
|
||||
id: 'attio_task_created',
|
||||
name: 'Attio Task Created',
|
||||
provider: 'attio',
|
||||
description: 'Trigger workflow when a new task is created in Attio',
|
||||
version: '1.0.0',
|
||||
icon: AttioIcon,
|
||||
|
||||
subBlocks: buildAttioTriggerSubBlocks('attio_task_created'),
|
||||
|
||||
outputs: buildTaskOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Attio-Signature': 'hmac-sha256-signature',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { AttioIcon } from '@/components/icons'
|
||||
import { buildAttioTriggerSubBlocks, buildTaskOutputs } from '@/triggers/attio/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Attio Task Deleted Trigger
|
||||
*
|
||||
* Triggers when a task is deleted in Attio.
|
||||
*/
|
||||
export const attioTaskDeletedTrigger: TriggerConfig = {
|
||||
id: 'attio_task_deleted',
|
||||
name: 'Attio Task Deleted',
|
||||
provider: 'attio',
|
||||
description: 'Trigger workflow when a task is deleted in Attio',
|
||||
version: '1.0.0',
|
||||
icon: AttioIcon,
|
||||
|
||||
subBlocks: buildAttioTriggerSubBlocks('attio_task_deleted'),
|
||||
|
||||
outputs: buildTaskOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Attio-Signature': 'hmac-sha256-signature',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { AttioIcon } from '@/components/icons'
|
||||
import { buildAttioTriggerSubBlocks, buildTaskOutputs } from '@/triggers/attio/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Attio Task Updated Trigger
|
||||
*
|
||||
* Triggers when a task is updated in Attio.
|
||||
*/
|
||||
export const attioTaskUpdatedTrigger: TriggerConfig = {
|
||||
id: 'attio_task_updated',
|
||||
name: 'Attio Task Updated',
|
||||
provider: 'attio',
|
||||
description: 'Trigger workflow when a task is updated in Attio',
|
||||
version: '1.0.0',
|
||||
icon: AttioIcon,
|
||||
|
||||
subBlocks: buildAttioTriggerSubBlocks('attio_task_updated'),
|
||||
|
||||
outputs: buildTaskOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Attio-Signature': 'hmac-sha256-signature',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,527 @@
|
||||
import type { SubBlockConfig } from '@/blocks/types'
|
||||
import type { TriggerOutput } from '@/triggers/types'
|
||||
|
||||
export const attioTriggerOptions = [
|
||||
{ label: 'Record Created', id: 'attio_record_created' },
|
||||
{ label: 'Record Updated', id: 'attio_record_updated' },
|
||||
{ label: 'Record Deleted', id: 'attio_record_deleted' },
|
||||
{ label: 'Record Merged', id: 'attio_record_merged' },
|
||||
{ label: 'Note Created', id: 'attio_note_created' },
|
||||
{ label: 'Note Updated', id: 'attio_note_updated' },
|
||||
{ label: 'Note Deleted', id: 'attio_note_deleted' },
|
||||
{ label: 'Task Created', id: 'attio_task_created' },
|
||||
{ label: 'Task Updated', id: 'attio_task_updated' },
|
||||
{ label: 'Task Deleted', id: 'attio_task_deleted' },
|
||||
{ label: 'Comment Created', id: 'attio_comment_created' },
|
||||
{ label: 'Comment Resolved', id: 'attio_comment_resolved' },
|
||||
{ label: 'Comment Unresolved', id: 'attio_comment_unresolved' },
|
||||
{ label: 'Comment Deleted', id: 'attio_comment_deleted' },
|
||||
{ label: 'List Entry Created', id: 'attio_list_entry_created' },
|
||||
{ label: 'List Entry Updated', id: 'attio_list_entry_updated' },
|
||||
{ label: 'List Entry Deleted', id: 'attio_list_entry_deleted' },
|
||||
{ label: 'List Created', id: 'attio_list_created' },
|
||||
{ label: 'List Updated', id: 'attio_list_updated' },
|
||||
{ label: 'List Deleted', id: 'attio_list_deleted' },
|
||||
{ label: 'Workspace Member Created', id: 'attio_workspace_member_created' },
|
||||
{ label: 'Generic Webhook (All Events)', id: 'attio_webhook' },
|
||||
]
|
||||
|
||||
export function attioSetupInstructions(): string {
|
||||
const instructions = [
|
||||
'<strong>Note:</strong> Webhooks are automatically created in Attio when you deploy this workflow, and deleted when you undeploy. See the <a href="https://docs.attio.com/rest-api/guides/webhooks" target="_blank" rel="noopener noreferrer">Attio webhook documentation</a> for details.',
|
||||
'Connect your <strong>Attio account</strong> using the credential selector above.',
|
||||
'<strong>Deploy</strong> the workflow — a webhook will be created automatically in your Attio workspace.',
|
||||
]
|
||||
|
||||
return instructions
|
||||
.map(
|
||||
(instruction, index) =>
|
||||
`<div class="mb-3">${index === 0 ? instruction : `<strong>${index}.</strong> ${instruction}`}</div>`
|
||||
)
|
||||
.join('')
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds subBlocks for an Attio trigger with OAuth credentials and automatic webhook lifecycle.
|
||||
* Used by both the primary trigger (with dropdown) and secondary triggers.
|
||||
*/
|
||||
export function buildAttioTriggerSubBlocks(triggerId: string): SubBlockConfig[] {
|
||||
return [
|
||||
{
|
||||
id: 'triggerCredentials',
|
||||
title: 'Attio Account',
|
||||
type: 'oauth-input',
|
||||
serviceId: 'attio',
|
||||
mode: 'trigger',
|
||||
required: true,
|
||||
condition: { field: 'selectedTriggerId', value: triggerId },
|
||||
},
|
||||
{
|
||||
id: 'triggerInstructions',
|
||||
title: 'Setup Instructions',
|
||||
hideFromPreview: true,
|
||||
type: 'text',
|
||||
defaultValue: attioSetupInstructions(),
|
||||
mode: 'trigger',
|
||||
condition: { field: 'selectedTriggerId', value: triggerId },
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* Base webhook outputs common to all Attio triggers.
|
||||
*/
|
||||
function buildBaseWebhookOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
eventType: {
|
||||
type: 'string',
|
||||
description: 'The type of event (e.g. record.created, note.created)',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Record event outputs for record triggers.
|
||||
*/
|
||||
function buildRecordIdOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
workspaceId: { type: 'string', description: 'The workspace ID' },
|
||||
objectId: { type: 'string', description: 'The object type ID (e.g. people, companies)' },
|
||||
recordId: { type: 'string', description: 'The record ID' },
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Record updated event outputs (includes attributeId).
|
||||
*/
|
||||
function buildRecordUpdatedIdOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
...buildRecordIdOutputs(),
|
||||
attributeId: {
|
||||
type: 'string',
|
||||
description: 'The ID of the attribute that was updated on the record',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Record merged event outputs.
|
||||
* Attio payload: id.record_id (winner), duplicate_object_id, duplicate_record_id (loser).
|
||||
*/
|
||||
function buildRecordMergedOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
workspaceId: { type: 'string', description: 'The workspace ID' },
|
||||
objectId: { type: 'string', description: 'The object type ID of the surviving record' },
|
||||
recordId: { type: 'string', description: 'The surviving record ID after merge' },
|
||||
duplicateObjectId: {
|
||||
type: 'string',
|
||||
description: 'The object type ID of the merged-away record',
|
||||
},
|
||||
duplicateRecordId: { type: 'string', description: 'The record ID that was merged away' },
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Note event outputs.
|
||||
*/
|
||||
function buildNoteIdOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
workspaceId: { type: 'string', description: 'The workspace ID' },
|
||||
noteId: { type: 'string', description: 'The note ID' },
|
||||
parentObjectId: { type: 'string', description: 'The parent object type ID' },
|
||||
parentRecordId: { type: 'string', description: 'The parent record ID' },
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Task event outputs.
|
||||
* Attio task webhook payloads only contain workspace_id and task_id.
|
||||
*/
|
||||
function buildTaskIdOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
workspaceId: { type: 'string', description: 'The workspace ID' },
|
||||
taskId: { type: 'string', description: 'The task ID' },
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Comment event outputs.
|
||||
* Attio payload uses object_id/record_id (not parent_*), plus list_id/entry_id.
|
||||
*/
|
||||
function buildCommentIdOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
workspaceId: { type: 'string', description: 'The workspace ID' },
|
||||
threadId: { type: 'string', description: 'The thread ID' },
|
||||
commentId: { type: 'string', description: 'The comment ID' },
|
||||
objectId: { type: 'string', description: 'The object type ID' },
|
||||
recordId: { type: 'string', description: 'The record ID' },
|
||||
listId: { type: 'string', description: 'The list ID (if comment is on a list entry)' },
|
||||
entryId: { type: 'string', description: 'The list entry ID (if comment is on a list entry)' },
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* List entry event outputs.
|
||||
*/
|
||||
function buildListEntryIdOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
workspaceId: { type: 'string', description: 'The workspace ID' },
|
||||
listId: { type: 'string', description: 'The list ID' },
|
||||
entryId: { type: 'string', description: 'The list entry ID' },
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* List entry updated event outputs (includes attributeId).
|
||||
*/
|
||||
function buildListEntryUpdatedIdOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
...buildListEntryIdOutputs(),
|
||||
attributeId: {
|
||||
type: 'string',
|
||||
description: 'The ID of the attribute that was updated on the list entry',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/** Record created/deleted outputs. */
|
||||
export function buildRecordOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
...buildBaseWebhookOutputs(),
|
||||
...buildRecordIdOutputs(),
|
||||
}
|
||||
}
|
||||
|
||||
/** Record updated outputs (includes attributeId). */
|
||||
export function buildRecordUpdatedOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
...buildBaseWebhookOutputs(),
|
||||
...buildRecordUpdatedIdOutputs(),
|
||||
}
|
||||
}
|
||||
|
||||
/** Record merged outputs. */
|
||||
export function buildRecordMergedEventOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
...buildBaseWebhookOutputs(),
|
||||
...buildRecordMergedOutputs(),
|
||||
}
|
||||
}
|
||||
|
||||
/** Note event outputs. */
|
||||
export function buildNoteOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
...buildBaseWebhookOutputs(),
|
||||
...buildNoteIdOutputs(),
|
||||
}
|
||||
}
|
||||
|
||||
/** Task event outputs. */
|
||||
export function buildTaskOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
...buildBaseWebhookOutputs(),
|
||||
...buildTaskIdOutputs(),
|
||||
}
|
||||
}
|
||||
|
||||
/** Comment event outputs. */
|
||||
export function buildCommentOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
...buildBaseWebhookOutputs(),
|
||||
...buildCommentIdOutputs(),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* List event outputs.
|
||||
*/
|
||||
function buildListIdOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
workspaceId: { type: 'string', description: 'The workspace ID' },
|
||||
listId: { type: 'string', description: 'The list ID' },
|
||||
}
|
||||
}
|
||||
|
||||
/** List created/updated/deleted outputs. */
|
||||
export function buildListOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
...buildBaseWebhookOutputs(),
|
||||
...buildListIdOutputs(),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Workspace member event outputs.
|
||||
*/
|
||||
function buildWorkspaceMemberIdOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
workspaceId: { type: 'string', description: 'The workspace ID' },
|
||||
workspaceMemberId: { type: 'string', description: 'The workspace member ID' },
|
||||
}
|
||||
}
|
||||
|
||||
/** Workspace member outputs. */
|
||||
export function buildWorkspaceMemberOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
...buildBaseWebhookOutputs(),
|
||||
...buildWorkspaceMemberIdOutputs(),
|
||||
}
|
||||
}
|
||||
|
||||
/** List entry created/deleted outputs. */
|
||||
export function buildListEntryOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
...buildBaseWebhookOutputs(),
|
||||
...buildListEntryIdOutputs(),
|
||||
}
|
||||
}
|
||||
|
||||
/** List entry updated outputs (includes attributeId). */
|
||||
export function buildListEntryUpdatedOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
...buildBaseWebhookOutputs(),
|
||||
...buildListEntryUpdatedIdOutputs(),
|
||||
}
|
||||
}
|
||||
|
||||
/** Generic webhook outputs covering all event types. */
|
||||
export function buildGenericWebhookOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
...buildBaseWebhookOutputs(),
|
||||
id: { type: 'json', description: 'The event ID object containing resource identifiers' },
|
||||
parentObjectId: {
|
||||
type: 'string',
|
||||
description: 'The parent object type ID (if applicable)',
|
||||
},
|
||||
parentRecordId: {
|
||||
type: 'string',
|
||||
description: 'The parent record ID (if applicable)',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps trigger IDs to the exact Attio event type strings.
|
||||
*/
|
||||
export const TRIGGER_EVENT_MAP: Record<string, string[]> = {
|
||||
attio_record_created: ['record.created'],
|
||||
attio_record_updated: ['record.updated'],
|
||||
attio_record_deleted: ['record.deleted'],
|
||||
attio_record_merged: ['record.merged'],
|
||||
attio_note_created: ['note.created'],
|
||||
attio_note_updated: ['note.updated', 'note-content.updated'],
|
||||
attio_note_deleted: ['note.deleted'],
|
||||
attio_task_created: ['task.created'],
|
||||
attio_task_updated: ['task.updated'],
|
||||
attio_task_deleted: ['task.deleted'],
|
||||
attio_comment_created: ['comment.created'],
|
||||
attio_comment_resolved: ['comment.resolved'],
|
||||
attio_comment_unresolved: ['comment.unresolved'],
|
||||
attio_comment_deleted: ['comment.deleted'],
|
||||
attio_list_entry_created: ['list-entry.created'],
|
||||
attio_list_entry_updated: ['list-entry.updated'],
|
||||
attio_list_entry_deleted: ['list-entry.deleted'],
|
||||
attio_list_created: ['list.created'],
|
||||
attio_list_updated: ['list.updated'],
|
||||
attio_list_deleted: ['list.deleted'],
|
||||
attio_workspace_member_created: ['workspace-member.created'],
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the first event from an Attio webhook payload.
|
||||
* Attio wraps events in an `events` array: `{ webhook_id, events: [{ event_type, id, ... }] }`.
|
||||
*/
|
||||
export function getAttioEvent(body: Record<string, unknown>): Record<string, unknown> | undefined {
|
||||
const events = body.events as Array<Record<string, unknown>> | undefined
|
||||
return events?.[0]
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an Attio webhook payload matches a trigger.
|
||||
*/
|
||||
export function isAttioPayloadMatch(triggerId: string, body: Record<string, unknown>): boolean {
|
||||
if (triggerId === 'attio_webhook') {
|
||||
return true
|
||||
}
|
||||
|
||||
const event = getAttioEvent(body)
|
||||
const eventType = event?.event_type as string | undefined
|
||||
if (!eventType) {
|
||||
return false
|
||||
}
|
||||
|
||||
const acceptedEvents = TRIGGER_EVENT_MAP[triggerId]
|
||||
return acceptedEvents ? acceptedEvents.includes(eventType) : false
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts formatted data from an Attio record event payload.
|
||||
* Used for record.created, record.deleted triggers.
|
||||
*/
|
||||
export function extractAttioRecordData(body: Record<string, unknown>): Record<string, unknown> {
|
||||
const event = getAttioEvent(body) ?? {}
|
||||
const id = (event.id as Record<string, unknown>) ?? {}
|
||||
return {
|
||||
eventType: event.event_type ?? null,
|
||||
workspaceId: id.workspace_id ?? null,
|
||||
objectId: id.object_id ?? null,
|
||||
recordId: id.record_id ?? null,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts formatted data from an Attio record.updated event payload.
|
||||
*/
|
||||
export function extractAttioRecordUpdatedData(
|
||||
body: Record<string, unknown>
|
||||
): Record<string, unknown> {
|
||||
const event = getAttioEvent(body) ?? {}
|
||||
const id = (event.id as Record<string, unknown>) ?? {}
|
||||
return {
|
||||
eventType: event.event_type ?? null,
|
||||
workspaceId: id.workspace_id ?? null,
|
||||
objectId: id.object_id ?? null,
|
||||
recordId: id.record_id ?? null,
|
||||
attributeId: id.attribute_id ?? null,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts formatted data from an Attio record.merged event payload.
|
||||
*/
|
||||
export function extractAttioRecordMergedData(
|
||||
body: Record<string, unknown>
|
||||
): Record<string, unknown> {
|
||||
const event = getAttioEvent(body) ?? {}
|
||||
const id = (event.id as Record<string, unknown>) ?? {}
|
||||
return {
|
||||
eventType: event.event_type ?? null,
|
||||
workspaceId: id.workspace_id ?? null,
|
||||
objectId: id.object_id ?? null,
|
||||
recordId: id.record_id ?? null,
|
||||
duplicateObjectId: (event.duplicate_object_id as string) ?? null,
|
||||
duplicateRecordId: (event.duplicate_record_id as string) ?? null,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts formatted data from an Attio note event payload.
|
||||
*/
|
||||
export function extractAttioNoteData(body: Record<string, unknown>): Record<string, unknown> {
|
||||
const event = getAttioEvent(body) ?? {}
|
||||
const id = (event.id as Record<string, unknown>) ?? {}
|
||||
return {
|
||||
eventType: event.event_type ?? null,
|
||||
workspaceId: id.workspace_id ?? null,
|
||||
noteId: id.note_id ?? null,
|
||||
parentObjectId: (event.parent_object_id as string) ?? null,
|
||||
parentRecordId: (event.parent_record_id as string) ?? null,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts formatted data from an Attio task event payload.
|
||||
*/
|
||||
export function extractAttioTaskData(body: Record<string, unknown>): Record<string, unknown> {
|
||||
const event = getAttioEvent(body) ?? {}
|
||||
const id = (event.id as Record<string, unknown>) ?? {}
|
||||
return {
|
||||
eventType: event.event_type ?? null,
|
||||
workspaceId: id.workspace_id ?? null,
|
||||
taskId: id.task_id ?? null,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts formatted data from an Attio comment event payload.
|
||||
*/
|
||||
export function extractAttioCommentData(body: Record<string, unknown>): Record<string, unknown> {
|
||||
const event = getAttioEvent(body) ?? {}
|
||||
const id = (event.id as Record<string, unknown>) ?? {}
|
||||
return {
|
||||
eventType: event.event_type ?? null,
|
||||
workspaceId: id.workspace_id ?? null,
|
||||
threadId: (event.thread_id as string) ?? null,
|
||||
commentId: id.comment_id ?? null,
|
||||
objectId: (event.object_id as string) ?? null,
|
||||
recordId: (event.record_id as string) ?? null,
|
||||
listId: (event.list_id as string) ?? null,
|
||||
entryId: (event.entry_id as string) ?? null,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts formatted data from an Attio list-entry event payload.
|
||||
* Used for list-entry.created, list-entry.deleted triggers.
|
||||
*/
|
||||
export function extractAttioListEntryData(body: Record<string, unknown>): Record<string, unknown> {
|
||||
const event = getAttioEvent(body) ?? {}
|
||||
const id = (event.id as Record<string, unknown>) ?? {}
|
||||
return {
|
||||
eventType: event.event_type ?? null,
|
||||
workspaceId: id.workspace_id ?? null,
|
||||
listId: id.list_id ?? null,
|
||||
entryId: id.entry_id ?? null,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts formatted data from an Attio list-entry.updated event payload.
|
||||
*/
|
||||
export function extractAttioListEntryUpdatedData(
|
||||
body: Record<string, unknown>
|
||||
): Record<string, unknown> {
|
||||
const event = getAttioEvent(body) ?? {}
|
||||
const id = (event.id as Record<string, unknown>) ?? {}
|
||||
return {
|
||||
eventType: event.event_type ?? null,
|
||||
workspaceId: id.workspace_id ?? null,
|
||||
listId: id.list_id ?? null,
|
||||
entryId: id.entry_id ?? null,
|
||||
attributeId: id.attribute_id ?? null,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts formatted data from an Attio list event payload.
|
||||
* Used for list.created, list.updated, list.deleted triggers.
|
||||
*/
|
||||
export function extractAttioListData(body: Record<string, unknown>): Record<string, unknown> {
|
||||
const event = getAttioEvent(body) ?? {}
|
||||
const id = (event.id as Record<string, unknown>) ?? {}
|
||||
return {
|
||||
eventType: event.event_type ?? null,
|
||||
workspaceId: id.workspace_id ?? null,
|
||||
listId: id.list_id ?? null,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts formatted data from an Attio workspace-member.created event payload.
|
||||
*/
|
||||
export function extractAttioWorkspaceMemberData(
|
||||
body: Record<string, unknown>
|
||||
): Record<string, unknown> {
|
||||
const event = getAttioEvent(body) ?? {}
|
||||
const id = (event.id as Record<string, unknown>) ?? {}
|
||||
return {
|
||||
eventType: event.event_type ?? null,
|
||||
workspaceId: id.workspace_id ?? null,
|
||||
workspaceMemberId: id.workspace_member_id ?? null,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts formatted data from a generic Attio webhook payload.
|
||||
* Passes through the first event with camelCase field mapping.
|
||||
*/
|
||||
export function extractAttioGenericData(body: Record<string, unknown>): Record<string, unknown> {
|
||||
const event = getAttioEvent(body) ?? {}
|
||||
const id = (event.id as Record<string, unknown>) ?? {}
|
||||
return {
|
||||
eventType: event.event_type ?? null,
|
||||
id,
|
||||
parentObjectId: (event.parent_object_id as string) ?? null,
|
||||
parentRecordId: (event.parent_record_id as string) ?? null,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { AttioIcon } from '@/components/icons'
|
||||
import { buildAttioTriggerSubBlocks, buildGenericWebhookOutputs } from '@/triggers/attio/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Generic Attio Webhook Trigger
|
||||
*
|
||||
* Captures all Attio webhook events without filtering.
|
||||
*/
|
||||
export const attioWebhookTrigger: TriggerConfig = {
|
||||
id: 'attio_webhook',
|
||||
name: 'Attio Webhook (All Events)',
|
||||
provider: 'attio',
|
||||
description: 'Trigger workflow on any Attio webhook event',
|
||||
version: '1.0.0',
|
||||
icon: AttioIcon,
|
||||
|
||||
subBlocks: buildAttioTriggerSubBlocks('attio_webhook'),
|
||||
|
||||
outputs: buildGenericWebhookOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Attio-Signature': 'hmac-sha256-signature',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { AttioIcon } from '@/components/icons'
|
||||
import { buildAttioTriggerSubBlocks, buildWorkspaceMemberOutputs } from '@/triggers/attio/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Attio Workspace Member Created Trigger
|
||||
*
|
||||
* Triggers when a new member is added to the Attio workspace.
|
||||
*/
|
||||
export const attioWorkspaceMemberCreatedTrigger: TriggerConfig = {
|
||||
id: 'attio_workspace_member_created',
|
||||
name: 'Attio Workspace Member Created',
|
||||
provider: 'attio',
|
||||
description: 'Trigger workflow when a new member is added to the Attio workspace',
|
||||
version: '1.0.0',
|
||||
icon: AttioIcon,
|
||||
|
||||
subBlocks: buildAttioTriggerSubBlocks('attio_workspace_member_created'),
|
||||
|
||||
outputs: buildWorkspaceMemberOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Attio-Signature': 'hmac-sha256-signature',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { AzureIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
azureDevOpsTriggerOptions,
|
||||
buildBuildFailedOutputs,
|
||||
buildFailedSetupInstructions,
|
||||
} from '@/triggers/azure_devops/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
export const azureDevOpsBuildFailedTrigger: TriggerConfig = {
|
||||
id: 'azure_devops_build_failed',
|
||||
name: 'Azure DevOps Build Failed',
|
||||
provider: 'azure_devops',
|
||||
description:
|
||||
'Trigger workflow when an Azure DevOps build fails, is canceled, or partially succeeds',
|
||||
version: '1.0.0',
|
||||
icon: AzureIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'azure_devops_build_failed',
|
||||
triggerOptions: azureDevOpsTriggerOptions,
|
||||
includeDropdown: true,
|
||||
setupInstructions: buildFailedSetupInstructions,
|
||||
}),
|
||||
|
||||
outputs: buildBuildFailedOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export { azureDevOpsBuildFailedTrigger } from './build_failed'
|
||||
export { azureDevOpsWebhookTrigger } from './webhook'
|
||||
export { azureDevOpsWorkItemCreatedTrigger } from './work_item_created'
|
||||
@@ -0,0 +1,283 @@
|
||||
import type { TriggerOutput } from '@/triggers/types'
|
||||
|
||||
export const azureDevOpsTriggerOptions = [
|
||||
{ label: 'Build Failed', id: 'azure_devops_build_failed' },
|
||||
{ label: 'Work Item Created', id: 'azure_devops_work_item_created' },
|
||||
{ label: 'All Service Hook Events', id: 'azure_devops_webhook' },
|
||||
]
|
||||
|
||||
export const AZURE_DEVOPS_BUILD_FAILED_EVENT = 'build.complete'
|
||||
export const AZURE_DEVOPS_WORK_ITEM_CREATED_EVENT = 'workitem.created'
|
||||
|
||||
function instructions(steps: string[]): string {
|
||||
return steps.map((s, i) => `<div class="mb-3"><strong>${i + 1}.</strong> ${s}</div>`).join('')
|
||||
}
|
||||
|
||||
export const buildFailedSetupInstructions = instructions([
|
||||
'Open your Azure DevOps project and go to <strong>Project settings → Service hooks</strong>.',
|
||||
'Click <strong>+ Create subscription</strong>, choose <strong>Web Hooks</strong>, then <strong>Next</strong>.',
|
||||
'For <strong>Trigger on this type of event</strong>, select <strong>Build completed</strong>.',
|
||||
'Under <strong>Filters</strong>, set <strong>Build result</strong> to <strong>Failed</strong> (optionally add Canceled / Partially succeeded).',
|
||||
'Click <strong>Next</strong>, paste the <strong>Webhook URL</strong> above into the <strong>URL</strong> field.',
|
||||
'Leave other fields as defaults. Click <strong>Test</strong> to verify, then <strong>Finish</strong>.',
|
||||
])
|
||||
|
||||
export const workItemCreatedSetupInstructions = instructions([
|
||||
'Open your Azure DevOps project and go to <strong>Project settings → Service hooks</strong>.',
|
||||
'Click <strong>+ Create subscription</strong>, choose <strong>Web Hooks</strong>, then <strong>Next</strong>.',
|
||||
'For <strong>Trigger on this type of event</strong>, select <strong>Work item created</strong>.',
|
||||
'Click <strong>Next</strong>, paste the <strong>Webhook URL</strong> above into the <strong>URL</strong> field.',
|
||||
'Leave other fields as defaults. Click <strong>Test</strong> to verify, then <strong>Finish</strong>.',
|
||||
])
|
||||
|
||||
export const webhookSetupInstructions = instructions([
|
||||
'Open your Azure DevOps project and go to <strong>Project settings → Service hooks</strong>.',
|
||||
'Click <strong>+ Create subscription</strong>, choose <strong>Web Hooks</strong>, then <strong>Next</strong>.',
|
||||
'Select whichever <strong>event types</strong> you want this URL to receive (build, work item, release, etc.).',
|
||||
'Click <strong>Next</strong>, paste the <strong>Webhook URL</strong> above into the <strong>URL</strong> field.',
|
||||
'Leave other fields as defaults. Click <strong>Test</strong> to verify, then <strong>Finish</strong>.',
|
||||
'Sim does not filter deliveries for this trigger — configure event types in Azure DevOps.',
|
||||
])
|
||||
|
||||
/**
|
||||
* Returns whether an Azure DevOps service hook payload matches the configured trigger.
|
||||
*/
|
||||
export function isAzureDevOpsEventMatch(triggerId: string, body: Record<string, unknown>): boolean {
|
||||
if (triggerId === 'azure_devops_webhook') {
|
||||
return true
|
||||
}
|
||||
|
||||
const eventType = body.eventType as string | undefined
|
||||
|
||||
if (triggerId === 'azure_devops_build_failed') {
|
||||
if (eventType !== AZURE_DEVOPS_BUILD_FAILED_EVENT) {
|
||||
return false
|
||||
}
|
||||
const resource = body.resource as Record<string, unknown> | undefined
|
||||
const result = (resource?.result as string | undefined)?.toLowerCase()
|
||||
return (
|
||||
result === 'failed' ||
|
||||
result === 'canceled' ||
|
||||
result === 'cancelled' ||
|
||||
result === 'stopped' ||
|
||||
result === 'partiallysucceeded'
|
||||
)
|
||||
}
|
||||
|
||||
if (triggerId === 'azure_devops_work_item_created') {
|
||||
return eventType === AZURE_DEVOPS_WORK_ITEM_CREATED_EVENT
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
export function buildBuildFailedOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
buildId: {
|
||||
type: 'number',
|
||||
description: 'Build ID',
|
||||
},
|
||||
buildNumber: {
|
||||
type: 'string',
|
||||
description: 'Build number string (e.g. 20240101.1)',
|
||||
},
|
||||
result: {
|
||||
type: 'string',
|
||||
description: 'Build result: failed | canceled | partiallySucceeded',
|
||||
},
|
||||
pipelineId: {
|
||||
type: 'number',
|
||||
description: 'Pipeline definition ID',
|
||||
},
|
||||
pipelineName: {
|
||||
type: 'string',
|
||||
description: 'Pipeline definition name',
|
||||
},
|
||||
projectName: {
|
||||
type: 'string',
|
||||
description: 'Azure DevOps project name',
|
||||
},
|
||||
branch: {
|
||||
type: 'string',
|
||||
description: 'Source branch name (refs/heads/ prefix stripped)',
|
||||
},
|
||||
commitSha: {
|
||||
type: 'string',
|
||||
description: 'Source commit SHA',
|
||||
},
|
||||
triggeredBy: {
|
||||
type: 'string',
|
||||
description: 'Display name of the person who triggered the build',
|
||||
},
|
||||
triggeredByEmail: {
|
||||
type: 'string',
|
||||
description: 'Email/unique name of the person who triggered the build, or null if not set',
|
||||
},
|
||||
startTime: {
|
||||
type: 'string',
|
||||
description: 'Build start time (ISO 8601)',
|
||||
},
|
||||
finishTime: {
|
||||
type: 'string',
|
||||
description: 'Build finish time (ISO 8601)',
|
||||
},
|
||||
buildUrl: {
|
||||
type: 'string',
|
||||
description: 'API URL for the build resource',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export function buildWorkItemCreatedOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
workItemId: {
|
||||
type: 'number',
|
||||
description: 'Work item ID',
|
||||
},
|
||||
workItemType: {
|
||||
type: 'string',
|
||||
description: 'Work item type for Basic process (e.g. Issue, Task, Epic)',
|
||||
},
|
||||
title: {
|
||||
type: 'string',
|
||||
description: 'Work item title',
|
||||
},
|
||||
state: {
|
||||
type: 'string',
|
||||
description: 'Work item state for Basic process (e.g. To Do, Doing, Done)',
|
||||
},
|
||||
createdBy: {
|
||||
type: 'string',
|
||||
description: 'Display name of the creator, or null if not set',
|
||||
},
|
||||
assignedTo: {
|
||||
type: 'string',
|
||||
description: 'Assignee display name, or null if unassigned',
|
||||
},
|
||||
priority: {
|
||||
type: 'number',
|
||||
description: 'Priority (1–4), or 0 if not set',
|
||||
},
|
||||
areaPath: {
|
||||
type: 'string',
|
||||
description: 'Area path',
|
||||
},
|
||||
iterationPath: {
|
||||
type: 'string',
|
||||
description: 'Iteration path',
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
description: 'Work item description (HTML), or null if not set',
|
||||
},
|
||||
projectName: {
|
||||
type: 'string',
|
||||
description: 'Azure DevOps project name',
|
||||
},
|
||||
workItemUrl: {
|
||||
type: 'string',
|
||||
description: 'API URL for the work item resource',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export function buildWebhookOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
eventType: {
|
||||
type: 'string',
|
||||
description: 'Service hook event type (e.g. build.complete, workitem.created)',
|
||||
},
|
||||
notificationId: {
|
||||
type: 'number',
|
||||
description: 'Notification ID',
|
||||
},
|
||||
subscriptionId: {
|
||||
type: 'string',
|
||||
description: 'Service hook subscription ID',
|
||||
},
|
||||
publisherId: {
|
||||
type: 'string',
|
||||
description: 'Publisher ID (e.g. tfs)',
|
||||
},
|
||||
createdDate: {
|
||||
type: 'string',
|
||||
description: 'Event creation time (ISO 8601)',
|
||||
},
|
||||
resource: {
|
||||
type: 'json',
|
||||
description: 'Event resource payload',
|
||||
},
|
||||
resourceContainers: {
|
||||
type: 'json',
|
||||
description: 'Resource container references (project, collection, etc.)',
|
||||
},
|
||||
message: {
|
||||
type: 'json',
|
||||
description: 'Short message object',
|
||||
},
|
||||
detailedMessage: {
|
||||
type: 'json',
|
||||
description: 'Detailed message object',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export function formatBuildCompleteInput(body: Record<string, unknown>): Record<string, unknown> {
|
||||
const resource = (body.resource ?? {}) as Record<string, unknown>
|
||||
const definition = (resource.definition ?? {}) as Record<string, unknown>
|
||||
const project = (resource.project ?? {}) as Record<string, unknown>
|
||||
const requestedFor = (resource.requestedFor ?? {}) as Record<string, unknown>
|
||||
const sourceBranch = (resource.sourceBranch as string) ?? ''
|
||||
|
||||
return {
|
||||
buildId: Number(resource.id ?? 0),
|
||||
buildNumber: (resource.buildNumber as string) ?? '',
|
||||
result: (resource.result as string) ?? '',
|
||||
pipelineId: Number(definition.id ?? 0),
|
||||
pipelineName: (definition.name as string) ?? '',
|
||||
projectName: (project.name as string) ?? '',
|
||||
branch: sourceBranch.replace(/^refs\/heads\//, ''),
|
||||
commitSha: (resource.sourceVersion as string) ?? '',
|
||||
triggeredBy: (requestedFor.displayName as string) ?? null,
|
||||
triggeredByEmail: (requestedFor.uniqueName as string) ?? null,
|
||||
startTime: (resource.startTime as string) ?? '',
|
||||
finishTime: (resource.finishTime as string) ?? '',
|
||||
buildUrl: (resource.url as string) ?? '',
|
||||
}
|
||||
}
|
||||
|
||||
export function formatWorkItemCreatedInput(body: Record<string, unknown>): Record<string, unknown> {
|
||||
const resource = (body.resource ?? {}) as Record<string, unknown>
|
||||
const fields = (resource.fields ?? {}) as Record<string, unknown>
|
||||
|
||||
return {
|
||||
workItemId: Number(resource.id ?? 0),
|
||||
workItemType: (fields['System.WorkItemType'] as string) ?? '',
|
||||
title: (fields['System.Title'] as string) ?? '',
|
||||
state: (fields['System.State'] as string) ?? '',
|
||||
createdBy:
|
||||
(fields['System.CreatedBy'] as { displayName?: string } | undefined)?.displayName ?? null,
|
||||
assignedTo:
|
||||
(fields['System.AssignedTo'] as { displayName?: string } | undefined)?.displayName ?? null,
|
||||
priority: Number(fields['Microsoft.VSTS.Common.Priority'] ?? 0),
|
||||
areaPath: (fields['System.AreaPath'] as string) ?? '',
|
||||
iterationPath: (fields['System.IterationPath'] as string) ?? '',
|
||||
description: (fields['System.Description'] as string) ?? null,
|
||||
projectName: (fields['System.TeamProject'] as string) ?? '',
|
||||
workItemUrl: (resource.url as string) ?? '',
|
||||
}
|
||||
}
|
||||
|
||||
export function formatWebhookEnvelopeInput(body: Record<string, unknown>): Record<string, unknown> {
|
||||
return {
|
||||
eventType: (body.eventType as string) ?? '',
|
||||
notificationId: Number(body.notificationId ?? 0),
|
||||
subscriptionId: (body.subscriptionId as string) ?? '',
|
||||
publisherId: (body.publisherId as string) ?? '',
|
||||
createdDate: (body.createdDate as string) ?? '',
|
||||
resource: body.resource ?? null,
|
||||
resourceContainers: body.resourceContainers ?? null,
|
||||
message: body.message ?? null,
|
||||
detailedMessage: body.detailedMessage ?? null,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import { AzureIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
azureDevOpsTriggerOptions,
|
||||
buildWebhookOutputs,
|
||||
webhookSetupInstructions,
|
||||
} from '@/triggers/azure_devops/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Azure DevOps generic webhook trigger.
|
||||
* Event filtering is determined by which events you enable on the service hook subscription.
|
||||
*/
|
||||
export const azureDevOpsWebhookTrigger: TriggerConfig = {
|
||||
id: 'azure_devops_webhook',
|
||||
name: 'Azure DevOps Webhook (All Service Hook Events)',
|
||||
provider: 'azure_devops',
|
||||
description:
|
||||
'Trigger on whichever service hook event types you configure in Azure DevOps. Sim does not filter deliveries for this trigger.',
|
||||
version: '1.0.0',
|
||||
icon: AzureIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'azure_devops_webhook',
|
||||
triggerOptions: azureDevOpsTriggerOptions,
|
||||
setupInstructions: webhookSetupInstructions,
|
||||
}),
|
||||
|
||||
outputs: buildWebhookOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import { AzureIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
azureDevOpsTriggerOptions,
|
||||
buildWorkItemCreatedOutputs,
|
||||
workItemCreatedSetupInstructions,
|
||||
} from '@/triggers/azure_devops/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
export const azureDevOpsWorkItemCreatedTrigger: TriggerConfig = {
|
||||
id: 'azure_devops_work_item_created',
|
||||
name: 'Azure DevOps Work Item Created',
|
||||
provider: 'azure_devops',
|
||||
description: 'Trigger workflow when a work item is created in Azure DevOps',
|
||||
version: '1.0.0',
|
||||
icon: AzureIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'azure_devops_work_item_created',
|
||||
triggerOptions: azureDevOpsTriggerOptions,
|
||||
setupInstructions: workItemCreatedSetupInstructions,
|
||||
}),
|
||||
|
||||
outputs: buildWorkItemCreatedOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { CalComIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildCancelledOutputs,
|
||||
calcomSetupInstructions,
|
||||
calcomTriggerOptions,
|
||||
calcomWebhookSecretField,
|
||||
} from '@/triggers/calcom/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
export const calcomBookingCancelledTrigger: TriggerConfig = {
|
||||
id: 'calcom_booking_cancelled',
|
||||
name: 'CalCom Booking Cancelled',
|
||||
provider: 'calcom',
|
||||
description: 'Trigger workflow when a booking is cancelled in Cal.com',
|
||||
version: '1.0.0',
|
||||
icon: CalComIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'calcom_booking_cancelled',
|
||||
triggerOptions: calcomTriggerOptions,
|
||||
setupInstructions: calcomSetupInstructions('cancelled'),
|
||||
extraFields: [calcomWebhookSecretField('calcom_booking_cancelled')],
|
||||
}),
|
||||
|
||||
outputs: buildCancelledOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Cal-Signature-256': '<hmac-sha256-hex>',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { CalComIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildBookingOutputs,
|
||||
calcomSetupInstructions,
|
||||
calcomTriggerOptions,
|
||||
calcomWebhookSecretField,
|
||||
} from '@/triggers/calcom/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
export const calcomBookingCreatedTrigger: TriggerConfig = {
|
||||
id: 'calcom_booking_created',
|
||||
name: 'CalCom Booking Created',
|
||||
provider: 'calcom',
|
||||
description: 'Trigger workflow when a new booking is created in Cal.com',
|
||||
version: '1.0.0',
|
||||
icon: CalComIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'calcom_booking_created',
|
||||
triggerOptions: calcomTriggerOptions,
|
||||
includeDropdown: true,
|
||||
setupInstructions: calcomSetupInstructions('created'),
|
||||
extraFields: [calcomWebhookSecretField('calcom_booking_created')],
|
||||
}),
|
||||
|
||||
outputs: buildBookingOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Cal-Signature-256': '<hmac-sha256-hex>',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { CalComIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildPaidOutputs,
|
||||
calcomSetupInstructions,
|
||||
calcomTriggerOptions,
|
||||
calcomWebhookSecretField,
|
||||
} from '@/triggers/calcom/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
export const calcomBookingPaidTrigger: TriggerConfig = {
|
||||
id: 'calcom_booking_paid',
|
||||
name: 'CalCom Booking Paid',
|
||||
provider: 'calcom',
|
||||
description: 'Trigger workflow when payment is completed for a paid booking',
|
||||
version: '1.0.0',
|
||||
icon: CalComIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'calcom_booking_paid',
|
||||
triggerOptions: calcomTriggerOptions,
|
||||
setupInstructions: calcomSetupInstructions('paid'),
|
||||
extraFields: [calcomWebhookSecretField('calcom_booking_paid')],
|
||||
}),
|
||||
|
||||
outputs: buildPaidOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Cal-Signature-256': '<hmac-sha256-hex>',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { CalComIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildRejectedOutputs,
|
||||
calcomSetupInstructions,
|
||||
calcomTriggerOptions,
|
||||
calcomWebhookSecretField,
|
||||
} from '@/triggers/calcom/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
export const calcomBookingRejectedTrigger: TriggerConfig = {
|
||||
id: 'calcom_booking_rejected',
|
||||
name: 'CalCom Booking Rejected',
|
||||
provider: 'calcom',
|
||||
description: 'Trigger workflow when a booking request is rejected by the host',
|
||||
version: '1.0.0',
|
||||
icon: CalComIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'calcom_booking_rejected',
|
||||
triggerOptions: calcomTriggerOptions,
|
||||
setupInstructions: calcomSetupInstructions('rejected'),
|
||||
extraFields: [calcomWebhookSecretField('calcom_booking_rejected')],
|
||||
}),
|
||||
|
||||
outputs: buildRejectedOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Cal-Signature-256': '<hmac-sha256-hex>',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { CalComIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildRequestedOutputs,
|
||||
calcomSetupInstructions,
|
||||
calcomTriggerOptions,
|
||||
calcomWebhookSecretField,
|
||||
} from '@/triggers/calcom/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
export const calcomBookingRequestedTrigger: TriggerConfig = {
|
||||
id: 'calcom_booking_requested',
|
||||
name: 'CalCom Booking Requested',
|
||||
provider: 'calcom',
|
||||
description: 'Trigger workflow when a booking request is submitted (pending confirmation)',
|
||||
version: '1.0.0',
|
||||
icon: CalComIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'calcom_booking_requested',
|
||||
triggerOptions: calcomTriggerOptions,
|
||||
setupInstructions: calcomSetupInstructions('requested'),
|
||||
extraFields: [calcomWebhookSecretField('calcom_booking_requested')],
|
||||
}),
|
||||
|
||||
outputs: buildRequestedOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Cal-Signature-256': '<hmac-sha256-hex>',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { CalComIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildRescheduledOutputs,
|
||||
calcomSetupInstructions,
|
||||
calcomTriggerOptions,
|
||||
calcomWebhookSecretField,
|
||||
} from '@/triggers/calcom/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
export const calcomBookingRescheduledTrigger: TriggerConfig = {
|
||||
id: 'calcom_booking_rescheduled',
|
||||
name: 'CalCom Booking Rescheduled',
|
||||
provider: 'calcom',
|
||||
description: 'Trigger workflow when a booking is rescheduled in Cal.com',
|
||||
version: '1.0.0',
|
||||
icon: CalComIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'calcom_booking_rescheduled',
|
||||
triggerOptions: calcomTriggerOptions,
|
||||
setupInstructions: calcomSetupInstructions('rescheduled'),
|
||||
extraFields: [calcomWebhookSecretField('calcom_booking_rescheduled')],
|
||||
}),
|
||||
|
||||
outputs: buildRescheduledOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Cal-Signature-256': '<hmac-sha256-hex>',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
export { calcomBookingCancelledTrigger } from './booking_cancelled'
|
||||
export { calcomBookingCreatedTrigger } from './booking_created'
|
||||
export { calcomBookingPaidTrigger } from './booking_paid'
|
||||
export { calcomBookingRejectedTrigger } from './booking_rejected'
|
||||
export { calcomBookingRequestedTrigger } from './booking_requested'
|
||||
export { calcomBookingRescheduledTrigger } from './booking_rescheduled'
|
||||
export { calcomMeetingEndedTrigger } from './meeting_ended'
|
||||
export { calcomRecordingReadyTrigger } from './recording_ready'
|
||||
export { calcomWebhookTrigger } from './webhook'
|
||||
@@ -0,0 +1,35 @@
|
||||
import { CalComIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildMeetingEndedOutputs,
|
||||
calcomSetupInstructions,
|
||||
calcomTriggerOptions,
|
||||
calcomWebhookSecretField,
|
||||
} from '@/triggers/calcom/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
export const calcomMeetingEndedTrigger: TriggerConfig = {
|
||||
id: 'calcom_meeting_ended',
|
||||
name: 'CalCom Meeting Ended',
|
||||
provider: 'calcom',
|
||||
description: 'Trigger workflow when a Cal.com meeting ends',
|
||||
version: '1.0.0',
|
||||
icon: CalComIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'calcom_meeting_ended',
|
||||
triggerOptions: calcomTriggerOptions,
|
||||
setupInstructions: calcomSetupInstructions('meeting_ended'),
|
||||
extraFields: [calcomWebhookSecretField('calcom_meeting_ended')],
|
||||
}),
|
||||
|
||||
outputs: buildMeetingEndedOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Cal-Signature-256': '<hmac-sha256-hex>',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { CalComIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildRecordingReadyOutputs,
|
||||
calcomSetupInstructions,
|
||||
calcomTriggerOptions,
|
||||
calcomWebhookSecretField,
|
||||
} from '@/triggers/calcom/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
export const calcomRecordingReadyTrigger: TriggerConfig = {
|
||||
id: 'calcom_recording_ready',
|
||||
name: 'CalCom Recording Ready',
|
||||
provider: 'calcom',
|
||||
description: 'Trigger workflow when a meeting recording is ready for download',
|
||||
version: '1.0.0',
|
||||
icon: CalComIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'calcom_recording_ready',
|
||||
triggerOptions: calcomTriggerOptions,
|
||||
setupInstructions: calcomSetupInstructions('recording_ready'),
|
||||
extraFields: [calcomWebhookSecretField('calcom_recording_ready')],
|
||||
}),
|
||||
|
||||
outputs: buildRecordingReadyOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Cal-Signature-256': '<hmac-sha256-hex>',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,664 @@
|
||||
import type { SubBlockConfig } from '@/blocks/types'
|
||||
import type { TriggerOutput } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Shared output property definitions for Cal.com trigger payloads.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Organizer output definition with destructured properties
|
||||
*/
|
||||
const ORGANIZER_OUTPUT: TriggerOutput = {
|
||||
type: 'object',
|
||||
description: 'Organizer details',
|
||||
properties: {
|
||||
id: { type: 'number', description: 'Organizer user ID' },
|
||||
name: { type: 'string', description: 'Organizer name' },
|
||||
email: { type: 'string', description: 'Organizer email' },
|
||||
username: { type: 'string', description: 'Organizer username' },
|
||||
timeZone: { type: 'string', description: 'Organizer timezone' },
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Attendees array output definition with destructured items
|
||||
*/
|
||||
const ATTENDEES_TRIGGER_OUTPUT: TriggerOutput = {
|
||||
type: 'array',
|
||||
description: 'List of attendees',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string', description: 'Attendee name' },
|
||||
email: { type: 'string', description: 'Attendee email' },
|
||||
timeZone: { type: 'string', description: 'Attendee timezone' },
|
||||
language: { type: 'string', description: 'Attendee language preference' },
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const calcomTriggerOptions = [
|
||||
{ label: 'Booking Created', id: 'calcom_booking_created' },
|
||||
{ label: 'Booking Cancelled', id: 'calcom_booking_cancelled' },
|
||||
{ label: 'Booking Rescheduled', id: 'calcom_booking_rescheduled' },
|
||||
{ label: 'Booking Requested', id: 'calcom_booking_requested' },
|
||||
{ label: 'Booking Rejected', id: 'calcom_booking_rejected' },
|
||||
{ label: 'Booking Paid', id: 'calcom_booking_paid' },
|
||||
{ label: 'Meeting Ended', id: 'calcom_meeting_ended' },
|
||||
{ label: 'Recording Ready', id: 'calcom_recording_ready' },
|
||||
{ label: 'Generic Webhook (All Events)', id: 'calcom_webhook' },
|
||||
]
|
||||
|
||||
/**
|
||||
* Creates the webhook secret field subBlock for a CalCom trigger
|
||||
*/
|
||||
export function calcomWebhookSecretField(triggerId: string): SubBlockConfig {
|
||||
return {
|
||||
id: 'webhookSecret',
|
||||
title: 'Webhook Secret',
|
||||
type: 'short-input',
|
||||
placeholder: 'Enter the same secret you configured in Cal.com',
|
||||
description: 'Used to verify webhook requests via X-Cal-Signature-256 header.',
|
||||
password: true,
|
||||
required: false,
|
||||
mode: 'trigger',
|
||||
condition: {
|
||||
field: 'selectedTriggerId',
|
||||
value: triggerId,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Event type configuration for setup instructions
|
||||
*/
|
||||
type CalcomEventType =
|
||||
| 'created'
|
||||
| 'cancelled'
|
||||
| 'rescheduled'
|
||||
| 'requested'
|
||||
| 'rejected'
|
||||
| 'paid'
|
||||
| 'meeting_ended'
|
||||
| 'recording_ready'
|
||||
| 'generic'
|
||||
|
||||
/**
|
||||
* Generates setup instructions HTML for CalCom triggers
|
||||
*/
|
||||
export function calcomSetupInstructions(eventType: CalcomEventType): string {
|
||||
const eventDescriptions: Record<CalcomEventType, string> = {
|
||||
created: 'This webhook triggers when a new booking is created.',
|
||||
cancelled: 'This webhook triggers when a booking is cancelled.',
|
||||
rescheduled: 'This webhook triggers when a booking is rescheduled.',
|
||||
requested:
|
||||
'This webhook triggers when a booking request is submitted (for event types requiring confirmation).',
|
||||
rejected: 'This webhook triggers when a booking request is rejected by the host.',
|
||||
paid: 'This webhook triggers when payment is completed for a paid booking.',
|
||||
meeting_ended: 'This webhook triggers when a meeting ends.',
|
||||
recording_ready: 'This webhook triggers when a meeting recording is ready for download.',
|
||||
generic: 'This webhook can receive any Cal.com event type you configure.',
|
||||
}
|
||||
|
||||
const eventNames: Record<CalcomEventType, string> = {
|
||||
created: 'BOOKING_CREATED',
|
||||
cancelled: 'BOOKING_CANCELLED',
|
||||
rescheduled: 'BOOKING_RESCHEDULED',
|
||||
requested: 'BOOKING_REQUESTED',
|
||||
rejected: 'BOOKING_REJECTED',
|
||||
paid: 'BOOKING_PAID',
|
||||
meeting_ended: 'MEETING_ENDED',
|
||||
recording_ready: 'RECORDING_READY',
|
||||
generic: 'your desired event type(s)',
|
||||
}
|
||||
|
||||
return [
|
||||
'Copy the webhook URL above.',
|
||||
'Go to your <a href="https://app.cal.com/settings/developer/webhooks" target="_blank" rel="noopener noreferrer">Cal.com Webhook Settings</a>.',
|
||||
'Click "New Webhook" and paste the URL.',
|
||||
`Select the <strong>${eventNames[eventType]}</strong> event trigger.`,
|
||||
eventDescriptions[eventType],
|
||||
'If you add a secret key in Cal.com, enter the same secret in the <strong>Webhook Secret</strong> field above to verify webhook authenticity.',
|
||||
]
|
||||
.map(
|
||||
(instruction, index) =>
|
||||
`<div class="mb-3"><strong>${index + 1}.</strong> ${instruction}</div>`
|
||||
)
|
||||
.join('')
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds common booking outputs for CalCom triggers
|
||||
*/
|
||||
export function buildBookingOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
triggerEvent: {
|
||||
type: 'string',
|
||||
description: 'The webhook event type',
|
||||
},
|
||||
createdAt: {
|
||||
type: 'string',
|
||||
description: 'When the webhook event was created (ISO 8601)',
|
||||
},
|
||||
payload: {
|
||||
title: {
|
||||
type: 'string',
|
||||
description: 'Booking title',
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
description: 'Booking description',
|
||||
},
|
||||
eventTypeId: {
|
||||
type: 'number',
|
||||
description: 'Event type ID',
|
||||
},
|
||||
startTime: {
|
||||
type: 'string',
|
||||
description: 'Booking start time (ISO 8601)',
|
||||
},
|
||||
endTime: {
|
||||
type: 'string',
|
||||
description: 'Booking end time (ISO 8601)',
|
||||
},
|
||||
uid: {
|
||||
type: 'string',
|
||||
description: 'Unique booking identifier',
|
||||
},
|
||||
bookingId: {
|
||||
type: 'number',
|
||||
description: 'Numeric booking ID',
|
||||
},
|
||||
status: {
|
||||
type: 'string',
|
||||
description: 'Booking status',
|
||||
},
|
||||
location: {
|
||||
type: 'string',
|
||||
description: 'Meeting location or URL',
|
||||
},
|
||||
organizer: ORGANIZER_OUTPUT,
|
||||
attendees: ATTENDEES_TRIGGER_OUTPUT,
|
||||
responses: {
|
||||
type: 'json',
|
||||
description:
|
||||
'Booking form responses (dynamic - fields depend on your event type configuration)',
|
||||
},
|
||||
metadata: {
|
||||
type: 'json',
|
||||
description:
|
||||
'Custom metadata attached to the booking (dynamic - user-defined key-value pairs)',
|
||||
},
|
||||
videoCallData: {
|
||||
type: 'json',
|
||||
description: 'Video call details (structure varies by provider)',
|
||||
},
|
||||
},
|
||||
} as any
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds outputs specific to cancelled bookings
|
||||
*/
|
||||
export function buildCancelledOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
triggerEvent: {
|
||||
type: 'string',
|
||||
description: 'The webhook event type',
|
||||
},
|
||||
createdAt: {
|
||||
type: 'string',
|
||||
description: 'When the webhook event was created (ISO 8601)',
|
||||
},
|
||||
payload: {
|
||||
title: {
|
||||
type: 'string',
|
||||
description: 'Booking title',
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
description: 'Booking description',
|
||||
},
|
||||
eventTypeId: {
|
||||
type: 'number',
|
||||
description: 'Event type ID',
|
||||
},
|
||||
startTime: {
|
||||
type: 'string',
|
||||
description: 'Booking start time (ISO 8601)',
|
||||
},
|
||||
endTime: {
|
||||
type: 'string',
|
||||
description: 'Booking end time (ISO 8601)',
|
||||
},
|
||||
uid: {
|
||||
type: 'string',
|
||||
description: 'Unique booking identifier',
|
||||
},
|
||||
bookingId: {
|
||||
type: 'number',
|
||||
description: 'Numeric booking ID',
|
||||
},
|
||||
status: {
|
||||
type: 'string',
|
||||
description: 'Booking status',
|
||||
},
|
||||
location: {
|
||||
type: 'string',
|
||||
description: 'Meeting location or URL',
|
||||
},
|
||||
cancellationReason: {
|
||||
type: 'string',
|
||||
description: 'Reason for cancellation',
|
||||
},
|
||||
organizer: ORGANIZER_OUTPUT,
|
||||
attendees: ATTENDEES_TRIGGER_OUTPUT,
|
||||
responses: {
|
||||
type: 'json',
|
||||
description: 'Booking form responses',
|
||||
},
|
||||
metadata: {
|
||||
type: 'json',
|
||||
description: 'Custom metadata attached to the booking',
|
||||
},
|
||||
},
|
||||
} as any
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds outputs specific to rescheduled bookings
|
||||
*/
|
||||
export function buildRescheduledOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
triggerEvent: {
|
||||
type: 'string',
|
||||
description: 'The webhook event type',
|
||||
},
|
||||
createdAt: {
|
||||
type: 'string',
|
||||
description: 'When the webhook event was created (ISO 8601)',
|
||||
},
|
||||
payload: {
|
||||
title: {
|
||||
type: 'string',
|
||||
description: 'Booking title',
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
description: 'Booking description',
|
||||
},
|
||||
eventTypeId: {
|
||||
type: 'number',
|
||||
description: 'Event type ID',
|
||||
},
|
||||
startTime: {
|
||||
type: 'string',
|
||||
description: 'New booking start time (ISO 8601)',
|
||||
},
|
||||
endTime: {
|
||||
type: 'string',
|
||||
description: 'New booking end time (ISO 8601)',
|
||||
},
|
||||
uid: {
|
||||
type: 'string',
|
||||
description: 'Unique booking identifier',
|
||||
},
|
||||
bookingId: {
|
||||
type: 'number',
|
||||
description: 'Numeric booking ID',
|
||||
},
|
||||
status: {
|
||||
type: 'string',
|
||||
description: 'Booking status',
|
||||
},
|
||||
location: {
|
||||
type: 'string',
|
||||
description: 'Meeting location or URL',
|
||||
},
|
||||
rescheduleId: {
|
||||
type: 'number',
|
||||
description: 'Previous booking ID',
|
||||
},
|
||||
rescheduleUid: {
|
||||
type: 'string',
|
||||
description: 'Previous booking UID',
|
||||
},
|
||||
rescheduleStartTime: {
|
||||
type: 'string',
|
||||
description: 'Original start time (ISO 8601)',
|
||||
},
|
||||
rescheduleEndTime: {
|
||||
type: 'string',
|
||||
description: 'Original end time (ISO 8601)',
|
||||
},
|
||||
organizer: ORGANIZER_OUTPUT,
|
||||
attendees: ATTENDEES_TRIGGER_OUTPUT,
|
||||
responses: {
|
||||
type: 'json',
|
||||
description: 'Booking form responses',
|
||||
},
|
||||
metadata: {
|
||||
type: 'json',
|
||||
description: 'Custom metadata attached to the booking',
|
||||
},
|
||||
},
|
||||
} as any
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds outputs for booking requested events (pending confirmation)
|
||||
*/
|
||||
export function buildRequestedOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
triggerEvent: {
|
||||
type: 'string',
|
||||
description: 'The webhook event type (BOOKING_REQUESTED)',
|
||||
},
|
||||
createdAt: {
|
||||
type: 'string',
|
||||
description: 'When the webhook event was created (ISO 8601)',
|
||||
},
|
||||
payload: {
|
||||
title: {
|
||||
type: 'string',
|
||||
description: 'Booking title',
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
description: 'Booking description',
|
||||
},
|
||||
eventTypeId: {
|
||||
type: 'number',
|
||||
description: 'Event type ID',
|
||||
},
|
||||
startTime: {
|
||||
type: 'string',
|
||||
description: 'Requested start time (ISO 8601)',
|
||||
},
|
||||
endTime: {
|
||||
type: 'string',
|
||||
description: 'Requested end time (ISO 8601)',
|
||||
},
|
||||
uid: {
|
||||
type: 'string',
|
||||
description: 'Unique booking identifier',
|
||||
},
|
||||
bookingId: {
|
||||
type: 'number',
|
||||
description: 'Numeric booking ID',
|
||||
},
|
||||
status: {
|
||||
type: 'string',
|
||||
description: 'Booking status (pending)',
|
||||
},
|
||||
location: {
|
||||
type: 'string',
|
||||
description: 'Meeting location or URL',
|
||||
},
|
||||
organizer: ORGANIZER_OUTPUT,
|
||||
attendees: ATTENDEES_TRIGGER_OUTPUT,
|
||||
responses: {
|
||||
type: 'json',
|
||||
description: 'Booking form responses',
|
||||
},
|
||||
metadata: {
|
||||
type: 'json',
|
||||
description: 'Custom metadata attached to the booking',
|
||||
},
|
||||
},
|
||||
} as any
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds outputs for booking rejected events
|
||||
*/
|
||||
export function buildRejectedOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
triggerEvent: {
|
||||
type: 'string',
|
||||
description: 'The webhook event type (BOOKING_REJECTED)',
|
||||
},
|
||||
createdAt: {
|
||||
type: 'string',
|
||||
description: 'When the webhook event was created (ISO 8601)',
|
||||
},
|
||||
payload: {
|
||||
title: {
|
||||
type: 'string',
|
||||
description: 'Booking title',
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
description: 'Booking description',
|
||||
},
|
||||
eventTypeId: {
|
||||
type: 'number',
|
||||
description: 'Event type ID',
|
||||
},
|
||||
startTime: {
|
||||
type: 'string',
|
||||
description: 'Requested start time (ISO 8601)',
|
||||
},
|
||||
endTime: {
|
||||
type: 'string',
|
||||
description: 'Requested end time (ISO 8601)',
|
||||
},
|
||||
uid: {
|
||||
type: 'string',
|
||||
description: 'Unique booking identifier',
|
||||
},
|
||||
bookingId: {
|
||||
type: 'number',
|
||||
description: 'Numeric booking ID',
|
||||
},
|
||||
status: {
|
||||
type: 'string',
|
||||
description: 'Booking status (rejected)',
|
||||
},
|
||||
rejectionReason: {
|
||||
type: 'string',
|
||||
description: 'Reason for rejection provided by host',
|
||||
},
|
||||
organizer: ORGANIZER_OUTPUT,
|
||||
attendees: ATTENDEES_TRIGGER_OUTPUT,
|
||||
metadata: {
|
||||
type: 'json',
|
||||
description: 'Custom metadata attached to the booking',
|
||||
},
|
||||
},
|
||||
} as any
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds outputs for booking paid events
|
||||
*/
|
||||
export function buildPaidOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
triggerEvent: {
|
||||
type: 'string',
|
||||
description: 'The webhook event type (BOOKING_PAID)',
|
||||
},
|
||||
createdAt: {
|
||||
type: 'string',
|
||||
description: 'When the webhook event was created (ISO 8601)',
|
||||
},
|
||||
payload: {
|
||||
title: {
|
||||
type: 'string',
|
||||
description: 'Booking title',
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
description: 'Booking description',
|
||||
},
|
||||
eventTypeId: {
|
||||
type: 'number',
|
||||
description: 'Event type ID',
|
||||
},
|
||||
startTime: {
|
||||
type: 'string',
|
||||
description: 'Booking start time (ISO 8601)',
|
||||
},
|
||||
endTime: {
|
||||
type: 'string',
|
||||
description: 'Booking end time (ISO 8601)',
|
||||
},
|
||||
uid: {
|
||||
type: 'string',
|
||||
description: 'Unique booking identifier',
|
||||
},
|
||||
bookingId: {
|
||||
type: 'number',
|
||||
description: 'Numeric booking ID',
|
||||
},
|
||||
status: {
|
||||
type: 'string',
|
||||
description: 'Booking status',
|
||||
},
|
||||
location: {
|
||||
type: 'string',
|
||||
description: 'Meeting location or URL',
|
||||
},
|
||||
payment: {
|
||||
type: 'object',
|
||||
description: 'Payment details',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Payment ID' },
|
||||
amount: { type: 'number', description: 'Payment amount' },
|
||||
currency: { type: 'string', description: 'Payment currency' },
|
||||
success: { type: 'boolean', description: 'Whether payment succeeded' },
|
||||
},
|
||||
},
|
||||
organizer: ORGANIZER_OUTPUT,
|
||||
attendees: ATTENDEES_TRIGGER_OUTPUT,
|
||||
metadata: {
|
||||
type: 'json',
|
||||
description: 'Custom metadata attached to the booking',
|
||||
},
|
||||
},
|
||||
} as any
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds outputs for meeting ended events
|
||||
*/
|
||||
export function buildMeetingEndedOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
triggerEvent: {
|
||||
type: 'string',
|
||||
description: 'The webhook event type (MEETING_ENDED)',
|
||||
},
|
||||
createdAt: {
|
||||
type: 'string',
|
||||
description: 'When the webhook event was created (ISO 8601)',
|
||||
},
|
||||
payload: {
|
||||
title: {
|
||||
type: 'string',
|
||||
description: 'Meeting title',
|
||||
},
|
||||
eventTypeId: {
|
||||
type: 'number',
|
||||
description: 'Event type ID',
|
||||
},
|
||||
startTime: {
|
||||
type: 'string',
|
||||
description: 'Meeting start time (ISO 8601)',
|
||||
},
|
||||
endTime: {
|
||||
type: 'string',
|
||||
description: 'Meeting end time (ISO 8601)',
|
||||
},
|
||||
uid: {
|
||||
type: 'string',
|
||||
description: 'Unique booking identifier',
|
||||
},
|
||||
bookingId: {
|
||||
type: 'number',
|
||||
description: 'Numeric booking ID',
|
||||
},
|
||||
duration: {
|
||||
type: 'number',
|
||||
description: 'Actual meeting duration in minutes',
|
||||
},
|
||||
organizer: ORGANIZER_OUTPUT,
|
||||
attendees: ATTENDEES_TRIGGER_OUTPUT,
|
||||
videoCallData: {
|
||||
type: 'json',
|
||||
description: 'Video call details',
|
||||
},
|
||||
},
|
||||
} as any
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds outputs for recording ready events
|
||||
*/
|
||||
export function buildRecordingReadyOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
triggerEvent: {
|
||||
type: 'string',
|
||||
description: 'The webhook event type (RECORDING_READY)',
|
||||
},
|
||||
createdAt: {
|
||||
type: 'string',
|
||||
description: 'When the webhook event was created (ISO 8601)',
|
||||
},
|
||||
payload: {
|
||||
title: {
|
||||
type: 'string',
|
||||
description: 'Meeting title',
|
||||
},
|
||||
eventTypeId: {
|
||||
type: 'number',
|
||||
description: 'Event type ID',
|
||||
},
|
||||
startTime: {
|
||||
type: 'string',
|
||||
description: 'Meeting start time (ISO 8601)',
|
||||
},
|
||||
endTime: {
|
||||
type: 'string',
|
||||
description: 'Meeting end time (ISO 8601)',
|
||||
},
|
||||
uid: {
|
||||
type: 'string',
|
||||
description: 'Unique booking identifier',
|
||||
},
|
||||
bookingId: {
|
||||
type: 'number',
|
||||
description: 'Numeric booking ID',
|
||||
},
|
||||
recordingUrl: {
|
||||
type: 'string',
|
||||
description: 'URL to download the recording',
|
||||
},
|
||||
transcription: {
|
||||
type: 'string',
|
||||
description: 'Meeting transcription text (if available)',
|
||||
},
|
||||
organizer: ORGANIZER_OUTPUT,
|
||||
attendees: ATTENDEES_TRIGGER_OUTPUT,
|
||||
},
|
||||
} as any
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds outputs for generic webhook (any event type)
|
||||
*/
|
||||
export function buildGenericOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
triggerEvent: {
|
||||
type: 'string',
|
||||
description: 'The webhook event type (e.g., BOOKING_CREATED, MEETING_ENDED)',
|
||||
},
|
||||
createdAt: {
|
||||
type: 'string',
|
||||
description: 'When the webhook event was created (ISO 8601)',
|
||||
},
|
||||
payload: {
|
||||
type: 'json',
|
||||
description: 'Complete webhook payload (structure varies by event type)',
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import { CalComIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildGenericOutputs,
|
||||
calcomSetupInstructions,
|
||||
calcomTriggerOptions,
|
||||
calcomWebhookSecretField,
|
||||
} from '@/triggers/calcom/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Generic Cal.com webhook trigger that accepts any event type.
|
||||
* Use this when you need to handle events not covered by specific triggers,
|
||||
* or when you want to receive multiple event types on the same webhook.
|
||||
*/
|
||||
export const calcomWebhookTrigger: TriggerConfig = {
|
||||
id: 'calcom_webhook',
|
||||
name: 'CalCom Webhook (All Events)',
|
||||
provider: 'calcom',
|
||||
description: 'Trigger workflow on any Cal.com webhook event (configure event types in Cal.com)',
|
||||
version: '1.0.0',
|
||||
icon: CalComIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'calcom_webhook',
|
||||
triggerOptions: calcomTriggerOptions,
|
||||
setupInstructions: calcomSetupInstructions('generic'),
|
||||
extraFields: [calcomWebhookSecretField('calcom_webhook')],
|
||||
}),
|
||||
|
||||
outputs: buildGenericOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Cal-Signature-256': '<hmac-sha256-hex>',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export { calendlyInviteeCanceledTrigger } from './invitee_canceled'
|
||||
export { calendlyInviteeCreatedTrigger } from './invitee_created'
|
||||
export { calendlyRoutingFormSubmittedTrigger } from './routing_form_submitted'
|
||||
export { calendlyWebhookTrigger } from './webhook'
|
||||
@@ -0,0 +1,76 @@
|
||||
import { CalendlyIcon } from '@/components/icons'
|
||||
import { buildInviteeOutputs } from '@/triggers/calendly/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
export const calendlyInviteeCanceledTrigger: TriggerConfig = {
|
||||
id: 'calendly_invitee_canceled',
|
||||
name: 'Calendly Invitee Canceled',
|
||||
provider: 'calendly',
|
||||
description: 'Trigger workflow when someone cancels a scheduled event on Calendly',
|
||||
version: '1.0.0',
|
||||
icon: CalendlyIcon,
|
||||
|
||||
subBlocks: [
|
||||
{
|
||||
id: 'apiKey',
|
||||
title: 'Personal Access Token',
|
||||
type: 'short-input',
|
||||
placeholder: 'Enter your Calendly personal access token',
|
||||
password: true,
|
||||
required: true,
|
||||
mode: 'trigger',
|
||||
condition: {
|
||||
field: 'selectedTriggerId',
|
||||
value: 'calendly_invitee_canceled',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'organization',
|
||||
title: 'Organization URI',
|
||||
type: 'short-input',
|
||||
placeholder: 'https://api.calendly.com/organizations/XXXXXX',
|
||||
description:
|
||||
'Organization URI for the webhook subscription. Get this from "Get Current User" operation.',
|
||||
required: true,
|
||||
mode: 'trigger',
|
||||
condition: {
|
||||
field: 'selectedTriggerId',
|
||||
value: 'calendly_invitee_canceled',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'triggerInstructions',
|
||||
title: 'Setup Instructions',
|
||||
hideFromPreview: true,
|
||||
type: 'text',
|
||||
defaultValue: [
|
||||
'<strong>Note:</strong> This trigger requires a paid Calendly subscription (Professional, Teams, or Enterprise plan).',
|
||||
'Get your Personal Access Token from <strong>Settings > Integrations > API & Webhooks</strong> in your Calendly account.',
|
||||
'Use the "Get Current User" operation in a Calendly block to retrieve your Organization URI.',
|
||||
'The webhook will be automatically created in Calendly when you deploy the workflow.',
|
||||
'This webhook triggers when an invitee cancels an event. The payload includes cancellation details and reason.',
|
||||
]
|
||||
.map(
|
||||
(instruction, index) =>
|
||||
`<div class="mb-3"><strong>${index + 1}.</strong> ${instruction}</div>`
|
||||
)
|
||||
.join(''),
|
||||
mode: 'trigger',
|
||||
condition: {
|
||||
field: 'selectedTriggerId',
|
||||
value: 'calendly_invitee_canceled',
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
outputs: buildInviteeOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Calendly-Webhook-Signature': 'v1,signature...',
|
||||
'User-Agent': 'Calendly-Webhook',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
import { CalendlyIcon } from '@/components/icons'
|
||||
import { buildInviteeOutputs, calendlyTriggerOptions } from '@/triggers/calendly/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
export const calendlyInviteeCreatedTrigger: TriggerConfig = {
|
||||
id: 'calendly_invitee_created',
|
||||
name: 'Calendly Invitee Created',
|
||||
provider: 'calendly',
|
||||
description: 'Trigger workflow when someone schedules a new event on Calendly',
|
||||
version: '1.0.0',
|
||||
icon: CalendlyIcon,
|
||||
|
||||
subBlocks: [
|
||||
{
|
||||
id: 'selectedTriggerId',
|
||||
title: 'Trigger Type',
|
||||
type: 'dropdown',
|
||||
mode: 'trigger',
|
||||
options: calendlyTriggerOptions,
|
||||
value: () => 'calendly_invitee_created',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'apiKey',
|
||||
title: 'Personal Access Token',
|
||||
type: 'short-input',
|
||||
placeholder: 'Enter your Calendly personal access token',
|
||||
password: true,
|
||||
required: true,
|
||||
mode: 'trigger',
|
||||
condition: {
|
||||
field: 'selectedTriggerId',
|
||||
value: 'calendly_invitee_created',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'organization',
|
||||
title: 'Organization URI',
|
||||
type: 'short-input',
|
||||
placeholder: 'https://api.calendly.com/organizations/XXXXXX',
|
||||
description:
|
||||
'Organization URI for the webhook subscription. Get this from "Get Current User" operation.',
|
||||
required: true,
|
||||
mode: 'trigger',
|
||||
condition: {
|
||||
field: 'selectedTriggerId',
|
||||
value: 'calendly_invitee_created',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'triggerInstructions',
|
||||
title: 'Setup Instructions',
|
||||
hideFromPreview: true,
|
||||
type: 'text',
|
||||
defaultValue: [
|
||||
'<strong>Note:</strong> This trigger requires a paid Calendly subscription (Professional, Teams, or Enterprise plan).',
|
||||
'Get your Personal Access Token from <strong>Settings > Integrations > API & Webhooks</strong> in your Calendly account.',
|
||||
'Use the "Get Current User" operation in a Calendly block to retrieve your Organization URI.',
|
||||
'The webhook will be automatically created in Calendly when you deploy the workflow.',
|
||||
'This webhook triggers when an invitee schedules a new event. Rescheduling triggers both cancellation and creation events.',
|
||||
]
|
||||
.map(
|
||||
(instruction, index) =>
|
||||
`<div class="mb-3"><strong>${index + 1}.</strong> ${instruction}</div>`
|
||||
)
|
||||
.join(''),
|
||||
mode: 'trigger',
|
||||
condition: {
|
||||
field: 'selectedTriggerId',
|
||||
value: 'calendly_invitee_created',
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
outputs: buildInviteeOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Calendly-Webhook-Signature': 'v1,signature...',
|
||||
'User-Agent': 'Calendly-Webhook',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
import { CalendlyIcon } from '@/components/icons'
|
||||
import { buildRoutingFormOutputs } from '@/triggers/calendly/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
export const calendlyRoutingFormSubmittedTrigger: TriggerConfig = {
|
||||
id: 'calendly_routing_form_submitted',
|
||||
name: 'Calendly Routing Form Submitted',
|
||||
provider: 'calendly',
|
||||
description: 'Trigger workflow when someone submits a Calendly routing form',
|
||||
version: '1.0.0',
|
||||
icon: CalendlyIcon,
|
||||
|
||||
subBlocks: [
|
||||
{
|
||||
id: 'apiKey',
|
||||
title: 'Personal Access Token',
|
||||
type: 'short-input',
|
||||
placeholder: 'Enter your Calendly personal access token',
|
||||
password: true,
|
||||
required: true,
|
||||
mode: 'trigger',
|
||||
condition: {
|
||||
field: 'selectedTriggerId',
|
||||
value: 'calendly_routing_form_submitted',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'organization',
|
||||
title: 'Organization URI',
|
||||
type: 'short-input',
|
||||
placeholder: 'https://api.calendly.com/organizations/XXXXXX',
|
||||
description:
|
||||
'Organization URI for the webhook subscription. Get this from "Get Current User" operation.',
|
||||
required: true,
|
||||
mode: 'trigger',
|
||||
condition: {
|
||||
field: 'selectedTriggerId',
|
||||
value: 'calendly_routing_form_submitted',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'triggerInstructions',
|
||||
title: 'Setup Instructions',
|
||||
hideFromPreview: true,
|
||||
type: 'text',
|
||||
defaultValue: [
|
||||
'<strong>Note:</strong> This trigger requires a paid Calendly subscription (Professional, Teams, or Enterprise plan).',
|
||||
'Get your Personal Access Token from <strong>Settings > Integrations > API & Webhooks</strong> in your Calendly account.',
|
||||
'Use the "Get Current User" operation in a Calendly block to retrieve your Organization URI.',
|
||||
'The webhook will be automatically created in Calendly when you deploy the workflow.',
|
||||
'This webhook triggers when someone submits a routing form, regardless of whether they book an event.',
|
||||
]
|
||||
.map(
|
||||
(instruction, index) =>
|
||||
`<div class="mb-3"><strong>${index + 1}.</strong> ${instruction}</div>`
|
||||
)
|
||||
.join(''),
|
||||
mode: 'trigger',
|
||||
condition: {
|
||||
field: 'selectedTriggerId',
|
||||
value: 'calendly_routing_form_submitted',
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
outputs: buildRoutingFormOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Calendly-Webhook-Signature': 'v1,signature...',
|
||||
'User-Agent': 'Calendly-Webhook',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,341 @@
|
||||
import type { TriggerOutput } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Shared trigger dropdown options for all Calendly triggers
|
||||
*/
|
||||
export const calendlyTriggerOptions = [
|
||||
{ label: 'Invitee Created', id: 'calendly_invitee_created' },
|
||||
{ label: 'Invitee Canceled', id: 'calendly_invitee_canceled' },
|
||||
{ label: 'Routing Form Submitted', id: 'calendly_routing_form_submitted' },
|
||||
{ label: 'General Webhook (All Events)', id: 'calendly_webhook' },
|
||||
]
|
||||
|
||||
/**
|
||||
* Generate setup instructions for a specific Calendly event type
|
||||
*/
|
||||
export function calendlySetupInstructions(eventType: string, additionalNotes?: string): string {
|
||||
const instructions = [
|
||||
'<strong>Note:</strong> Webhooks require a paid Calendly subscription (Professional, Teams, or Enterprise plan).',
|
||||
'<strong>Important:</strong> Calendly does not provide a UI for creating webhooks. You must create them programmatically using the API. See the <a href="https://developer.calendly.com/api-docs" target="_blank" rel="noopener noreferrer">Calendly Developer documentation</a> for details.',
|
||||
'Get your Calendly <strong>Personal Access Token</strong> from the Calendly dashboard under <strong>Integrations > API & Webhooks</strong>.',
|
||||
'In your workflow, add a Calendly block and select the <strong>"Create Webhook"</strong> operation.',
|
||||
'Enter your Personal Access Token in the Calendly block.',
|
||||
'Copy the <strong>Webhook URL</strong> shown above and paste it into the webhook URL field in the Create Webhook operation.',
|
||||
`Select the event types to monitor. For this trigger, select <strong>${eventType}</strong>.`,
|
||||
'Set the scope to <strong>Organization</strong> or <strong>User</strong> as needed (routing form submissions require organization scope).',
|
||||
'Run the workflow to create the webhook subscription. You can use the "List Webhooks" operation to verify it was created.',
|
||||
]
|
||||
|
||||
if (additionalNotes) {
|
||||
instructions.push(additionalNotes)
|
||||
}
|
||||
|
||||
return instructions
|
||||
.map(
|
||||
(instruction, index) =>
|
||||
`<div class="mb-3">${index === 0 ? instruction : `<strong>${index}.</strong> ${instruction}`}</div>`
|
||||
)
|
||||
.join('')
|
||||
}
|
||||
|
||||
/**
|
||||
* Shared tracking output schema
|
||||
*/
|
||||
export const trackingOutputs = {
|
||||
utm_campaign: {
|
||||
type: 'string',
|
||||
description: 'UTM campaign parameter',
|
||||
},
|
||||
utm_source: {
|
||||
type: 'string',
|
||||
description: 'UTM source parameter',
|
||||
},
|
||||
utm_medium: {
|
||||
type: 'string',
|
||||
description: 'UTM medium parameter',
|
||||
},
|
||||
utm_content: {
|
||||
type: 'string',
|
||||
description: 'UTM content parameter',
|
||||
},
|
||||
utm_term: {
|
||||
type: 'string',
|
||||
description: 'UTM term parameter',
|
||||
},
|
||||
salesforce_uuid: {
|
||||
type: 'string',
|
||||
description: 'Salesforce UUID',
|
||||
},
|
||||
} as const
|
||||
|
||||
/**
|
||||
* Shared questions and answers output schema
|
||||
*/
|
||||
export const questionsAndAnswersOutputs = {
|
||||
type: 'array',
|
||||
description: 'Questions and answers from the booking form',
|
||||
items: {
|
||||
question: {
|
||||
type: 'string',
|
||||
description: 'Question text',
|
||||
},
|
||||
answer: {
|
||||
type: 'string',
|
||||
description: 'Answer text',
|
||||
},
|
||||
},
|
||||
} as const
|
||||
|
||||
/**
|
||||
* Build output schema for invitee events
|
||||
*/
|
||||
export function buildInviteeOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
event: {
|
||||
type: 'string',
|
||||
description: 'Event type (invitee.created or invitee.canceled)',
|
||||
},
|
||||
created_at: {
|
||||
type: 'string',
|
||||
description: 'Webhook event creation timestamp',
|
||||
},
|
||||
created_by: {
|
||||
type: 'string',
|
||||
description: 'URI of the Calendly user who created this webhook',
|
||||
},
|
||||
payload: {
|
||||
uri: {
|
||||
type: 'string',
|
||||
description: 'Invitee URI',
|
||||
},
|
||||
email: {
|
||||
type: 'string',
|
||||
description: 'Invitee email address',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
description: 'Invitee full name',
|
||||
},
|
||||
first_name: {
|
||||
type: 'string',
|
||||
description: 'Invitee first name',
|
||||
},
|
||||
last_name: {
|
||||
type: 'string',
|
||||
description: 'Invitee last name',
|
||||
},
|
||||
status: {
|
||||
type: 'string',
|
||||
description: 'Invitee status (active or canceled)',
|
||||
},
|
||||
timezone: {
|
||||
type: 'string',
|
||||
description: 'Invitee timezone',
|
||||
},
|
||||
event: {
|
||||
type: 'string',
|
||||
description: 'Scheduled event URI',
|
||||
},
|
||||
questions_and_answers: questionsAndAnswersOutputs,
|
||||
tracking: trackingOutputs,
|
||||
text_reminder_number: {
|
||||
type: 'string',
|
||||
description: 'Phone number for text reminders',
|
||||
},
|
||||
rescheduled: {
|
||||
type: 'boolean',
|
||||
description: 'Whether this invitee rescheduled',
|
||||
},
|
||||
old_invitee: {
|
||||
type: 'string',
|
||||
description: 'URI of the old invitee (if rescheduled)',
|
||||
},
|
||||
new_invitee: {
|
||||
type: 'string',
|
||||
description: 'URI of the new invitee (if rescheduled)',
|
||||
},
|
||||
cancel_url: {
|
||||
type: 'string',
|
||||
description: 'URL to cancel the event',
|
||||
},
|
||||
reschedule_url: {
|
||||
type: 'string',
|
||||
description: 'URL to reschedule the event',
|
||||
},
|
||||
created_at: {
|
||||
type: 'string',
|
||||
description: 'Invitee creation timestamp',
|
||||
},
|
||||
updated_at: {
|
||||
type: 'string',
|
||||
description: 'Invitee last update timestamp',
|
||||
},
|
||||
canceled: {
|
||||
type: 'boolean',
|
||||
description: 'Whether the event was canceled',
|
||||
},
|
||||
cancellation: {
|
||||
type: 'object',
|
||||
description: 'Cancellation details',
|
||||
properties: {
|
||||
canceled_by: {
|
||||
type: 'string',
|
||||
description: 'Who canceled the event',
|
||||
},
|
||||
reason: {
|
||||
type: 'string',
|
||||
description: 'Cancellation reason',
|
||||
},
|
||||
},
|
||||
},
|
||||
payment: {
|
||||
type: 'object',
|
||||
description: 'Payment details',
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
description: 'Payment ID',
|
||||
},
|
||||
provider: {
|
||||
type: 'string',
|
||||
description: 'Payment provider',
|
||||
},
|
||||
amount: {
|
||||
type: 'number',
|
||||
description: 'Payment amount',
|
||||
},
|
||||
currency: {
|
||||
type: 'string',
|
||||
description: 'Payment currency',
|
||||
},
|
||||
terms: {
|
||||
type: 'string',
|
||||
description: 'Payment terms',
|
||||
},
|
||||
successful: {
|
||||
type: 'boolean',
|
||||
description: 'Whether payment was successful',
|
||||
},
|
||||
},
|
||||
},
|
||||
no_show: {
|
||||
type: 'object',
|
||||
description: 'No-show details',
|
||||
properties: {
|
||||
created_at: {
|
||||
type: 'string',
|
||||
description: 'No-show marked timestamp',
|
||||
},
|
||||
},
|
||||
},
|
||||
reconfirmation: {
|
||||
type: 'object',
|
||||
description: 'Reconfirmation details',
|
||||
properties: {
|
||||
created_at: {
|
||||
type: 'string',
|
||||
description: 'Reconfirmation timestamp',
|
||||
},
|
||||
confirmed_at: {
|
||||
type: 'string',
|
||||
description: 'Confirmation timestamp',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as any
|
||||
}
|
||||
|
||||
/**
|
||||
* Build output schema for routing form submission events
|
||||
*/
|
||||
export function buildRoutingFormOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
event: {
|
||||
type: 'string',
|
||||
description: 'Event type (routing_form_submission.created)',
|
||||
},
|
||||
created_at: {
|
||||
type: 'string',
|
||||
description: 'Webhook event creation timestamp',
|
||||
},
|
||||
created_by: {
|
||||
type: 'string',
|
||||
description: 'URI of the Calendly user who created this webhook',
|
||||
},
|
||||
payload: {
|
||||
uri: {
|
||||
type: 'string',
|
||||
description: 'Routing form submission URI',
|
||||
},
|
||||
routing_form: {
|
||||
type: 'string',
|
||||
description: 'Routing form URI',
|
||||
},
|
||||
submitter: {
|
||||
type: 'object',
|
||||
description: 'Submitter details',
|
||||
properties: {
|
||||
uri: {
|
||||
type: 'string',
|
||||
description: 'Submitter URI',
|
||||
},
|
||||
email: {
|
||||
type: 'string',
|
||||
description: 'Submitter email address',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
description: 'Submitter full name',
|
||||
},
|
||||
},
|
||||
},
|
||||
submitter_type: {
|
||||
type: 'string',
|
||||
description: 'Type of submitter',
|
||||
},
|
||||
questions_and_answers: questionsAndAnswersOutputs,
|
||||
tracking: trackingOutputs,
|
||||
result: {
|
||||
type: 'object',
|
||||
description: 'Routing result details',
|
||||
properties: {
|
||||
type: {
|
||||
type: 'string',
|
||||
description: 'Result type (event_type, custom_message, or external_url)',
|
||||
},
|
||||
value: {
|
||||
type: 'string',
|
||||
description: 'Result value (event type URI, message, or URL)',
|
||||
},
|
||||
},
|
||||
},
|
||||
created_at: {
|
||||
type: 'string',
|
||||
description: 'Submission creation timestamp',
|
||||
},
|
||||
updated_at: {
|
||||
type: 'string',
|
||||
description: 'Submission last update timestamp',
|
||||
},
|
||||
},
|
||||
} as any
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a Calendly event matches the expected trigger configuration
|
||||
*/
|
||||
export function isCalendlyEventMatch(triggerId: string, eventType: string): boolean {
|
||||
const eventMap: Record<string, string> = {
|
||||
calendly_invitee_created: 'invitee.created',
|
||||
calendly_invitee_canceled: 'invitee.canceled',
|
||||
calendly_routing_form_submitted: 'routing_form_submission.created',
|
||||
}
|
||||
|
||||
const expectedEvent = eventMap[triggerId]
|
||||
if (!expectedEvent) {
|
||||
return true // Unknown trigger or general webhook, allow through
|
||||
}
|
||||
|
||||
return expectedEvent === eventType
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
import { CalendlyIcon } from '@/components/icons'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
export const calendlyWebhookTrigger: TriggerConfig = {
|
||||
id: 'calendly_webhook',
|
||||
name: 'Calendly Webhook',
|
||||
provider: 'calendly',
|
||||
description: 'Trigger workflow from any Calendly webhook event',
|
||||
version: '1.0.0',
|
||||
icon: CalendlyIcon,
|
||||
|
||||
subBlocks: [
|
||||
{
|
||||
id: 'apiKey',
|
||||
title: 'Personal Access Token',
|
||||
type: 'short-input',
|
||||
placeholder: 'Enter your Calendly personal access token',
|
||||
password: true,
|
||||
required: true,
|
||||
mode: 'trigger',
|
||||
condition: {
|
||||
field: 'selectedTriggerId',
|
||||
value: 'calendly_webhook',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'organization',
|
||||
title: 'Organization URI',
|
||||
type: 'short-input',
|
||||
placeholder: 'https://api.calendly.com/organizations/XXXXXX',
|
||||
description:
|
||||
'Organization URI for the webhook subscription. Get this from "Get Current User" operation.',
|
||||
required: true,
|
||||
mode: 'trigger',
|
||||
condition: {
|
||||
field: 'selectedTriggerId',
|
||||
value: 'calendly_webhook',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'triggerInstructions',
|
||||
title: 'Setup Instructions',
|
||||
hideFromPreview: true,
|
||||
type: 'text',
|
||||
defaultValue: [
|
||||
'<strong>Note:</strong> This trigger requires a paid Calendly subscription (Professional, Teams, or Enterprise plan).',
|
||||
'Get your Personal Access Token from <strong>Settings > Integrations > API & Webhooks</strong> in your Calendly account.',
|
||||
'Use the "Get Current User" operation in a Calendly block to retrieve your Organization URI.',
|
||||
'The webhook will be automatically created in Calendly when you deploy the workflow.',
|
||||
'This webhook subscribes to all Calendly events (invitee created, invitee canceled, and routing form submitted). Use the <code>event</code> field in the payload to determine the event type.',
|
||||
]
|
||||
.map(
|
||||
(instruction, index) =>
|
||||
`<div class="mb-3"><strong>${index + 1}.</strong> ${instruction}</div>`
|
||||
)
|
||||
.join(''),
|
||||
mode: 'trigger',
|
||||
condition: {
|
||||
field: 'selectedTriggerId',
|
||||
value: 'calendly_webhook',
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
outputs: {
|
||||
event: {
|
||||
type: 'string',
|
||||
description:
|
||||
'Event type (invitee.created, invitee.canceled, or routing_form_submission.created)',
|
||||
},
|
||||
created_at: {
|
||||
type: 'string',
|
||||
description: 'Webhook event creation timestamp',
|
||||
},
|
||||
created_by: {
|
||||
type: 'string',
|
||||
description: 'URI of the Calendly user who created this webhook',
|
||||
},
|
||||
payload: {
|
||||
type: 'object',
|
||||
description: 'Complete event payload (structure varies by event type)',
|
||||
},
|
||||
},
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Calendly-Webhook-Signature': 'v1,signature...',
|
||||
'User-Agent': 'Calendly-Webhook',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export { circlebackMeetingCompletedTrigger } from './meeting_completed'
|
||||
export { circlebackMeetingNotesTrigger } from './meeting_notes'
|
||||
export { circlebackWebhookTrigger } from './webhook'
|
||||
@@ -0,0 +1,64 @@
|
||||
import { CirclebackIcon } from '@/components/icons'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
import { buildMeetingOutputs, circlebackSetupInstructions } from './utils'
|
||||
|
||||
export const circlebackMeetingCompletedTrigger: TriggerConfig = {
|
||||
id: 'circleback_meeting_completed',
|
||||
name: 'Circleback Meeting Completed',
|
||||
provider: 'circleback',
|
||||
description: 'Trigger workflow when a meeting is processed and ready in Circleback',
|
||||
version: '1.0.0',
|
||||
icon: CirclebackIcon,
|
||||
|
||||
subBlocks: [
|
||||
{
|
||||
id: 'webhookUrlDisplay',
|
||||
title: 'Webhook URL',
|
||||
type: 'short-input',
|
||||
readOnly: true,
|
||||
showCopyButton: true,
|
||||
useWebhookUrl: true,
|
||||
placeholder: 'Webhook URL will be generated',
|
||||
mode: 'trigger',
|
||||
condition: {
|
||||
field: 'selectedTriggerId',
|
||||
value: 'circleback_meeting_completed',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'webhookSecret',
|
||||
title: 'Signing Secret',
|
||||
type: 'short-input',
|
||||
placeholder: 'Paste signing secret from Circleback (optional)',
|
||||
description: 'Validates that webhook deliveries originate from Circleback using HMAC-SHA256.',
|
||||
password: true,
|
||||
required: false,
|
||||
mode: 'trigger',
|
||||
condition: {
|
||||
field: 'selectedTriggerId',
|
||||
value: 'circleback_meeting_completed',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'triggerInstructions',
|
||||
title: 'Setup Instructions',
|
||||
hideFromPreview: true,
|
||||
type: 'text',
|
||||
defaultValue: circlebackSetupInstructions('All meeting data'),
|
||||
mode: 'trigger',
|
||||
condition: {
|
||||
field: 'selectedTriggerId',
|
||||
value: 'circleback_meeting_completed',
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
outputs: buildMeetingOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
import { CirclebackIcon } from '@/components/icons'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
import { buildMeetingOutputs, circlebackSetupInstructions } from './utils'
|
||||
|
||||
export const circlebackMeetingNotesTrigger: TriggerConfig = {
|
||||
id: 'circleback_meeting_notes',
|
||||
name: 'Circleback Meeting Notes Ready',
|
||||
provider: 'circleback',
|
||||
description: 'Trigger workflow when meeting notes and action items are ready',
|
||||
version: '1.0.0',
|
||||
icon: CirclebackIcon,
|
||||
|
||||
subBlocks: [
|
||||
{
|
||||
id: 'webhookUrlDisplay',
|
||||
title: 'Webhook URL',
|
||||
type: 'short-input',
|
||||
readOnly: true,
|
||||
showCopyButton: true,
|
||||
useWebhookUrl: true,
|
||||
placeholder: 'Webhook URL will be generated',
|
||||
mode: 'trigger',
|
||||
condition: {
|
||||
field: 'selectedTriggerId',
|
||||
value: 'circleback_meeting_notes',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'webhookSecret',
|
||||
title: 'Signing Secret',
|
||||
type: 'short-input',
|
||||
placeholder: 'Paste signing secret from Circleback (optional)',
|
||||
description: 'Validates that webhook deliveries originate from Circleback using HMAC-SHA256.',
|
||||
password: true,
|
||||
required: false,
|
||||
mode: 'trigger',
|
||||
condition: {
|
||||
field: 'selectedTriggerId',
|
||||
value: 'circleback_meeting_notes',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'triggerInstructions',
|
||||
title: 'Setup Instructions',
|
||||
hideFromPreview: true,
|
||||
type: 'text',
|
||||
defaultValue: circlebackSetupInstructions('Meeting notes and action items'),
|
||||
mode: 'trigger',
|
||||
condition: {
|
||||
field: 'selectedTriggerId',
|
||||
value: 'circleback_meeting_notes',
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
outputs: buildMeetingOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
import type { TriggerOutput } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Shared trigger dropdown options for all Circleback triggers
|
||||
*/
|
||||
export const circlebackTriggerOptions = [
|
||||
{ label: 'General Webhook', id: 'circleback_webhook' },
|
||||
{ label: 'Meeting Completed', id: 'circleback_meeting_completed' },
|
||||
{ label: 'Meeting Notes Ready', id: 'circleback_meeting_notes' },
|
||||
]
|
||||
|
||||
/**
|
||||
* Generate setup instructions for a specific Circleback event type
|
||||
*/
|
||||
export function circlebackSetupInstructions(eventType: string): string {
|
||||
const instructions = [
|
||||
'<strong>Note:</strong> You need access to Circleback automations to set up webhooks. See the <a href="https://circleback.ai/docs/webhook-integration" target="_blank" rel="noopener noreferrer">Circleback webhook documentation</a> for details.',
|
||||
'In Circleback, click <strong>Automations</strong> in the sidebar.',
|
||||
'Create a new automation or edit an existing one.',
|
||||
'Add a <strong>Send webhook request</strong> step to your automation.',
|
||||
'Paste the <strong>Webhook URL</strong> from above into the Endpoint field.',
|
||||
'Optionally, copy the <strong>Signing Secret</strong> from Circleback and paste it above to verify webhook signatures.',
|
||||
`Toggle what to include in the request (Meeting notes, Action items, Transcript). For this trigger: <strong>${eventType}</strong>.`,
|
||||
'Click <strong>"Done"</strong> and save the automation.',
|
||||
]
|
||||
|
||||
return instructions
|
||||
.map(
|
||||
(instruction, index) =>
|
||||
`<div class="mb-3">${index === 0 ? instruction : `<strong>${index}.</strong> ${instruction}`}</div>`
|
||||
)
|
||||
.join('')
|
||||
}
|
||||
|
||||
/**
|
||||
* Build output schema for meeting events
|
||||
*/
|
||||
export function buildMeetingOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
id: {
|
||||
type: 'number',
|
||||
description: 'Circleback meeting ID',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
description: 'Meeting title/name',
|
||||
},
|
||||
url: {
|
||||
type: 'string',
|
||||
description: 'URL of the virtual meeting (Zoom, Google Meet, Teams, etc.)',
|
||||
},
|
||||
createdAt: {
|
||||
type: 'string',
|
||||
description: 'ISO8601 timestamp when meeting was created',
|
||||
},
|
||||
duration: {
|
||||
type: 'number',
|
||||
description: 'Meeting duration in seconds',
|
||||
},
|
||||
recordingUrl: {
|
||||
type: 'string',
|
||||
description: 'Recording URL (valid for 24 hours, if enabled)',
|
||||
},
|
||||
tags: {
|
||||
type: 'array',
|
||||
description: 'Array of tag strings',
|
||||
},
|
||||
icalUid: {
|
||||
type: 'string',
|
||||
description: 'Calendar event identifier',
|
||||
},
|
||||
attendees: {
|
||||
type: 'array',
|
||||
description: 'Array of attendee objects with name and email',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string', description: 'Attendee name' },
|
||||
email: { type: 'string', description: 'Attendee email address' },
|
||||
},
|
||||
},
|
||||
},
|
||||
notes: {
|
||||
type: 'string',
|
||||
description: 'Meeting notes in Markdown format',
|
||||
},
|
||||
actionItems: {
|
||||
type: 'array',
|
||||
description: 'Array of action item objects',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'number', description: 'Action item ID' },
|
||||
title: { type: 'string', description: 'Action item title' },
|
||||
description: { type: 'string', description: 'Action item description' },
|
||||
assignee: {
|
||||
type: 'object',
|
||||
description: 'Person assigned to the action item (or null)',
|
||||
properties: {
|
||||
name: { type: 'string', description: 'Assignee name' },
|
||||
email: { type: 'string', description: 'Assignee email' },
|
||||
},
|
||||
},
|
||||
status: { type: 'string', description: 'Status: PENDING or DONE' },
|
||||
},
|
||||
},
|
||||
},
|
||||
transcript: {
|
||||
type: 'array',
|
||||
description: 'Array of transcript segments',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
speaker: { type: 'string', description: 'Speaker name' },
|
||||
text: { type: 'string', description: 'Transcript text' },
|
||||
timestamp: { type: 'number', description: 'Timestamp in seconds' },
|
||||
},
|
||||
},
|
||||
},
|
||||
insights: {
|
||||
type: 'object',
|
||||
description: 'User-created insights keyed by insight name',
|
||||
},
|
||||
meeting: {
|
||||
type: 'object',
|
||||
description: 'Full meeting payload object',
|
||||
properties: {
|
||||
id: { type: 'number', description: 'Meeting ID' },
|
||||
name: { type: 'string', description: 'Meeting name' },
|
||||
url: { type: 'string', description: 'Meeting URL' },
|
||||
duration: { type: 'number', description: 'Duration in seconds' },
|
||||
createdAt: { type: 'string', description: 'Creation timestamp' },
|
||||
recordingUrl: { type: 'string', description: 'Recording URL' },
|
||||
},
|
||||
},
|
||||
} as any
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import { CirclebackIcon } from '@/components/icons'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
import { buildMeetingOutputs, circlebackSetupInstructions, circlebackTriggerOptions } from './utils'
|
||||
|
||||
export const circlebackWebhookTrigger: TriggerConfig = {
|
||||
id: 'circleback_webhook',
|
||||
name: 'Circleback Webhook',
|
||||
provider: 'circleback',
|
||||
description: 'Generic webhook trigger for all Circleback events',
|
||||
version: '1.0.0',
|
||||
icon: CirclebackIcon,
|
||||
|
||||
subBlocks: [
|
||||
{
|
||||
id: 'selectedTriggerId',
|
||||
title: 'Trigger Type',
|
||||
type: 'dropdown',
|
||||
mode: 'trigger',
|
||||
options: circlebackTriggerOptions,
|
||||
value: () => 'circleback_webhook',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'webhookUrlDisplay',
|
||||
title: 'Webhook URL',
|
||||
type: 'short-input',
|
||||
readOnly: true,
|
||||
showCopyButton: true,
|
||||
useWebhookUrl: true,
|
||||
placeholder: 'Webhook URL will be generated',
|
||||
mode: 'trigger',
|
||||
condition: {
|
||||
field: 'selectedTriggerId',
|
||||
value: 'circleback_webhook',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'webhookSecret',
|
||||
title: 'Signing Secret',
|
||||
type: 'short-input',
|
||||
placeholder: 'Paste signing secret from Circleback (optional)',
|
||||
description: 'Validates that webhook deliveries originate from Circleback using HMAC-SHA256.',
|
||||
password: true,
|
||||
required: false,
|
||||
mode: 'trigger',
|
||||
condition: {
|
||||
field: 'selectedTriggerId',
|
||||
value: 'circleback_webhook',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'triggerInstructions',
|
||||
title: 'Setup Instructions',
|
||||
hideFromPreview: true,
|
||||
type: 'text',
|
||||
defaultValue: circlebackSetupInstructions('All events'),
|
||||
mode: 'trigger',
|
||||
condition: {
|
||||
field: 'selectedTriggerId',
|
||||
value: 'circleback_webhook',
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
outputs: buildMeetingOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
export { clerkOrganizationCreatedTrigger } from './organization_created'
|
||||
export { clerkOrganizationDeletedTrigger } from './organization_deleted'
|
||||
export { clerkOrganizationMembershipCreatedTrigger } from './organization_membership_created'
|
||||
export { clerkOrganizationMembershipDeletedTrigger } from './organization_membership_deleted'
|
||||
export { clerkOrganizationMembershipUpdatedTrigger } from './organization_membership_updated'
|
||||
export { clerkOrganizationUpdatedTrigger } from './organization_updated'
|
||||
export { clerkSessionCreatedTrigger } from './session_created'
|
||||
export { clerkSessionEndedTrigger } from './session_ended'
|
||||
export { clerkSessionRemovedTrigger } from './session_removed'
|
||||
export { clerkSessionRevokedTrigger } from './session_revoked'
|
||||
export { clerkUserCreatedTrigger } from './user_created'
|
||||
export { clerkUserDeletedTrigger } from './user_deleted'
|
||||
export { clerkUserUpdatedTrigger } from './user_updated'
|
||||
export { clerkWebhookTrigger } from './webhook'
|
||||
@@ -0,0 +1,38 @@
|
||||
import { ClerkIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildClerkExtraFields,
|
||||
buildOrganizationOutputs,
|
||||
clerkSetupInstructions,
|
||||
clerkTriggerOptions,
|
||||
} from '@/triggers/clerk/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Clerk Organization Created Trigger.
|
||||
* Triggers when a new organization is created.
|
||||
*/
|
||||
export const clerkOrganizationCreatedTrigger: TriggerConfig = {
|
||||
id: 'clerk_organization_created',
|
||||
name: 'Clerk Organization Created',
|
||||
provider: 'clerk',
|
||||
description: 'Trigger workflow when a Clerk organization is created',
|
||||
version: '1.0.0',
|
||||
icon: ClerkIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'clerk_organization_created',
|
||||
triggerOptions: clerkTriggerOptions,
|
||||
setupInstructions: clerkSetupInstructions('organization.created'),
|
||||
extraFields: buildClerkExtraFields('clerk_organization_created'),
|
||||
}),
|
||||
|
||||
outputs: buildOrganizationOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { ClerkIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildClerkExtraFields,
|
||||
buildOrganizationDeletedOutputs,
|
||||
clerkSetupInstructions,
|
||||
clerkTriggerOptions,
|
||||
} from '@/triggers/clerk/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Clerk Organization Deleted Trigger.
|
||||
* Triggers when an organization is deleted.
|
||||
*/
|
||||
export const clerkOrganizationDeletedTrigger: TriggerConfig = {
|
||||
id: 'clerk_organization_deleted',
|
||||
name: 'Clerk Organization Deleted',
|
||||
provider: 'clerk',
|
||||
description: 'Trigger workflow when a Clerk organization is deleted',
|
||||
version: '1.0.0',
|
||||
icon: ClerkIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'clerk_organization_deleted',
|
||||
triggerOptions: clerkTriggerOptions,
|
||||
setupInstructions: clerkSetupInstructions('organization.deleted'),
|
||||
extraFields: buildClerkExtraFields('clerk_organization_deleted'),
|
||||
}),
|
||||
|
||||
outputs: buildOrganizationDeletedOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { ClerkIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildClerkExtraFields,
|
||||
buildOrganizationMembershipOutputs,
|
||||
clerkSetupInstructions,
|
||||
clerkTriggerOptions,
|
||||
} from '@/triggers/clerk/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Clerk Organization Membership Created Trigger.
|
||||
* Triggers when a user is added as a member of an organization.
|
||||
*/
|
||||
export const clerkOrganizationMembershipCreatedTrigger: TriggerConfig = {
|
||||
id: 'clerk_organization_membership_created',
|
||||
name: 'Clerk Organization Membership Created',
|
||||
provider: 'clerk',
|
||||
description: 'Trigger workflow when a Clerk organization membership is created',
|
||||
version: '1.0.0',
|
||||
icon: ClerkIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'clerk_organization_membership_created',
|
||||
triggerOptions: clerkTriggerOptions,
|
||||
setupInstructions: clerkSetupInstructions('organizationMembership.created'),
|
||||
extraFields: buildClerkExtraFields('clerk_organization_membership_created'),
|
||||
}),
|
||||
|
||||
outputs: buildOrganizationMembershipOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { ClerkIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildClerkExtraFields,
|
||||
buildOrganizationMembershipDeletedOutputs,
|
||||
clerkSetupInstructions,
|
||||
clerkTriggerOptions,
|
||||
} from '@/triggers/clerk/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Clerk Organization Membership Deleted Trigger.
|
||||
* Triggers when a member is removed from an organization.
|
||||
*/
|
||||
export const clerkOrganizationMembershipDeletedTrigger: TriggerConfig = {
|
||||
id: 'clerk_organization_membership_deleted',
|
||||
name: 'Clerk Organization Membership Deleted',
|
||||
provider: 'clerk',
|
||||
description: 'Trigger workflow when a Clerk organization membership is deleted',
|
||||
version: '1.0.0',
|
||||
icon: ClerkIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'clerk_organization_membership_deleted',
|
||||
triggerOptions: clerkTriggerOptions,
|
||||
setupInstructions: clerkSetupInstructions('organizationMembership.deleted'),
|
||||
extraFields: buildClerkExtraFields('clerk_organization_membership_deleted'),
|
||||
}),
|
||||
|
||||
outputs: buildOrganizationMembershipDeletedOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { ClerkIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildClerkExtraFields,
|
||||
buildOrganizationMembershipOutputs,
|
||||
clerkSetupInstructions,
|
||||
clerkTriggerOptions,
|
||||
} from '@/triggers/clerk/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Clerk Organization Membership Updated Trigger.
|
||||
* Triggers when a member's role within an organization changes.
|
||||
*/
|
||||
export const clerkOrganizationMembershipUpdatedTrigger: TriggerConfig = {
|
||||
id: 'clerk_organization_membership_updated',
|
||||
name: 'Clerk Organization Membership Updated',
|
||||
provider: 'clerk',
|
||||
description: 'Trigger workflow when a Clerk organization membership is updated',
|
||||
version: '1.0.0',
|
||||
icon: ClerkIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'clerk_organization_membership_updated',
|
||||
triggerOptions: clerkTriggerOptions,
|
||||
setupInstructions: clerkSetupInstructions('organizationMembership.updated'),
|
||||
extraFields: buildClerkExtraFields('clerk_organization_membership_updated'),
|
||||
}),
|
||||
|
||||
outputs: buildOrganizationMembershipOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { ClerkIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildClerkExtraFields,
|
||||
buildOrganizationOutputs,
|
||||
clerkSetupInstructions,
|
||||
clerkTriggerOptions,
|
||||
} from '@/triggers/clerk/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Clerk Organization Updated Trigger.
|
||||
* Triggers when an organization's details are updated.
|
||||
*/
|
||||
export const clerkOrganizationUpdatedTrigger: TriggerConfig = {
|
||||
id: 'clerk_organization_updated',
|
||||
name: 'Clerk Organization Updated',
|
||||
provider: 'clerk',
|
||||
description: 'Trigger workflow when a Clerk organization is updated',
|
||||
version: '1.0.0',
|
||||
icon: ClerkIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'clerk_organization_updated',
|
||||
triggerOptions: clerkTriggerOptions,
|
||||
setupInstructions: clerkSetupInstructions('organization.updated'),
|
||||
extraFields: buildClerkExtraFields('clerk_organization_updated'),
|
||||
}),
|
||||
|
||||
outputs: buildOrganizationOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { ClerkIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildClerkExtraFields,
|
||||
buildSessionOutputs,
|
||||
clerkSetupInstructions,
|
||||
clerkTriggerOptions,
|
||||
} from '@/triggers/clerk/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Clerk Session Created Trigger.
|
||||
* Triggers when a user signs in and a new session is created.
|
||||
*/
|
||||
export const clerkSessionCreatedTrigger: TriggerConfig = {
|
||||
id: 'clerk_session_created',
|
||||
name: 'Clerk Session Created',
|
||||
provider: 'clerk',
|
||||
description: 'Trigger workflow when a Clerk session is created',
|
||||
version: '1.0.0',
|
||||
icon: ClerkIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'clerk_session_created',
|
||||
triggerOptions: clerkTriggerOptions,
|
||||
setupInstructions: clerkSetupInstructions('session.created'),
|
||||
extraFields: buildClerkExtraFields('clerk_session_created'),
|
||||
}),
|
||||
|
||||
outputs: buildSessionOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { ClerkIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildClerkExtraFields,
|
||||
buildSessionOutputs,
|
||||
clerkSetupInstructions,
|
||||
clerkTriggerOptions,
|
||||
} from '@/triggers/clerk/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Clerk Session Ended Trigger.
|
||||
* Triggers when a user signs out and the session ends.
|
||||
*/
|
||||
export const clerkSessionEndedTrigger: TriggerConfig = {
|
||||
id: 'clerk_session_ended',
|
||||
name: 'Clerk Session Ended',
|
||||
provider: 'clerk',
|
||||
description: 'Trigger workflow when a Clerk session ends',
|
||||
version: '1.0.0',
|
||||
icon: ClerkIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'clerk_session_ended',
|
||||
triggerOptions: clerkTriggerOptions,
|
||||
setupInstructions: clerkSetupInstructions('session.ended'),
|
||||
extraFields: buildClerkExtraFields('clerk_session_ended'),
|
||||
}),
|
||||
|
||||
outputs: buildSessionOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { ClerkIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildClerkExtraFields,
|
||||
buildSessionOutputs,
|
||||
clerkSetupInstructions,
|
||||
clerkTriggerOptions,
|
||||
} from '@/triggers/clerk/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Clerk Session Removed Trigger.
|
||||
* Triggers when a session is removed, e.g. because the associated user was deleted.
|
||||
*/
|
||||
export const clerkSessionRemovedTrigger: TriggerConfig = {
|
||||
id: 'clerk_session_removed',
|
||||
name: 'Clerk Session Removed',
|
||||
provider: 'clerk',
|
||||
description: 'Trigger workflow when a Clerk session is removed',
|
||||
version: '1.0.0',
|
||||
icon: ClerkIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'clerk_session_removed',
|
||||
triggerOptions: clerkTriggerOptions,
|
||||
setupInstructions: clerkSetupInstructions('session.removed'),
|
||||
extraFields: buildClerkExtraFields('clerk_session_removed'),
|
||||
}),
|
||||
|
||||
outputs: buildSessionOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { ClerkIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildClerkExtraFields,
|
||||
buildSessionOutputs,
|
||||
clerkSetupInstructions,
|
||||
clerkTriggerOptions,
|
||||
} from '@/triggers/clerk/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Clerk Session Revoked Trigger.
|
||||
* Triggers when a session is revoked, e.g. via the Revoke Session API or Dashboard.
|
||||
*/
|
||||
export const clerkSessionRevokedTrigger: TriggerConfig = {
|
||||
id: 'clerk_session_revoked',
|
||||
name: 'Clerk Session Revoked',
|
||||
provider: 'clerk',
|
||||
description: 'Trigger workflow when a Clerk session is revoked',
|
||||
version: '1.0.0',
|
||||
icon: ClerkIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'clerk_session_revoked',
|
||||
triggerOptions: clerkTriggerOptions,
|
||||
setupInstructions: clerkSetupInstructions('session.revoked'),
|
||||
extraFields: buildClerkExtraFields('clerk_session_revoked'),
|
||||
}),
|
||||
|
||||
outputs: buildSessionOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import { ClerkIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildClerkExtraFields,
|
||||
buildUserOutputs,
|
||||
clerkSetupInstructions,
|
||||
clerkTriggerOptions,
|
||||
} from '@/triggers/clerk/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Clerk User Created Trigger (primary).
|
||||
* Triggers when a new user registers or is created via the Dashboard or Backend API.
|
||||
*/
|
||||
export const clerkUserCreatedTrigger: TriggerConfig = {
|
||||
id: 'clerk_user_created',
|
||||
name: 'Clerk User Created',
|
||||
provider: 'clerk',
|
||||
description: 'Trigger workflow when a Clerk user is created',
|
||||
version: '1.0.0',
|
||||
icon: ClerkIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'clerk_user_created',
|
||||
triggerOptions: clerkTriggerOptions,
|
||||
includeDropdown: true,
|
||||
setupInstructions: clerkSetupInstructions('user.created'),
|
||||
extraFields: buildClerkExtraFields('clerk_user_created'),
|
||||
}),
|
||||
|
||||
outputs: buildUserOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { ClerkIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildClerkExtraFields,
|
||||
buildUserDeletedOutputs,
|
||||
clerkSetupInstructions,
|
||||
clerkTriggerOptions,
|
||||
} from '@/triggers/clerk/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Clerk User Deleted Trigger.
|
||||
* Triggers when a user deletes their account or is deleted.
|
||||
*/
|
||||
export const clerkUserDeletedTrigger: TriggerConfig = {
|
||||
id: 'clerk_user_deleted',
|
||||
name: 'Clerk User Deleted',
|
||||
provider: 'clerk',
|
||||
description: 'Trigger workflow when a Clerk user is deleted',
|
||||
version: '1.0.0',
|
||||
icon: ClerkIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'clerk_user_deleted',
|
||||
triggerOptions: clerkTriggerOptions,
|
||||
setupInstructions: clerkSetupInstructions('user.deleted'),
|
||||
extraFields: buildClerkExtraFields('clerk_user_deleted'),
|
||||
}),
|
||||
|
||||
outputs: buildUserDeletedOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { ClerkIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildClerkExtraFields,
|
||||
buildUserOutputs,
|
||||
clerkSetupInstructions,
|
||||
clerkTriggerOptions,
|
||||
} from '@/triggers/clerk/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Clerk User Updated Trigger.
|
||||
* Triggers when a user's information is updated.
|
||||
*/
|
||||
export const clerkUserUpdatedTrigger: TriggerConfig = {
|
||||
id: 'clerk_user_updated',
|
||||
name: 'Clerk User Updated',
|
||||
provider: 'clerk',
|
||||
description: 'Trigger workflow when a Clerk user is updated',
|
||||
version: '1.0.0',
|
||||
icon: ClerkIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'clerk_user_updated',
|
||||
triggerOptions: clerkTriggerOptions,
|
||||
setupInstructions: clerkSetupInstructions('user.updated'),
|
||||
extraFields: buildClerkExtraFields('clerk_user_updated'),
|
||||
}),
|
||||
|
||||
outputs: buildUserOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
import type { SubBlockConfig } from '@/blocks/types'
|
||||
import type { TriggerOutput } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Maps Sim Clerk trigger IDs to their Clerk webhook event type.
|
||||
* Kept in sync with `matchEvent` in the `clerk` webhook provider.
|
||||
* Event-type strings are the canonical Clerk webhook event names
|
||||
* (see https://clerk.com/docs/guides/development/webhooks/overview).
|
||||
*/
|
||||
export const CLERK_TRIGGER_TO_EVENT_TYPE: Record<string, string> = {
|
||||
clerk_user_created: 'user.created',
|
||||
clerk_user_updated: 'user.updated',
|
||||
clerk_user_deleted: 'user.deleted',
|
||||
clerk_session_created: 'session.created',
|
||||
clerk_session_ended: 'session.ended',
|
||||
clerk_session_removed: 'session.removed',
|
||||
clerk_session_revoked: 'session.revoked',
|
||||
clerk_organization_created: 'organization.created',
|
||||
clerk_organization_updated: 'organization.updated',
|
||||
clerk_organization_deleted: 'organization.deleted',
|
||||
clerk_organization_membership_created: 'organizationMembership.created',
|
||||
clerk_organization_membership_updated: 'organizationMembership.updated',
|
||||
clerk_organization_membership_deleted: 'organizationMembership.deleted',
|
||||
}
|
||||
|
||||
/**
|
||||
* Shared trigger dropdown options for all Clerk triggers.
|
||||
*/
|
||||
export const clerkTriggerOptions = [
|
||||
{ label: 'User Created', id: 'clerk_user_created' },
|
||||
{ label: 'User Updated', id: 'clerk_user_updated' },
|
||||
{ label: 'User Deleted', id: 'clerk_user_deleted' },
|
||||
{ label: 'Session Created', id: 'clerk_session_created' },
|
||||
{ label: 'Session Ended', id: 'clerk_session_ended' },
|
||||
{ label: 'Session Removed', id: 'clerk_session_removed' },
|
||||
{ label: 'Session Revoked', id: 'clerk_session_revoked' },
|
||||
{ label: 'Organization Created', id: 'clerk_organization_created' },
|
||||
{ label: 'Organization Updated', id: 'clerk_organization_updated' },
|
||||
{ label: 'Organization Deleted', id: 'clerk_organization_deleted' },
|
||||
{ label: 'Organization Membership Created', id: 'clerk_organization_membership_created' },
|
||||
{ label: 'Organization Membership Updated', id: 'clerk_organization_membership_updated' },
|
||||
{ label: 'Organization Membership Deleted', id: 'clerk_organization_membership_deleted' },
|
||||
{ label: 'Generic Webhook (All Events)', id: 'clerk_webhook' },
|
||||
]
|
||||
|
||||
/**
|
||||
* Generate setup instructions for a specific Clerk webhook event type.
|
||||
* Clerk webhooks are configured manually in the Clerk Dashboard, and the
|
||||
* Signing Secret must be pasted into the trigger configuration.
|
||||
*/
|
||||
export function clerkSetupInstructions(eventType: string): string {
|
||||
const instructions = [
|
||||
'Copy the <strong>Webhook URL</strong> above.',
|
||||
'In the <a href="https://dashboard.clerk.com" target="_blank" rel="noopener noreferrer">Clerk Dashboard</a>, go to <strong>Configure > Webhooks</strong> and click <strong>Add Endpoint</strong>.',
|
||||
'Paste the <strong>Webhook URL</strong> into the <strong>Endpoint URL</strong> field.',
|
||||
`Under <strong>Subscribe to events</strong>, select the <strong>${eventType}</strong> event, then click <strong>Create</strong>.`,
|
||||
'Open the endpoint you just created and copy its <strong>Signing Secret</strong> (starts with <code>whsec_</code>).',
|
||||
'Paste the <strong>Signing Secret</strong> into the field below.',
|
||||
'Click <strong>"Save Configuration"</strong> above to activate your trigger.',
|
||||
]
|
||||
|
||||
return instructions
|
||||
.map(
|
||||
(instruction, index) =>
|
||||
`<div class="mb-3"><strong>${index + 1}.</strong> ${instruction}</div>`
|
||||
)
|
||||
.join('')
|
||||
}
|
||||
|
||||
/**
|
||||
* Build Clerk-specific extra fields.
|
||||
* Includes the Svix Signing Secret used to verify incoming webhook signatures.
|
||||
* Use with the generic buildTriggerSubBlocks from @/triggers.
|
||||
*/
|
||||
export function buildClerkExtraFields(triggerId: string): SubBlockConfig[] {
|
||||
return [
|
||||
{
|
||||
id: 'signingSecret',
|
||||
title: 'Signing Secret',
|
||||
type: 'short-input',
|
||||
placeholder: 'whsec_...',
|
||||
description: 'Copy this from your Clerk webhook endpoint to verify event signatures.',
|
||||
password: true,
|
||||
paramVisibility: 'user-only',
|
||||
required: true,
|
||||
mode: 'trigger',
|
||||
condition: { field: 'selectedTriggerId', value: triggerId },
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* Fields common to every Clerk webhook event payload
|
||||
* (see https://clerk.com/docs/guides/development/webhooks/overview).
|
||||
*/
|
||||
const commonEventOutputs: Record<string, TriggerOutput> = {
|
||||
type: { type: 'string', description: 'Event type (e.g., user.created, session.created)' },
|
||||
object: { type: 'string', description: 'Always "event"' },
|
||||
timestamp: { type: 'number', description: 'Timestamp in milliseconds when the event occurred' },
|
||||
instance_id: { type: 'string', description: 'Identifier of your Clerk instance' },
|
||||
data: {
|
||||
type: 'json',
|
||||
description: 'Raw event `data` object (shape varies by event type)',
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Build outputs for `user.created` and `user.updated` events.
|
||||
* The `data` object is the Clerk User object.
|
||||
*/
|
||||
export function buildUserOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
...commonEventOutputs,
|
||||
userId: { type: 'string', description: 'Clerk user ID (data.id)' },
|
||||
firstName: { type: 'string', description: "User's first name" },
|
||||
lastName: { type: 'string', description: "User's last name" },
|
||||
username: { type: 'string', description: "User's username" },
|
||||
imageUrl: { type: 'string', description: 'Profile image URL' },
|
||||
primaryEmailAddressId: { type: 'string', description: 'Primary email address ID' },
|
||||
emailAddresses: { type: 'json', description: 'Array of email address objects' },
|
||||
phoneNumbers: { type: 'json', description: 'Array of phone number objects' },
|
||||
externalId: { type: 'string', description: 'External system ID linked to the user' },
|
||||
createdAt: { type: 'number', description: 'User creation timestamp (data.created_at)' },
|
||||
updatedAt: { type: 'number', description: 'User last update timestamp (data.updated_at)' },
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build outputs for `user.deleted` events.
|
||||
* The `data` object is a deleted-object marker: `{ id, deleted, object }`.
|
||||
*/
|
||||
export function buildUserDeletedOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
...commonEventOutputs,
|
||||
userId: { type: 'string', description: 'Deleted Clerk user ID (data.id)' },
|
||||
deleted: { type: 'boolean', description: 'Whether the user was deleted (data.deleted)' },
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build outputs for `session.created` events.
|
||||
* The `data` object is the Clerk Session object.
|
||||
*/
|
||||
export function buildSessionOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
...commonEventOutputs,
|
||||
sessionId: { type: 'string', description: 'Clerk session ID (data.id)' },
|
||||
userId: { type: 'string', description: 'User the session belongs to (data.user_id)' },
|
||||
clientId: { type: 'string', description: 'Client ID for the session (data.client_id)' },
|
||||
status: { type: 'string', description: 'Session status (data.status)' },
|
||||
createdAt: { type: 'number', description: 'Session creation timestamp (data.created_at)' },
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build outputs for `organization.created` events.
|
||||
* The `data` object is the Clerk Organization object.
|
||||
*/
|
||||
export function buildOrganizationOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
...commonEventOutputs,
|
||||
organizationId: { type: 'string', description: 'Clerk organization ID (data.id)' },
|
||||
name: { type: 'string', description: 'Organization name (data.name)' },
|
||||
slug: { type: 'string', description: 'Organization slug (data.slug)' },
|
||||
createdBy: { type: 'string', description: 'User ID of the creator (data.created_by)' },
|
||||
membersCount: { type: 'number', description: 'Number of members (data.members_count)' },
|
||||
maxAllowedMemberships: {
|
||||
type: 'number',
|
||||
description: 'Maximum allowed memberships (data.max_allowed_memberships)',
|
||||
},
|
||||
createdAt: { type: 'number', description: 'Organization creation timestamp (data.created_at)' },
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build outputs for `organizationMembership.created` and `.updated` events.
|
||||
* The `data` object is the Clerk OrganizationMembership object.
|
||||
*/
|
||||
export function buildOrganizationMembershipOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
...commonEventOutputs,
|
||||
membershipId: { type: 'string', description: 'Membership ID (data.id)' },
|
||||
role: { type: 'string', description: 'Membership role, e.g. org:admin (data.role)' },
|
||||
organizationId: {
|
||||
type: 'string',
|
||||
description: 'Organization ID (data.organization.id)',
|
||||
},
|
||||
userId: {
|
||||
type: 'string',
|
||||
description: 'User ID of the member (data.public_user_data.user_id)',
|
||||
},
|
||||
createdAt: { type: 'number', description: 'Membership creation timestamp (data.created_at)' },
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build outputs for `organization.deleted` events.
|
||||
* The `data` object is a deleted-object marker: `{ id, deleted, object }`.
|
||||
*/
|
||||
export function buildOrganizationDeletedOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
...commonEventOutputs,
|
||||
organizationId: { type: 'string', description: 'Deleted Clerk organization ID (data.id)' },
|
||||
deleted: {
|
||||
type: 'boolean',
|
||||
description: 'Whether the organization was deleted (data.deleted)',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build outputs for `organizationMembership.deleted` events.
|
||||
* The `data` object is a deleted-object marker: `{ id, deleted, object }`.
|
||||
*/
|
||||
export function buildOrganizationMembershipDeletedOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
...commonEventOutputs,
|
||||
membershipId: { type: 'string', description: 'Deleted membership ID (data.id)' },
|
||||
deleted: { type: 'boolean', description: 'Whether the membership was deleted (data.deleted)' },
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build outputs for the generic webhook (all events).
|
||||
* Only the fields common to every Clerk event are guaranteed; use `data`
|
||||
* for event-specific fields.
|
||||
*/
|
||||
export function buildClerkOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
...commonEventOutputs,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a Clerk event payload matches the expected trigger configuration.
|
||||
*/
|
||||
export function isClerkEventMatch(triggerId: string, body: Record<string, unknown>): boolean {
|
||||
const expectedType = CLERK_TRIGGER_TO_EVENT_TYPE[triggerId]
|
||||
if (!expectedType) {
|
||||
return true // Unknown trigger or generic webhook, allow through
|
||||
}
|
||||
return (body?.type as string | undefined) === expectedType
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { ClerkIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildClerkExtraFields,
|
||||
buildClerkOutputs,
|
||||
clerkSetupInstructions,
|
||||
clerkTriggerOptions,
|
||||
} from '@/triggers/clerk/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Clerk Generic Webhook Trigger (all events).
|
||||
* Triggers for any Clerk webhook event you subscribe the endpoint to.
|
||||
*/
|
||||
export const clerkWebhookTrigger: TriggerConfig = {
|
||||
id: 'clerk_webhook',
|
||||
name: 'Clerk Webhook',
|
||||
provider: 'clerk',
|
||||
description: 'Trigger workflow on any Clerk webhook event',
|
||||
version: '1.0.0',
|
||||
icon: ClerkIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'clerk_webhook',
|
||||
triggerOptions: clerkTriggerOptions,
|
||||
setupInstructions: clerkSetupInstructions('events you want to receive'),
|
||||
extraFields: buildClerkExtraFields('clerk_webhook'),
|
||||
}),
|
||||
|
||||
outputs: buildClerkOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { ConfluenceIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildAttachmentOutputs,
|
||||
buildConfluenceAttachmentExtraFields,
|
||||
confluenceSetupInstructions,
|
||||
confluenceTriggerOptions,
|
||||
} from '@/triggers/confluence/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Confluence Attachment Created Trigger
|
||||
*
|
||||
* Triggers when a new attachment is uploaded to a page or blog post in Confluence.
|
||||
*/
|
||||
export const confluenceAttachmentCreatedTrigger: TriggerConfig = {
|
||||
id: 'confluence_attachment_created',
|
||||
name: 'Confluence Attachment Created',
|
||||
provider: 'confluence',
|
||||
description: 'Trigger workflow when an attachment is uploaded in Confluence',
|
||||
version: '1.0.0',
|
||||
icon: ConfluenceIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'confluence_attachment_created',
|
||||
triggerOptions: confluenceTriggerOptions,
|
||||
setupInstructions: confluenceSetupInstructions('attachment_created'),
|
||||
extraFields: buildConfluenceAttachmentExtraFields('confluence_attachment_created'),
|
||||
}),
|
||||
|
||||
outputs: buildAttachmentOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Hub-Signature': 'sha256=...',
|
||||
'X-Atlassian-Webhook-Identifier': 'unique-webhook-id',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { ConfluenceIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildAttachmentOutputs,
|
||||
buildConfluenceAttachmentExtraFields,
|
||||
confluenceSetupInstructions,
|
||||
confluenceTriggerOptions,
|
||||
} from '@/triggers/confluence/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Confluence Attachment Removed Trigger
|
||||
*
|
||||
* Triggers when an attachment is removed or trashed from a page or blog post in Confluence.
|
||||
*/
|
||||
export const confluenceAttachmentRemovedTrigger: TriggerConfig = {
|
||||
id: 'confluence_attachment_removed',
|
||||
name: 'Confluence Attachment Removed',
|
||||
provider: 'confluence',
|
||||
description: 'Trigger workflow when an attachment is removed in Confluence',
|
||||
version: '1.0.0',
|
||||
icon: ConfluenceIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'confluence_attachment_removed',
|
||||
triggerOptions: confluenceTriggerOptions,
|
||||
setupInstructions: confluenceSetupInstructions('attachment_removed'),
|
||||
extraFields: buildConfluenceAttachmentExtraFields('confluence_attachment_removed'),
|
||||
}),
|
||||
|
||||
outputs: buildAttachmentOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Hub-Signature': 'sha256=...',
|
||||
'X-Atlassian-Webhook-Identifier': 'unique-webhook-id',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { ConfluenceIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildAttachmentOutputs,
|
||||
buildConfluenceAttachmentExtraFields,
|
||||
confluenceSetupInstructions,
|
||||
confluenceTriggerOptions,
|
||||
} from '@/triggers/confluence/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Confluence Attachment Updated Trigger
|
||||
*
|
||||
* Triggers when an attachment is updated (new version uploaded) in Confluence.
|
||||
*/
|
||||
export const confluenceAttachmentUpdatedTrigger: TriggerConfig = {
|
||||
id: 'confluence_attachment_updated',
|
||||
name: 'Confluence Attachment Updated',
|
||||
provider: 'confluence',
|
||||
description: 'Trigger workflow when an attachment is updated in Confluence',
|
||||
version: '1.0.0',
|
||||
icon: ConfluenceIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'confluence_attachment_updated',
|
||||
triggerOptions: confluenceTriggerOptions,
|
||||
setupInstructions: confluenceSetupInstructions('attachment_updated'),
|
||||
extraFields: buildConfluenceAttachmentExtraFields('confluence_attachment_updated'),
|
||||
}),
|
||||
|
||||
outputs: buildAttachmentOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Hub-Signature': 'sha256=...',
|
||||
'X-Atlassian-Webhook-Identifier': 'unique-webhook-id',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { ConfluenceIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildBlogOutputs,
|
||||
buildConfluenceExtraFields,
|
||||
confluenceSetupInstructions,
|
||||
confluenceTriggerOptions,
|
||||
} from '@/triggers/confluence/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Confluence Blog Post Created Trigger
|
||||
*
|
||||
* Triggers when a new blog post is created in Confluence.
|
||||
*/
|
||||
export const confluenceBlogCreatedTrigger: TriggerConfig = {
|
||||
id: 'confluence_blog_created',
|
||||
name: 'Confluence Blog Post Created',
|
||||
provider: 'confluence',
|
||||
description: 'Trigger workflow when a blog post is created in Confluence',
|
||||
version: '1.0.0',
|
||||
icon: ConfluenceIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'confluence_blog_created',
|
||||
triggerOptions: confluenceTriggerOptions,
|
||||
setupInstructions: confluenceSetupInstructions('blog_created'),
|
||||
extraFields: buildConfluenceExtraFields('confluence_blog_created'),
|
||||
}),
|
||||
|
||||
outputs: buildBlogOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Hub-Signature': 'sha256=...',
|
||||
'X-Atlassian-Webhook-Identifier': 'unique-webhook-id',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { ConfluenceIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildBlogOutputs,
|
||||
buildConfluenceExtraFields,
|
||||
confluenceSetupInstructions,
|
||||
confluenceTriggerOptions,
|
||||
} from '@/triggers/confluence/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Confluence Blog Post Removed Trigger
|
||||
*
|
||||
* Triggers when a blog post is removed or trashed in Confluence.
|
||||
*/
|
||||
export const confluenceBlogRemovedTrigger: TriggerConfig = {
|
||||
id: 'confluence_blog_removed',
|
||||
name: 'Confluence Blog Post Removed',
|
||||
provider: 'confluence',
|
||||
description: 'Trigger workflow when a blog post is removed in Confluence',
|
||||
version: '1.0.0',
|
||||
icon: ConfluenceIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'confluence_blog_removed',
|
||||
triggerOptions: confluenceTriggerOptions,
|
||||
setupInstructions: confluenceSetupInstructions('blog_removed'),
|
||||
extraFields: buildConfluenceExtraFields('confluence_blog_removed'),
|
||||
}),
|
||||
|
||||
outputs: buildBlogOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Hub-Signature': 'sha256=...',
|
||||
'X-Atlassian-Webhook-Identifier': 'unique-webhook-id',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { ConfluenceIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildBlogOutputs,
|
||||
buildConfluenceExtraFields,
|
||||
confluenceSetupInstructions,
|
||||
confluenceTriggerOptions,
|
||||
} from '@/triggers/confluence/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Confluence Blog Post Restored Trigger
|
||||
*
|
||||
* Triggers when a blog post is restored from trash in Confluence.
|
||||
*/
|
||||
export const confluenceBlogRestoredTrigger: TriggerConfig = {
|
||||
id: 'confluence_blog_restored',
|
||||
name: 'Confluence Blog Post Restored',
|
||||
provider: 'confluence',
|
||||
description: 'Trigger workflow when a blog post is restored from trash in Confluence',
|
||||
version: '1.0.0',
|
||||
icon: ConfluenceIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'confluence_blog_restored',
|
||||
triggerOptions: confluenceTriggerOptions,
|
||||
setupInstructions: confluenceSetupInstructions('blog_restored'),
|
||||
extraFields: buildConfluenceExtraFields('confluence_blog_restored'),
|
||||
}),
|
||||
|
||||
outputs: buildBlogOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Hub-Signature': 'sha256=...',
|
||||
'X-Atlassian-Webhook-Identifier': 'unique-webhook-id',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { ConfluenceIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildBlogOutputs,
|
||||
buildConfluenceExtraFields,
|
||||
confluenceSetupInstructions,
|
||||
confluenceTriggerOptions,
|
||||
} from '@/triggers/confluence/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Confluence Blog Post Updated Trigger
|
||||
*
|
||||
* Triggers when a blog post is updated in Confluence.
|
||||
*/
|
||||
export const confluenceBlogUpdatedTrigger: TriggerConfig = {
|
||||
id: 'confluence_blog_updated',
|
||||
name: 'Confluence Blog Post Updated',
|
||||
provider: 'confluence',
|
||||
description: 'Trigger workflow when a blog post is updated in Confluence',
|
||||
version: '1.0.0',
|
||||
icon: ConfluenceIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'confluence_blog_updated',
|
||||
triggerOptions: confluenceTriggerOptions,
|
||||
setupInstructions: confluenceSetupInstructions('blog_updated'),
|
||||
extraFields: buildConfluenceExtraFields('confluence_blog_updated'),
|
||||
}),
|
||||
|
||||
outputs: buildBlogOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Hub-Signature': 'sha256=...',
|
||||
'X-Atlassian-Webhook-Identifier': 'unique-webhook-id',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { ConfluenceIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildCommentOutputs,
|
||||
buildConfluenceExtraFields,
|
||||
confluenceSetupInstructions,
|
||||
confluenceTriggerOptions,
|
||||
} from '@/triggers/confluence/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Confluence Comment Created Trigger
|
||||
*
|
||||
* Triggers when a new comment is created on a page or blog post in Confluence.
|
||||
*/
|
||||
export const confluenceCommentCreatedTrigger: TriggerConfig = {
|
||||
id: 'confluence_comment_created',
|
||||
name: 'Confluence Comment Created',
|
||||
provider: 'confluence',
|
||||
description: 'Trigger workflow when a comment is created in Confluence',
|
||||
version: '1.0.0',
|
||||
icon: ConfluenceIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'confluence_comment_created',
|
||||
triggerOptions: confluenceTriggerOptions,
|
||||
setupInstructions: confluenceSetupInstructions('comment_created'),
|
||||
extraFields: buildConfluenceExtraFields('confluence_comment_created'),
|
||||
}),
|
||||
|
||||
outputs: buildCommentOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Hub-Signature': 'sha256=...',
|
||||
'X-Atlassian-Webhook-Identifier': 'unique-webhook-id',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { ConfluenceIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildCommentOutputs,
|
||||
buildConfluenceExtraFields,
|
||||
confluenceSetupInstructions,
|
||||
confluenceTriggerOptions,
|
||||
} from '@/triggers/confluence/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Confluence Comment Removed Trigger
|
||||
*
|
||||
* Triggers when a comment is removed from a page or blog post in Confluence.
|
||||
*/
|
||||
export const confluenceCommentRemovedTrigger: TriggerConfig = {
|
||||
id: 'confluence_comment_removed',
|
||||
name: 'Confluence Comment Removed',
|
||||
provider: 'confluence',
|
||||
description: 'Trigger workflow when a comment is removed in Confluence',
|
||||
version: '1.0.0',
|
||||
icon: ConfluenceIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'confluence_comment_removed',
|
||||
triggerOptions: confluenceTriggerOptions,
|
||||
setupInstructions: confluenceSetupInstructions('comment_removed'),
|
||||
extraFields: buildConfluenceExtraFields('confluence_comment_removed'),
|
||||
}),
|
||||
|
||||
outputs: buildCommentOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Hub-Signature': 'sha256=...',
|
||||
'X-Atlassian-Webhook-Identifier': 'unique-webhook-id',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { ConfluenceIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildCommentOutputs,
|
||||
buildConfluenceExtraFields,
|
||||
confluenceSetupInstructions,
|
||||
confluenceTriggerOptions,
|
||||
} from '@/triggers/confluence/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Confluence Comment Updated Trigger
|
||||
*
|
||||
* Triggers when a comment on a page or blog post is updated/edited in Confluence.
|
||||
*/
|
||||
export const confluenceCommentUpdatedTrigger: TriggerConfig = {
|
||||
id: 'confluence_comment_updated',
|
||||
name: 'Confluence Comment Updated',
|
||||
provider: 'confluence',
|
||||
description: 'Trigger workflow when a comment is updated in Confluence',
|
||||
version: '1.0.0',
|
||||
icon: ConfluenceIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'confluence_comment_updated',
|
||||
triggerOptions: confluenceTriggerOptions,
|
||||
setupInstructions: confluenceSetupInstructions('comment_updated'),
|
||||
extraFields: buildConfluenceExtraFields('confluence_comment_updated'),
|
||||
}),
|
||||
|
||||
outputs: buildCommentOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Hub-Signature': 'sha256=...',
|
||||
'X-Atlassian-Webhook-Identifier': 'unique-webhook-id',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Confluence Triggers
|
||||
* Export all Confluence webhook triggers
|
||||
*/
|
||||
|
||||
export { confluenceAttachmentCreatedTrigger } from './attachment_created'
|
||||
export { confluenceAttachmentRemovedTrigger } from './attachment_removed'
|
||||
export { confluenceAttachmentUpdatedTrigger } from './attachment_updated'
|
||||
export { confluenceBlogCreatedTrigger } from './blog_created'
|
||||
export { confluenceBlogRemovedTrigger } from './blog_removed'
|
||||
export { confluenceBlogRestoredTrigger } from './blog_restored'
|
||||
export { confluenceBlogUpdatedTrigger } from './blog_updated'
|
||||
export { confluenceCommentCreatedTrigger } from './comment_created'
|
||||
export { confluenceCommentRemovedTrigger } from './comment_removed'
|
||||
export { confluenceCommentUpdatedTrigger } from './comment_updated'
|
||||
export { confluenceLabelAddedTrigger } from './label_added'
|
||||
export { confluenceLabelRemovedTrigger } from './label_removed'
|
||||
export { confluencePageCreatedTrigger } from './page_created'
|
||||
export { confluencePageMovedTrigger } from './page_moved'
|
||||
export { confluencePagePermissionsUpdatedTrigger } from './page_permissions_updated'
|
||||
export { confluencePageRemovedTrigger } from './page_removed'
|
||||
export { confluencePageRestoredTrigger } from './page_restored'
|
||||
export { confluencePageUpdatedTrigger } from './page_updated'
|
||||
export { confluenceSpaceCreatedTrigger } from './space_created'
|
||||
export { confluenceSpaceRemovedTrigger } from './space_removed'
|
||||
export { confluenceSpaceUpdatedTrigger } from './space_updated'
|
||||
export { confluenceUserCreatedTrigger } from './user_created'
|
||||
export { confluenceWebhookTrigger } from './webhook'
|
||||
@@ -0,0 +1,41 @@
|
||||
import { ConfluenceIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildConfluenceExtraFields,
|
||||
buildLabelOutputs,
|
||||
confluenceSetupInstructions,
|
||||
confluenceTriggerOptions,
|
||||
} from '@/triggers/confluence/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Confluence Label Added Trigger
|
||||
*
|
||||
* Triggers when a label is added to a page, blog post, or other content in Confluence.
|
||||
*/
|
||||
export const confluenceLabelAddedTrigger: TriggerConfig = {
|
||||
id: 'confluence_label_added',
|
||||
name: 'Confluence Label Added',
|
||||
provider: 'confluence',
|
||||
description: 'Trigger workflow when a label is added to content in Confluence',
|
||||
version: '1.0.0',
|
||||
icon: ConfluenceIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'confluence_label_added',
|
||||
triggerOptions: confluenceTriggerOptions,
|
||||
setupInstructions: confluenceSetupInstructions('label_added'),
|
||||
extraFields: buildConfluenceExtraFields('confluence_label_added'),
|
||||
}),
|
||||
|
||||
outputs: buildLabelOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Hub-Signature': 'sha256=...',
|
||||
'X-Atlassian-Webhook-Identifier': 'unique-webhook-id',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { ConfluenceIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildConfluenceExtraFields,
|
||||
buildLabelOutputs,
|
||||
confluenceSetupInstructions,
|
||||
confluenceTriggerOptions,
|
||||
} from '@/triggers/confluence/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Confluence Label Removed Trigger
|
||||
*
|
||||
* Triggers when a label is removed from a page, blog post, or other content in Confluence.
|
||||
*/
|
||||
export const confluenceLabelRemovedTrigger: TriggerConfig = {
|
||||
id: 'confluence_label_removed',
|
||||
name: 'Confluence Label Removed',
|
||||
provider: 'confluence',
|
||||
description: 'Trigger workflow when a label is removed from content in Confluence',
|
||||
version: '1.0.0',
|
||||
icon: ConfluenceIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'confluence_label_removed',
|
||||
triggerOptions: confluenceTriggerOptions,
|
||||
setupInstructions: confluenceSetupInstructions('label_removed'),
|
||||
extraFields: buildConfluenceExtraFields('confluence_label_removed'),
|
||||
}),
|
||||
|
||||
outputs: buildLabelOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Hub-Signature': 'sha256=...',
|
||||
'X-Atlassian-Webhook-Identifier': 'unique-webhook-id',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import { ConfluenceIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildConfluenceExtraFields,
|
||||
buildPageOutputs,
|
||||
confluenceSetupInstructions,
|
||||
confluenceTriggerOptions,
|
||||
} from '@/triggers/confluence/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Confluence Page Created Trigger
|
||||
*
|
||||
* This is the PRIMARY trigger - it includes the dropdown for selecting trigger type.
|
||||
* Triggers when a new page is created in Confluence.
|
||||
*/
|
||||
export const confluencePageCreatedTrigger: TriggerConfig = {
|
||||
id: 'confluence_page_created',
|
||||
name: 'Confluence Page Created',
|
||||
provider: 'confluence',
|
||||
description: 'Trigger workflow when a new page is created in Confluence',
|
||||
version: '1.0.0',
|
||||
icon: ConfluenceIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'confluence_page_created',
|
||||
triggerOptions: confluenceTriggerOptions,
|
||||
includeDropdown: true,
|
||||
setupInstructions: confluenceSetupInstructions('page_created'),
|
||||
extraFields: buildConfluenceExtraFields('confluence_page_created'),
|
||||
}),
|
||||
|
||||
outputs: buildPageOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Hub-Signature': 'sha256=...',
|
||||
'X-Atlassian-Webhook-Identifier': 'unique-webhook-id',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { ConfluenceIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildConfluenceExtraFields,
|
||||
buildPageOutputs,
|
||||
confluenceSetupInstructions,
|
||||
confluenceTriggerOptions,
|
||||
} from '@/triggers/confluence/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Confluence Page Moved Trigger
|
||||
*
|
||||
* Triggers when a page is moved to a different space or parent in Confluence.
|
||||
*/
|
||||
export const confluencePageMovedTrigger: TriggerConfig = {
|
||||
id: 'confluence_page_moved',
|
||||
name: 'Confluence Page Moved',
|
||||
provider: 'confluence',
|
||||
description: 'Trigger workflow when a page is moved in Confluence',
|
||||
version: '1.0.0',
|
||||
icon: ConfluenceIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'confluence_page_moved',
|
||||
triggerOptions: confluenceTriggerOptions,
|
||||
setupInstructions: confluenceSetupInstructions('page_moved'),
|
||||
extraFields: buildConfluenceExtraFields('confluence_page_moved'),
|
||||
}),
|
||||
|
||||
outputs: buildPageOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Hub-Signature': 'sha256=...',
|
||||
'X-Atlassian-Webhook-Identifier': 'unique-webhook-id',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { ConfluenceIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildConfluenceExtraFields,
|
||||
buildPagePermissionsOutputs,
|
||||
confluenceSetupInstructions,
|
||||
confluenceTriggerOptions,
|
||||
} from '@/triggers/confluence/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Confluence Page Permissions Updated Trigger
|
||||
*
|
||||
* Triggers when page permissions are changed in Confluence.
|
||||
*/
|
||||
export const confluencePagePermissionsUpdatedTrigger: TriggerConfig = {
|
||||
id: 'confluence_page_permissions_updated',
|
||||
name: 'Confluence Page Permissions Updated',
|
||||
provider: 'confluence',
|
||||
description: 'Trigger workflow when page permissions are changed in Confluence',
|
||||
version: '1.0.0',
|
||||
icon: ConfluenceIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'confluence_page_permissions_updated',
|
||||
triggerOptions: confluenceTriggerOptions,
|
||||
setupInstructions: confluenceSetupInstructions('content_permissions_updated'),
|
||||
extraFields: buildConfluenceExtraFields('confluence_page_permissions_updated'),
|
||||
}),
|
||||
|
||||
outputs: buildPagePermissionsOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Hub-Signature': 'sha256=...',
|
||||
'X-Atlassian-Webhook-Identifier': 'unique-webhook-id',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { ConfluenceIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildConfluenceExtraFields,
|
||||
buildPageOutputs,
|
||||
confluenceSetupInstructions,
|
||||
confluenceTriggerOptions,
|
||||
} from '@/triggers/confluence/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Confluence Page Removed Trigger
|
||||
*
|
||||
* Triggers when a page is removed or trashed in Confluence.
|
||||
*/
|
||||
export const confluencePageRemovedTrigger: TriggerConfig = {
|
||||
id: 'confluence_page_removed',
|
||||
name: 'Confluence Page Removed',
|
||||
provider: 'confluence',
|
||||
description: 'Trigger workflow when a page is removed or trashed in Confluence',
|
||||
version: '1.0.0',
|
||||
icon: ConfluenceIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'confluence_page_removed',
|
||||
triggerOptions: confluenceTriggerOptions,
|
||||
setupInstructions: confluenceSetupInstructions('page_removed'),
|
||||
extraFields: buildConfluenceExtraFields('confluence_page_removed'),
|
||||
}),
|
||||
|
||||
outputs: buildPageOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Hub-Signature': 'sha256=...',
|
||||
'X-Atlassian-Webhook-Identifier': 'unique-webhook-id',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { ConfluenceIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildConfluenceExtraFields,
|
||||
buildPageOutputs,
|
||||
confluenceSetupInstructions,
|
||||
confluenceTriggerOptions,
|
||||
} from '@/triggers/confluence/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Confluence Page Restored Trigger
|
||||
*
|
||||
* Triggers when a page is restored from trash in Confluence.
|
||||
*/
|
||||
export const confluencePageRestoredTrigger: TriggerConfig = {
|
||||
id: 'confluence_page_restored',
|
||||
name: 'Confluence Page Restored',
|
||||
provider: 'confluence',
|
||||
description: 'Trigger workflow when a page is restored from trash in Confluence',
|
||||
version: '1.0.0',
|
||||
icon: ConfluenceIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'confluence_page_restored',
|
||||
triggerOptions: confluenceTriggerOptions,
|
||||
setupInstructions: confluenceSetupInstructions('page_restored'),
|
||||
extraFields: buildConfluenceExtraFields('confluence_page_restored'),
|
||||
}),
|
||||
|
||||
outputs: buildPageOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Hub-Signature': 'sha256=...',
|
||||
'X-Atlassian-Webhook-Identifier': 'unique-webhook-id',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { ConfluenceIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildConfluenceExtraFields,
|
||||
buildPageOutputs,
|
||||
confluenceSetupInstructions,
|
||||
confluenceTriggerOptions,
|
||||
} from '@/triggers/confluence/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Confluence Page Updated Trigger
|
||||
*
|
||||
* Triggers when an existing page is updated in Confluence.
|
||||
*/
|
||||
export const confluencePageUpdatedTrigger: TriggerConfig = {
|
||||
id: 'confluence_page_updated',
|
||||
name: 'Confluence Page Updated',
|
||||
provider: 'confluence',
|
||||
description: 'Trigger workflow when a page is updated in Confluence',
|
||||
version: '1.0.0',
|
||||
icon: ConfluenceIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'confluence_page_updated',
|
||||
triggerOptions: confluenceTriggerOptions,
|
||||
setupInstructions: confluenceSetupInstructions('page_updated'),
|
||||
extraFields: buildConfluenceExtraFields('confluence_page_updated'),
|
||||
}),
|
||||
|
||||
outputs: buildPageOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Hub-Signature': 'sha256=...',
|
||||
'X-Atlassian-Webhook-Identifier': 'unique-webhook-id',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { ConfluenceIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildConfluenceExtraFields,
|
||||
buildSpaceOutputs,
|
||||
confluenceSetupInstructions,
|
||||
confluenceTriggerOptions,
|
||||
} from '@/triggers/confluence/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Confluence Space Created Trigger
|
||||
*
|
||||
* Triggers when a new space is created in Confluence.
|
||||
*/
|
||||
export const confluenceSpaceCreatedTrigger: TriggerConfig = {
|
||||
id: 'confluence_space_created',
|
||||
name: 'Confluence Space Created',
|
||||
provider: 'confluence',
|
||||
description: 'Trigger workflow when a new space is created in Confluence',
|
||||
version: '1.0.0',
|
||||
icon: ConfluenceIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'confluence_space_created',
|
||||
triggerOptions: confluenceTriggerOptions,
|
||||
setupInstructions: confluenceSetupInstructions('space_created'),
|
||||
extraFields: buildConfluenceExtraFields('confluence_space_created'),
|
||||
}),
|
||||
|
||||
outputs: buildSpaceOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Hub-Signature': 'sha256=...',
|
||||
'X-Atlassian-Webhook-Identifier': 'unique-webhook-id',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { ConfluenceIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildConfluenceExtraFields,
|
||||
buildSpaceOutputs,
|
||||
confluenceSetupInstructions,
|
||||
confluenceTriggerOptions,
|
||||
} from '@/triggers/confluence/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Confluence Space Removed Trigger
|
||||
*
|
||||
* Triggers when a space is deleted/removed in Confluence.
|
||||
*/
|
||||
export const confluenceSpaceRemovedTrigger: TriggerConfig = {
|
||||
id: 'confluence_space_removed',
|
||||
name: 'Confluence Space Removed',
|
||||
provider: 'confluence',
|
||||
description: 'Trigger workflow when a space is removed in Confluence',
|
||||
version: '1.0.0',
|
||||
icon: ConfluenceIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'confluence_space_removed',
|
||||
triggerOptions: confluenceTriggerOptions,
|
||||
setupInstructions: confluenceSetupInstructions('space_removed'),
|
||||
extraFields: buildConfluenceExtraFields('confluence_space_removed'),
|
||||
}),
|
||||
|
||||
outputs: buildSpaceOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Hub-Signature': 'sha256=...',
|
||||
'X-Atlassian-Webhook-Identifier': 'unique-webhook-id',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { ConfluenceIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildConfluenceExtraFields,
|
||||
buildSpaceOutputs,
|
||||
confluenceSetupInstructions,
|
||||
confluenceTriggerOptions,
|
||||
} from '@/triggers/confluence/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Confluence Space Updated Trigger
|
||||
*
|
||||
* Triggers when a space is updated (settings, permissions, etc.) in Confluence.
|
||||
*/
|
||||
export const confluenceSpaceUpdatedTrigger: TriggerConfig = {
|
||||
id: 'confluence_space_updated',
|
||||
name: 'Confluence Space Updated',
|
||||
provider: 'confluence',
|
||||
description: 'Trigger workflow when a space is updated in Confluence',
|
||||
version: '1.0.0',
|
||||
icon: ConfluenceIcon,
|
||||
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'confluence_space_updated',
|
||||
triggerOptions: confluenceTriggerOptions,
|
||||
setupInstructions: confluenceSetupInstructions('space_updated'),
|
||||
extraFields: buildConfluenceExtraFields('confluence_space_updated'),
|
||||
}),
|
||||
|
||||
outputs: buildSpaceOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Hub-Signature': 'sha256=...',
|
||||
'X-Atlassian-Webhook-Identifier': 'unique-webhook-id',
|
||||
},
|
||||
},
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user