mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-15 01:47:59 -05:00
Compare commits
1 Commits
feat/group
...
sim-499
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
09cea81ae3 |
@@ -0,0 +1,86 @@
|
|||||||
|
import { Button } from '@/components/emcn'
|
||||||
|
import { Alert, AlertDescription } from '@/components/ui/alert'
|
||||||
|
import type { SaveStatus } from '@/hooks/use-auto-save'
|
||||||
|
|
||||||
|
interface SaveStatusIndicatorProps {
|
||||||
|
/** Current save status */
|
||||||
|
status: SaveStatus
|
||||||
|
/** Error message to display */
|
||||||
|
errorMessage: string | null
|
||||||
|
/** Text to show while saving (e.g., "Saving schedule...") */
|
||||||
|
savingText?: string
|
||||||
|
/** Text to show while loading (e.g., "Loading schedule...") */
|
||||||
|
loadingText?: string
|
||||||
|
/** Whether to show loading indicator */
|
||||||
|
isLoading?: boolean
|
||||||
|
/** Callback when retry button is clicked */
|
||||||
|
onRetry?: () => void
|
||||||
|
/** Whether retry is disabled (e.g., during saving) */
|
||||||
|
retryDisabled?: boolean
|
||||||
|
/** Number of retry attempts made */
|
||||||
|
retryCount?: number
|
||||||
|
/** Maximum retry attempts allowed */
|
||||||
|
maxRetries?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shared component for displaying save status indicators.
|
||||||
|
* Shows saving spinner, error alerts with retry, and loading indicators.
|
||||||
|
*/
|
||||||
|
export function SaveStatusIndicator({
|
||||||
|
status,
|
||||||
|
errorMessage,
|
||||||
|
savingText = 'Saving...',
|
||||||
|
loadingText = 'Loading...',
|
||||||
|
isLoading = false,
|
||||||
|
onRetry,
|
||||||
|
retryDisabled = false,
|
||||||
|
retryCount = 0,
|
||||||
|
maxRetries = 3,
|
||||||
|
}: SaveStatusIndicatorProps) {
|
||||||
|
const maxRetriesReached = retryCount >= maxRetries
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/* Saving indicator */}
|
||||||
|
{status === 'saving' && (
|
||||||
|
<div className='flex items-center gap-2 text-muted-foreground text-sm'>
|
||||||
|
<div className='h-4 w-4 animate-spin rounded-full border-[1.5px] border-current border-t-transparent' />
|
||||||
|
{savingText}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Error message with retry */}
|
||||||
|
{errorMessage && (
|
||||||
|
<Alert variant='destructive'>
|
||||||
|
<AlertDescription className='flex items-center justify-between'>
|
||||||
|
<span>
|
||||||
|
{errorMessage}
|
||||||
|
{maxRetriesReached && (
|
||||||
|
<span className='ml-1 text-xs opacity-75'>(Max retries reached)</span>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
{onRetry && (
|
||||||
|
<Button
|
||||||
|
variant='ghost'
|
||||||
|
onClick={onRetry}
|
||||||
|
disabled={retryDisabled || status === 'saving'}
|
||||||
|
className='ml-2 h-6 px-2 text-xs'
|
||||||
|
>
|
||||||
|
Retry
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</AlertDescription>
|
||||||
|
</Alert>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Loading indicator */}
|
||||||
|
{isLoading && status !== 'saving' && (
|
||||||
|
<div className='flex items-center gap-2 text-muted-foreground text-sm'>
|
||||||
|
<div className='h-4 w-4 animate-spin rounded-full border-[1.5px] border-current border-t-transparent' />
|
||||||
|
{loadingText}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,11 +1,9 @@
|
|||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||||
import { useParams } from 'next/navigation'
|
import { useParams } from 'next/navigation'
|
||||||
import { Button, Modal, ModalBody, ModalContent, ModalFooter, ModalHeader } from '@/components/emcn'
|
|
||||||
import { Trash } from '@/components/emcn/icons/trash'
|
|
||||||
import { Alert, AlertDescription } from '@/components/ui/alert'
|
|
||||||
import { cn } from '@/lib/core/utils/cn'
|
|
||||||
import { createLogger } from '@/lib/logs/console/logger'
|
import { createLogger } from '@/lib/logs/console/logger'
|
||||||
import { parseCronToHumanReadable } from '@/lib/workflows/schedules/utils'
|
import { parseCronToHumanReadable } from '@/lib/workflows/schedules/utils'
|
||||||
|
import { SaveStatusIndicator } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/save-status-indicator/save-status-indicator'
|
||||||
|
import { useAutoSave } from '@/hooks/use-auto-save'
|
||||||
import { useCollaborativeWorkflow } from '@/hooks/use-collaborative-workflow'
|
import { useCollaborativeWorkflow } from '@/hooks/use-collaborative-workflow'
|
||||||
import { useScheduleManagement } from '@/hooks/use-schedule-management'
|
import { useScheduleManagement } from '@/hooks/use-schedule-management'
|
||||||
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
|
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
|
||||||
@@ -18,16 +16,9 @@ interface ScheduleSaveProps {
|
|||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
type SaveStatus = 'idle' | 'saving' | 'saved' | 'error'
|
|
||||||
|
|
||||||
export function ScheduleSave({ blockId, isPreview = false, disabled = false }: ScheduleSaveProps) {
|
export function ScheduleSave({ blockId, isPreview = false, disabled = false }: ScheduleSaveProps) {
|
||||||
const params = useParams()
|
const params = useParams()
|
||||||
const workflowId = params.workflowId as string
|
const workflowId = params.workflowId as string
|
||||||
const [saveStatus, setSaveStatus] = useState<SaveStatus>('idle')
|
|
||||||
const [errorMessage, setErrorMessage] = useState<string | null>(null)
|
|
||||||
const [deleteStatus, setDeleteStatus] = useState<'idle' | 'deleting'>('idle')
|
|
||||||
const [showDeleteDialog, setShowDeleteDialog] = useState(false)
|
|
||||||
const [scheduleStatus, setScheduleStatus] = useState<'active' | 'disabled' | null>(null)
|
|
||||||
const [nextRunAt, setNextRunAt] = useState<Date | null>(null)
|
const [nextRunAt, setNextRunAt] = useState<Date | null>(null)
|
||||||
const [lastRanAt, setLastRanAt] = useState<Date | null>(null)
|
const [lastRanAt, setLastRanAt] = useState<Date | null>(null)
|
||||||
const [failedCount, setFailedCount] = useState<number>(0)
|
const [failedCount, setFailedCount] = useState<number>(0)
|
||||||
@@ -36,7 +27,7 @@ export function ScheduleSave({ blockId, isPreview = false, disabled = false }: S
|
|||||||
|
|
||||||
const { collaborativeSetSubblockValue } = useCollaborativeWorkflow()
|
const { collaborativeSetSubblockValue } = useCollaborativeWorkflow()
|
||||||
|
|
||||||
const { scheduleId, saveConfig, deleteConfig, isSaving } = useScheduleManagement({
|
const { scheduleId, saveConfig, isSaving } = useScheduleManagement({
|
||||||
blockId,
|
blockId,
|
||||||
isPreview,
|
isPreview,
|
||||||
})
|
})
|
||||||
@@ -56,13 +47,8 @@ export function ScheduleSave({ blockId, isPreview = false, disabled = false }: S
|
|||||||
)
|
)
|
||||||
const scheduleTimezone = useSubBlockStore((state) => state.getValue(blockId, 'timezone'))
|
const scheduleTimezone = useSubBlockStore((state) => state.getValue(blockId, 'timezone'))
|
||||||
|
|
||||||
const validateRequiredFields = useCallback((): { valid: boolean; missingFields: string[] } => {
|
const validateRequiredFields = useCallback((): boolean => {
|
||||||
const missingFields: string[] = []
|
if (!scheduleType) return false
|
||||||
|
|
||||||
if (!scheduleType) {
|
|
||||||
missingFields.push('Frequency')
|
|
||||||
return { valid: false, missingFields }
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (scheduleType) {
|
switch (scheduleType) {
|
||||||
case 'minutes': {
|
case 'minutes': {
|
||||||
@@ -73,7 +59,7 @@ export function ScheduleSave({ blockId, isPreview = false, disabled = false }: S
|
|||||||
minutesNum < 1 ||
|
minutesNum < 1 ||
|
||||||
minutesNum > 1440
|
minutesNum > 1440
|
||||||
) {
|
) {
|
||||||
missingFields.push('Minutes Interval (must be 1-1440)')
|
return false
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -87,48 +73,39 @@ export function ScheduleSave({ blockId, isPreview = false, disabled = false }: S
|
|||||||
hourlyNum < 0 ||
|
hourlyNum < 0 ||
|
||||||
hourlyNum > 59
|
hourlyNum > 59
|
||||||
) {
|
) {
|
||||||
missingFields.push('Minute (must be 0-59)')
|
return false
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'daily':
|
case 'daily':
|
||||||
if (!scheduleDailyTime) {
|
if (!scheduleDailyTime) return false
|
||||||
missingFields.push('Time')
|
|
||||||
}
|
|
||||||
break
|
break
|
||||||
case 'weekly':
|
case 'weekly':
|
||||||
if (!scheduleWeeklyDay) {
|
if (!scheduleWeeklyDay || !scheduleWeeklyTime) return false
|
||||||
missingFields.push('Day of Week')
|
|
||||||
}
|
|
||||||
if (!scheduleWeeklyTime) {
|
|
||||||
missingFields.push('Time')
|
|
||||||
}
|
|
||||||
break
|
break
|
||||||
case 'monthly': {
|
case 'monthly': {
|
||||||
const monthlyNum = Number(scheduleMonthlyDay)
|
const monthlyNum = Number(scheduleMonthlyDay)
|
||||||
if (!scheduleMonthlyDay || Number.isNaN(monthlyNum) || monthlyNum < 1 || monthlyNum > 31) {
|
if (
|
||||||
missingFields.push('Day of Month (must be 1-31)')
|
!scheduleMonthlyDay ||
|
||||||
}
|
Number.isNaN(monthlyNum) ||
|
||||||
if (!scheduleMonthlyTime) {
|
monthlyNum < 1 ||
|
||||||
missingFields.push('Time')
|
monthlyNum > 31 ||
|
||||||
|
!scheduleMonthlyTime
|
||||||
|
) {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'custom':
|
case 'custom':
|
||||||
if (!scheduleCronExpression) {
|
if (!scheduleCronExpression) return false
|
||||||
missingFields.push('Cron Expression')
|
|
||||||
}
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!scheduleTimezone && scheduleType !== 'minutes' && scheduleType !== 'hourly') {
|
if (!scheduleTimezone && scheduleType !== 'minutes' && scheduleType !== 'hourly') {
|
||||||
missingFields.push('Timezone')
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return true
|
||||||
valid: missingFields.length === 0,
|
|
||||||
missingFields,
|
|
||||||
}
|
|
||||||
}, [
|
}, [
|
||||||
scheduleType,
|
scheduleType,
|
||||||
scheduleMinutesInterval,
|
scheduleMinutesInterval,
|
||||||
@@ -160,7 +137,7 @@ export function ScheduleSave({ blockId, isPreview = false, disabled = false }: S
|
|||||||
const subscribedSubBlockValues = useSubBlockStore(
|
const subscribedSubBlockValues = useSubBlockStore(
|
||||||
useCallback(
|
useCallback(
|
||||||
(state) => {
|
(state) => {
|
||||||
const values: Record<string, any> = {}
|
const values: Record<string, unknown> = {}
|
||||||
requiredSubBlockIds.forEach((subBlockId) => {
|
requiredSubBlockIds.forEach((subBlockId) => {
|
||||||
const value = state.getValue(blockId, subBlockId)
|
const value = state.getValue(blockId, subBlockId)
|
||||||
if (value !== null && value !== undefined && value !== '') {
|
if (value !== null && value !== undefined && value !== '') {
|
||||||
@@ -173,52 +150,57 @@ export function ScheduleSave({ blockId, isPreview = false, disabled = false }: S
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
const previousValuesRef = useRef<Record<string, any>>({})
|
const configFingerprint = useMemo(() => {
|
||||||
const validationTimeoutRef = useRef<NodeJS.Timeout | null>(null)
|
return JSON.stringify(subscribedSubBlockValues)
|
||||||
|
}, [subscribedSubBlockValues])
|
||||||
|
|
||||||
|
const handleSaveSuccess = useCallback(
|
||||||
|
async (result: { success: boolean; nextRunAt?: string; cronExpression?: string }) => {
|
||||||
|
const scheduleIdValue = useSubBlockStore.getState().getValue(blockId, 'scheduleId')
|
||||||
|
collaborativeSetSubblockValue(blockId, 'scheduleId', scheduleIdValue)
|
||||||
|
|
||||||
|
if (result.nextRunAt) {
|
||||||
|
setNextRunAt(new Date(result.nextRunAt))
|
||||||
|
}
|
||||||
|
|
||||||
|
await fetchScheduleStatus()
|
||||||
|
|
||||||
|
if (result.cronExpression) {
|
||||||
|
setSavedCronExpression(result.cronExpression)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[blockId, collaborativeSetSubblockValue]
|
||||||
|
)
|
||||||
|
|
||||||
|
const {
|
||||||
|
saveStatus,
|
||||||
|
errorMessage,
|
||||||
|
retryCount,
|
||||||
|
maxRetries,
|
||||||
|
triggerSave,
|
||||||
|
onConfigChange,
|
||||||
|
markInitialLoadComplete,
|
||||||
|
} = useAutoSave({
|
||||||
|
disabled: isPreview || disabled,
|
||||||
|
isExternallySaving: isSaving,
|
||||||
|
validate: validateRequiredFields,
|
||||||
|
onSave: saveConfig,
|
||||||
|
onSaveSuccess: handleSaveSuccess,
|
||||||
|
loggerName: 'ScheduleSave',
|
||||||
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (saveStatus !== 'error') {
|
onConfigChange(configFingerprint)
|
||||||
previousValuesRef.current = subscribedSubBlockValues
|
}, [configFingerprint, onConfigChange])
|
||||||
return
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isLoadingStatus && scheduleId) {
|
||||||
|
return markInitialLoadComplete(configFingerprint)
|
||||||
}
|
}
|
||||||
|
if (!scheduleId && !isLoadingStatus) {
|
||||||
const hasChanges = Object.keys(subscribedSubBlockValues).some(
|
return markInitialLoadComplete(configFingerprint)
|
||||||
(key) =>
|
|
||||||
previousValuesRef.current[key] !== (subscribedSubBlockValues as Record<string, any>)[key]
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!hasChanges) {
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
}, [isLoadingStatus, scheduleId, configFingerprint, markInitialLoadComplete])
|
||||||
if (validationTimeoutRef.current) {
|
|
||||||
clearTimeout(validationTimeoutRef.current)
|
|
||||||
}
|
|
||||||
|
|
||||||
validationTimeoutRef.current = setTimeout(() => {
|
|
||||||
const validation = validateRequiredFields()
|
|
||||||
|
|
||||||
if (validation.valid) {
|
|
||||||
setErrorMessage(null)
|
|
||||||
setSaveStatus('idle')
|
|
||||||
logger.debug('Error cleared after validation passed', { blockId })
|
|
||||||
} else {
|
|
||||||
setErrorMessage(`Missing required fields: ${validation.missingFields.join(', ')}`)
|
|
||||||
logger.debug('Error message updated', {
|
|
||||||
blockId,
|
|
||||||
missingFields: validation.missingFields,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
previousValuesRef.current = subscribedSubBlockValues
|
|
||||||
}, 300)
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
if (validationTimeoutRef.current) {
|
|
||||||
clearTimeout(validationTimeoutRef.current)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [blockId, subscribedSubBlockValues, saveStatus, validateRequiredFields])
|
|
||||||
|
|
||||||
const fetchScheduleStatus = useCallback(async () => {
|
const fetchScheduleStatus = useCallback(async () => {
|
||||||
if (!scheduleId || isPreview) return
|
if (!scheduleId || isPreview) return
|
||||||
@@ -231,7 +213,6 @@ export function ScheduleSave({ blockId, isPreview = false, disabled = false }: S
|
|||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const data = await response.json()
|
const data = await response.json()
|
||||||
if (data.schedule) {
|
if (data.schedule) {
|
||||||
setScheduleStatus(data.schedule.status)
|
|
||||||
setNextRunAt(data.schedule.nextRunAt ? new Date(data.schedule.nextRunAt) : null)
|
setNextRunAt(data.schedule.nextRunAt ? new Date(data.schedule.nextRunAt) : null)
|
||||||
setLastRanAt(data.schedule.lastRanAt ? new Date(data.schedule.lastRanAt) : null)
|
setLastRanAt(data.schedule.lastRanAt ? new Date(data.schedule.lastRanAt) : null)
|
||||||
setFailedCount(data.schedule.failedCount || 0)
|
setFailedCount(data.schedule.failedCount || 0)
|
||||||
@@ -251,249 +232,82 @@ export function ScheduleSave({ blockId, isPreview = false, disabled = false }: S
|
|||||||
}
|
}
|
||||||
}, [scheduleId, isPreview, fetchScheduleStatus])
|
}, [scheduleId, isPreview, fetchScheduleStatus])
|
||||||
|
|
||||||
const handleSave = async () => {
|
if (isPreview) {
|
||||||
if (isPreview || disabled) return
|
return null
|
||||||
|
|
||||||
setSaveStatus('saving')
|
|
||||||
setErrorMessage(null)
|
|
||||||
|
|
||||||
try {
|
|
||||||
const validation = validateRequiredFields()
|
|
||||||
if (!validation.valid) {
|
|
||||||
setErrorMessage(`Missing required fields: ${validation.missingFields.join(', ')}`)
|
|
||||||
setSaveStatus('error')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await saveConfig()
|
|
||||||
if (!result.success) {
|
|
||||||
throw new Error('Save config returned false')
|
|
||||||
}
|
|
||||||
|
|
||||||
setSaveStatus('saved')
|
|
||||||
setErrorMessage(null)
|
|
||||||
|
|
||||||
const scheduleIdValue = useSubBlockStore.getState().getValue(blockId, 'scheduleId')
|
|
||||||
collaborativeSetSubblockValue(blockId, 'scheduleId', scheduleIdValue)
|
|
||||||
|
|
||||||
if (result.nextRunAt) {
|
|
||||||
setNextRunAt(new Date(result.nextRunAt))
|
|
||||||
setScheduleStatus('active')
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch additional status info, then apply cron from save result to prevent stale data
|
|
||||||
await fetchScheduleStatus()
|
|
||||||
|
|
||||||
if (result.cronExpression) {
|
|
||||||
setSavedCronExpression(result.cronExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
setSaveStatus('idle')
|
|
||||||
}, 2000)
|
|
||||||
|
|
||||||
logger.info('Schedule configuration saved successfully', {
|
|
||||||
blockId,
|
|
||||||
hasScheduleId: !!scheduleId,
|
|
||||||
})
|
|
||||||
} catch (error: any) {
|
|
||||||
setSaveStatus('error')
|
|
||||||
setErrorMessage(error.message || 'An error occurred while saving.')
|
|
||||||
logger.error('Error saving schedule config', { error })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleDelete = async () => {
|
const hasScheduleInfo = scheduleId || isLoadingStatus || saveStatus === 'saving' || errorMessage
|
||||||
if (isPreview || disabled) return
|
|
||||||
|
|
||||||
setShowDeleteDialog(false)
|
if (!hasScheduleInfo) {
|
||||||
setDeleteStatus('deleting')
|
return null
|
||||||
|
|
||||||
try {
|
|
||||||
const success = await deleteConfig()
|
|
||||||
if (!success) {
|
|
||||||
throw new Error('Failed to delete schedule')
|
|
||||||
}
|
|
||||||
|
|
||||||
setScheduleStatus(null)
|
|
||||||
setNextRunAt(null)
|
|
||||||
setLastRanAt(null)
|
|
||||||
setFailedCount(0)
|
|
||||||
|
|
||||||
collaborativeSetSubblockValue(blockId, 'scheduleId', null)
|
|
||||||
|
|
||||||
logger.info('Schedule deleted successfully', { blockId })
|
|
||||||
} catch (error: any) {
|
|
||||||
setErrorMessage(error.message || 'An error occurred while deleting.')
|
|
||||||
logger.error('Error deleting schedule', { error })
|
|
||||||
} finally {
|
|
||||||
setDeleteStatus('idle')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleDeleteConfirm = () => {
|
|
||||||
handleDelete()
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleToggleStatus = async () => {
|
|
||||||
if (!scheduleId || isPreview || disabled) return
|
|
||||||
|
|
||||||
try {
|
|
||||||
const action = scheduleStatus === 'active' ? 'disable' : 'reactivate'
|
|
||||||
const response = await fetch(`/api/schedules/${scheduleId}`, {
|
|
||||||
method: 'PUT',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
body: JSON.stringify({ action }),
|
|
||||||
})
|
|
||||||
|
|
||||||
if (response.ok) {
|
|
||||||
await fetchScheduleStatus()
|
|
||||||
logger.info(`Schedule ${action}d successfully`, { scheduleId })
|
|
||||||
} else {
|
|
||||||
throw new Error(`Failed to ${action} schedule`)
|
|
||||||
}
|
|
||||||
} catch (error: any) {
|
|
||||||
setErrorMessage(
|
|
||||||
error.message ||
|
|
||||||
`An error occurred while ${scheduleStatus === 'active' ? 'disabling' : 'reactivating'} the schedule.`
|
|
||||||
)
|
|
||||||
logger.error('Error toggling schedule status', { error })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='mt-2'>
|
<div className='space-y-1 pb-4'>
|
||||||
<div className='flex gap-2'>
|
<SaveStatusIndicator
|
||||||
<Button
|
status={saveStatus}
|
||||||
variant='default'
|
errorMessage={errorMessage}
|
||||||
onClick={handleSave}
|
savingText='Saving schedule...'
|
||||||
disabled={disabled || isPreview || isSaving || saveStatus === 'saving' || isLoadingStatus}
|
loadingText='Loading schedule...'
|
||||||
className={cn(
|
isLoading={isLoadingStatus}
|
||||||
'h-9 flex-1 rounded-[8px] transition-all duration-200',
|
onRetry={triggerSave}
|
||||||
saveStatus === 'saved' && 'bg-green-600 hover:bg-green-700',
|
retryDisabled={isSaving}
|
||||||
saveStatus === 'error' && 'bg-red-600 hover:bg-red-700'
|
retryCount={retryCount}
|
||||||
)}
|
maxRetries={maxRetries}
|
||||||
>
|
/>
|
||||||
{saveStatus === 'saving' && (
|
|
||||||
<>
|
|
||||||
<div className='mr-2 h-4 w-4 animate-spin rounded-full border-[1.5px] border-current border-t-transparent' />
|
|
||||||
Saving...
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{saveStatus === 'saved' && 'Saved'}
|
|
||||||
{saveStatus === 'idle' && (scheduleId ? 'Update Schedule' : 'Save Schedule')}
|
|
||||||
{saveStatus === 'error' && 'Error'}
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
{scheduleId && (
|
{/* Schedule status info */}
|
||||||
<Button
|
{scheduleId && !isLoadingStatus && saveStatus !== 'saving' && (
|
||||||
variant='default'
|
<>
|
||||||
onClick={() => setShowDeleteDialog(true)}
|
{failedCount > 0 && (
|
||||||
disabled={disabled || isPreview || deleteStatus === 'deleting' || isSaving}
|
<p className='text-destructive text-sm'>
|
||||||
className='h-9 rounded-[8px] px-3'
|
{failedCount} failed run{failedCount !== 1 ? 's' : ''}
|
||||||
>
|
|
||||||
{deleteStatus === 'deleting' ? (
|
|
||||||
<div className='h-4 w-4 animate-spin rounded-full border-[1.5px] border-current border-t-transparent' />
|
|
||||||
) : (
|
|
||||||
<Trash className='h-[14px] w-[14px]' />
|
|
||||||
)}
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{errorMessage && (
|
|
||||||
<Alert variant='destructive' className='mt-2'>
|
|
||||||
<AlertDescription>{errorMessage}</AlertDescription>
|
|
||||||
</Alert>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{scheduleId && (scheduleStatus || isLoadingStatus || nextRunAt) && (
|
|
||||||
<div className='mt-2 space-y-1'>
|
|
||||||
{isLoadingStatus ? (
|
|
||||||
<div className='flex items-center gap-2 text-muted-foreground text-sm'>
|
|
||||||
<div className='h-4 w-4 animate-spin rounded-full border-[1.5px] border-current border-t-transparent' />
|
|
||||||
Loading schedule status...
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
{failedCount > 0 && (
|
|
||||||
<div className='flex items-center gap-2'>
|
|
||||||
<span className='text-destructive text-sm'>
|
|
||||||
⚠️ {failedCount} failed run{failedCount !== 1 ? 's' : ''}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{savedCronExpression && (
|
|
||||||
<p className='text-muted-foreground text-sm'>
|
|
||||||
Runs{' '}
|
|
||||||
{parseCronToHumanReadable(
|
|
||||||
savedCronExpression,
|
|
||||||
scheduleTimezone || 'UTC'
|
|
||||||
).toLowerCase()}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{nextRunAt && (
|
|
||||||
<p className='text-sm'>
|
|
||||||
<span className='font-medium'>Next run:</span>{' '}
|
|
||||||
{nextRunAt.toLocaleString('en-US', {
|
|
||||||
timeZone: scheduleTimezone || 'UTC',
|
|
||||||
year: 'numeric',
|
|
||||||
month: 'numeric',
|
|
||||||
day: 'numeric',
|
|
||||||
hour: 'numeric',
|
|
||||||
minute: '2-digit',
|
|
||||||
hour12: true,
|
|
||||||
})}{' '}
|
|
||||||
{scheduleTimezone || 'UTC'}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{lastRanAt && (
|
|
||||||
<p className='text-muted-foreground text-sm'>
|
|
||||||
<span className='font-medium'>Last ran:</span>{' '}
|
|
||||||
{lastRanAt.toLocaleString('en-US', {
|
|
||||||
timeZone: scheduleTimezone || 'UTC',
|
|
||||||
year: 'numeric',
|
|
||||||
month: 'numeric',
|
|
||||||
day: 'numeric',
|
|
||||||
hour: 'numeric',
|
|
||||||
minute: '2-digit',
|
|
||||||
hour12: true,
|
|
||||||
})}{' '}
|
|
||||||
{scheduleTimezone || 'UTC'}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Modal open={showDeleteDialog} onOpenChange={setShowDeleteDialog}>
|
|
||||||
<ModalContent size='sm'>
|
|
||||||
<ModalHeader>Delete Schedule</ModalHeader>
|
|
||||||
<ModalBody>
|
|
||||||
<p className='text-[12px] text-[var(--text-tertiary)]'>
|
|
||||||
Are you sure you want to delete this schedule configuration? This will stop the
|
|
||||||
workflow from running automatically.{' '}
|
|
||||||
<span className='text-[var(--text-error)]'>This action cannot be undone.</span>
|
|
||||||
</p>
|
</p>
|
||||||
</ModalBody>
|
)}
|
||||||
<ModalFooter>
|
|
||||||
<Button variant='active' onClick={() => setShowDeleteDialog(false)}>
|
{savedCronExpression && (
|
||||||
Cancel
|
<p className='text-muted-foreground text-sm'>
|
||||||
</Button>
|
Runs{' '}
|
||||||
<Button
|
{parseCronToHumanReadable(
|
||||||
variant='primary'
|
savedCronExpression,
|
||||||
onClick={handleDeleteConfirm}
|
scheduleTimezone || 'UTC'
|
||||||
className='!bg-[var(--text-error)] !text-white hover:!bg-[var(--text-error)]/90'
|
).toLowerCase()}
|
||||||
>
|
</p>
|
||||||
Delete
|
)}
|
||||||
</Button>
|
|
||||||
</ModalFooter>
|
{nextRunAt && (
|
||||||
</ModalContent>
|
<p className='text-sm'>
|
||||||
</Modal>
|
<span className='font-medium'>Next run:</span>{' '}
|
||||||
|
{nextRunAt.toLocaleString('en-US', {
|
||||||
|
timeZone: scheduleTimezone || 'UTC',
|
||||||
|
year: 'numeric',
|
||||||
|
month: 'numeric',
|
||||||
|
day: 'numeric',
|
||||||
|
hour: 'numeric',
|
||||||
|
minute: '2-digit',
|
||||||
|
hour12: true,
|
||||||
|
})}{' '}
|
||||||
|
{scheduleTimezone || 'UTC'}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{lastRanAt && (
|
||||||
|
<p className='text-muted-foreground text-sm'>
|
||||||
|
<span className='font-medium'>Last ran:</span>{' '}
|
||||||
|
{lastRanAt.toLocaleString('en-US', {
|
||||||
|
timeZone: scheduleTimezone || 'UTC',
|
||||||
|
year: 'numeric',
|
||||||
|
month: 'numeric',
|
||||||
|
day: 'numeric',
|
||||||
|
hour: 'numeric',
|
||||||
|
minute: '2-digit',
|
||||||
|
hour12: true,
|
||||||
|
})}{' '}
|
||||||
|
{scheduleTimezone || 'UTC'}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,15 @@
|
|||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||||
import {
|
import { Button } from '@/components/emcn/components'
|
||||||
Button,
|
|
||||||
Modal,
|
|
||||||
ModalBody,
|
|
||||||
ModalContent,
|
|
||||||
ModalFooter,
|
|
||||||
ModalHeader,
|
|
||||||
} from '@/components/emcn/components'
|
|
||||||
import { Trash } from '@/components/emcn/icons/trash'
|
|
||||||
import { Alert, AlertDescription } from '@/components/ui/alert'
|
|
||||||
import { cn } from '@/lib/core/utils/cn'
|
|
||||||
import { createLogger } from '@/lib/logs/console/logger'
|
import { createLogger } from '@/lib/logs/console/logger'
|
||||||
|
import { SaveStatusIndicator } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/save-status-indicator/save-status-indicator'
|
||||||
|
import { ShortInput } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/short-input/short-input'
|
||||||
|
import { useAutoSave } from '@/hooks/use-auto-save'
|
||||||
import { useCollaborativeWorkflow } from '@/hooks/use-collaborative-workflow'
|
import { useCollaborativeWorkflow } from '@/hooks/use-collaborative-workflow'
|
||||||
import { useTriggerConfigAggregation } from '@/hooks/use-trigger-config-aggregation'
|
import { getTriggerConfigAggregation } from '@/hooks/use-trigger-config-aggregation'
|
||||||
import { useWebhookManagement } from '@/hooks/use-webhook-management'
|
import { useWebhookManagement } from '@/hooks/use-webhook-management'
|
||||||
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
|
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
|
||||||
import { getTrigger, isTriggerValid } from '@/triggers'
|
import { getTrigger, isTriggerValid } from '@/triggers'
|
||||||
import { SYSTEM_SUBBLOCK_IDS } from '@/triggers/constants'
|
import { SYSTEM_SUBBLOCK_IDS } from '@/triggers/constants'
|
||||||
import { ShortInput } from '../short-input/short-input'
|
|
||||||
|
|
||||||
const logger = createLogger('TriggerSave')
|
const logger = createLogger('TriggerSave')
|
||||||
|
|
||||||
@@ -29,8 +21,6 @@ interface TriggerSaveProps {
|
|||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
type SaveStatus = 'idle' | 'saving' | 'saved' | 'error'
|
|
||||||
|
|
||||||
export function TriggerSave({
|
export function TriggerSave({
|
||||||
blockId,
|
blockId,
|
||||||
subBlockId,
|
subBlockId,
|
||||||
@@ -38,11 +28,8 @@ export function TriggerSave({
|
|||||||
isPreview = false,
|
isPreview = false,
|
||||||
disabled = false,
|
disabled = false,
|
||||||
}: TriggerSaveProps) {
|
}: TriggerSaveProps) {
|
||||||
const [saveStatus, setSaveStatus] = useState<SaveStatus>('idle')
|
|
||||||
const [errorMessage, setErrorMessage] = useState<string | null>(null)
|
|
||||||
const [deleteStatus, setDeleteStatus] = useState<'idle' | 'deleting'>('idle')
|
|
||||||
const [showDeleteDialog, setShowDeleteDialog] = useState(false)
|
|
||||||
const [isGeneratingTestUrl, setIsGeneratingTestUrl] = useState(false)
|
const [isGeneratingTestUrl, setIsGeneratingTestUrl] = useState(false)
|
||||||
|
const [testUrlError, setTestUrlError] = useState<string | null>(null)
|
||||||
|
|
||||||
const storedTestUrl = useSubBlockStore((state) => state.getValue(blockId, 'testUrl'))
|
const storedTestUrl = useSubBlockStore((state) => state.getValue(blockId, 'testUrl'))
|
||||||
const storedTestUrlExpiresAt = useSubBlockStore((state) =>
|
const storedTestUrlExpiresAt = useSubBlockStore((state) =>
|
||||||
@@ -70,13 +57,12 @@ export function TriggerSave({
|
|||||||
|
|
||||||
const { collaborativeSetSubblockValue } = useCollaborativeWorkflow()
|
const { collaborativeSetSubblockValue } = useCollaborativeWorkflow()
|
||||||
|
|
||||||
const { webhookId, saveConfig, deleteConfig, isLoading } = useWebhookManagement({
|
const { webhookId, saveConfig, isLoading } = useWebhookManagement({
|
||||||
blockId,
|
blockId,
|
||||||
triggerId: effectiveTriggerId,
|
triggerId: effectiveTriggerId,
|
||||||
isPreview,
|
isPreview,
|
||||||
})
|
})
|
||||||
|
|
||||||
const triggerConfig = useSubBlockStore((state) => state.getValue(blockId, 'triggerConfig'))
|
|
||||||
const triggerCredentials = useSubBlockStore((state) =>
|
const triggerCredentials = useSubBlockStore((state) =>
|
||||||
state.getValue(blockId, 'triggerCredentials')
|
state.getValue(blockId, 'triggerCredentials')
|
||||||
)
|
)
|
||||||
@@ -87,40 +73,26 @@ export function TriggerSave({
|
|||||||
const hasWebhookUrlDisplay =
|
const hasWebhookUrlDisplay =
|
||||||
triggerDef?.subBlocks.some((sb) => sb.id === 'webhookUrlDisplay') ?? false
|
triggerDef?.subBlocks.some((sb) => sb.id === 'webhookUrlDisplay') ?? false
|
||||||
|
|
||||||
const validateRequiredFields = useCallback(
|
const validateRequiredFields = useCallback((): boolean => {
|
||||||
(
|
if (!triggerDef) return true
|
||||||
configToCheck: Record<string, any> | null | undefined
|
|
||||||
): { valid: boolean; missingFields: string[] } => {
|
const aggregatedConfig = getTriggerConfigAggregation(blockId, effectiveTriggerId)
|
||||||
if (!triggerDef) {
|
|
||||||
return { valid: true, missingFields: [] }
|
const requiredSubBlocks = triggerDef.subBlocks.filter(
|
||||||
|
(sb) => sb.required && sb.mode === 'trigger' && !SYSTEM_SUBBLOCK_IDS.includes(sb.id)
|
||||||
|
)
|
||||||
|
|
||||||
|
for (const subBlock of requiredSubBlocks) {
|
||||||
|
if (subBlock.id === 'triggerCredentials') {
|
||||||
|
if (!triggerCredentials) return false
|
||||||
|
} else {
|
||||||
|
const value = aggregatedConfig?.[subBlock.id]
|
||||||
|
if (value === undefined || value === null || value === '') return false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const missingFields: string[] = []
|
return true
|
||||||
|
}, [triggerDef, triggerCredentials, blockId, effectiveTriggerId])
|
||||||
triggerDef.subBlocks
|
|
||||||
.filter(
|
|
||||||
(sb) => sb.required && sb.mode === 'trigger' && !SYSTEM_SUBBLOCK_IDS.includes(sb.id)
|
|
||||||
)
|
|
||||||
.forEach((subBlock) => {
|
|
||||||
if (subBlock.id === 'triggerCredentials') {
|
|
||||||
if (!triggerCredentials) {
|
|
||||||
missingFields.push(subBlock.title || 'Credentials')
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const value = configToCheck?.[subBlock.id]
|
|
||||||
if (value === undefined || value === null || value === '') {
|
|
||||||
missingFields.push(subBlock.title || subBlock.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return {
|
|
||||||
valid: missingFields.length === 0,
|
|
||||||
missingFields,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[triggerDef, triggerCredentials]
|
|
||||||
)
|
|
||||||
|
|
||||||
const requiredSubBlockIds = useMemo(() => {
|
const requiredSubBlockIds = useMemo(() => {
|
||||||
if (!triggerDef) return []
|
if (!triggerDef) return []
|
||||||
@@ -133,11 +105,11 @@ export function TriggerSave({
|
|||||||
useCallback(
|
useCallback(
|
||||||
(state) => {
|
(state) => {
|
||||||
if (!triggerDef) return {}
|
if (!triggerDef) return {}
|
||||||
const values: Record<string, any> = {}
|
const values: Record<string, unknown> = {}
|
||||||
requiredSubBlockIds.forEach((subBlockId) => {
|
requiredSubBlockIds.forEach((id) => {
|
||||||
const value = state.getValue(blockId, subBlockId)
|
const value = state.getValue(blockId, id)
|
||||||
if (value !== null && value !== undefined && value !== '') {
|
if (value !== null && value !== undefined && value !== '') {
|
||||||
values[subBlockId] = value
|
values[id] = value
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return values
|
return values
|
||||||
@@ -146,69 +118,9 @@ export function TriggerSave({
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
const previousValuesRef = useRef<Record<string, any>>({})
|
const configFingerprint = useMemo(() => {
|
||||||
const validationTimeoutRef = useRef<NodeJS.Timeout | null>(null)
|
return JSON.stringify({ ...subscribedSubBlockValues, triggerCredentials })
|
||||||
|
}, [subscribedSubBlockValues, triggerCredentials])
|
||||||
useEffect(() => {
|
|
||||||
if (saveStatus !== 'error' || !triggerDef) {
|
|
||||||
previousValuesRef.current = subscribedSubBlockValues
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const hasChanges = Object.keys(subscribedSubBlockValues).some(
|
|
||||||
(key) =>
|
|
||||||
previousValuesRef.current[key] !== (subscribedSubBlockValues as Record<string, any>)[key]
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!hasChanges) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (validationTimeoutRef.current) {
|
|
||||||
clearTimeout(validationTimeoutRef.current)
|
|
||||||
}
|
|
||||||
|
|
||||||
validationTimeoutRef.current = setTimeout(() => {
|
|
||||||
const aggregatedConfig = useTriggerConfigAggregation(blockId, effectiveTriggerId)
|
|
||||||
|
|
||||||
if (aggregatedConfig) {
|
|
||||||
useSubBlockStore.getState().setValue(blockId, 'triggerConfig', aggregatedConfig)
|
|
||||||
}
|
|
||||||
|
|
||||||
const validation = validateRequiredFields(aggregatedConfig)
|
|
||||||
|
|
||||||
if (validation.valid) {
|
|
||||||
setErrorMessage(null)
|
|
||||||
setSaveStatus('idle')
|
|
||||||
logger.debug('Error cleared after validation passed', {
|
|
||||||
blockId,
|
|
||||||
triggerId: effectiveTriggerId,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
setErrorMessage(`Missing required fields: ${validation.missingFields.join(', ')}`)
|
|
||||||
logger.debug('Error message updated', {
|
|
||||||
blockId,
|
|
||||||
triggerId: effectiveTriggerId,
|
|
||||||
missingFields: validation.missingFields,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
previousValuesRef.current = subscribedSubBlockValues
|
|
||||||
}, 300)
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
if (validationTimeoutRef.current) {
|
|
||||||
clearTimeout(validationTimeoutRef.current)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [
|
|
||||||
blockId,
|
|
||||||
effectiveTriggerId,
|
|
||||||
triggerDef,
|
|
||||||
subscribedSubBlockValues,
|
|
||||||
saveStatus,
|
|
||||||
validateRequiredFields,
|
|
||||||
])
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isTestUrlExpired && storedTestUrl) {
|
if (isTestUrlExpired && storedTestUrl) {
|
||||||
@@ -217,69 +129,63 @@ export function TriggerSave({
|
|||||||
}
|
}
|
||||||
}, [blockId, isTestUrlExpired, storedTestUrl])
|
}, [blockId, isTestUrlExpired, storedTestUrl])
|
||||||
|
|
||||||
const handleSave = async () => {
|
const handleSave = useCallback(async () => {
|
||||||
if (isPreview || disabled) return
|
const aggregatedConfig = getTriggerConfigAggregation(blockId, effectiveTriggerId)
|
||||||
|
|
||||||
setSaveStatus('saving')
|
if (aggregatedConfig) {
|
||||||
setErrorMessage(null)
|
useSubBlockStore.getState().setValue(blockId, 'triggerConfig', aggregatedConfig)
|
||||||
|
|
||||||
try {
|
|
||||||
const aggregatedConfig = useTriggerConfigAggregation(blockId, effectiveTriggerId)
|
|
||||||
|
|
||||||
if (aggregatedConfig) {
|
|
||||||
useSubBlockStore.getState().setValue(blockId, 'triggerConfig', aggregatedConfig)
|
|
||||||
logger.debug('Stored aggregated trigger config', {
|
|
||||||
blockId,
|
|
||||||
triggerId: effectiveTriggerId,
|
|
||||||
aggregatedConfig,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const validation = validateRequiredFields(aggregatedConfig)
|
|
||||||
if (!validation.valid) {
|
|
||||||
setErrorMessage(`Missing required fields: ${validation.missingFields.join(', ')}`)
|
|
||||||
setSaveStatus('error')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const success = await saveConfig()
|
|
||||||
if (!success) {
|
|
||||||
throw new Error('Save config returned false')
|
|
||||||
}
|
|
||||||
|
|
||||||
setSaveStatus('saved')
|
|
||||||
setErrorMessage(null)
|
|
||||||
|
|
||||||
const savedWebhookId = useSubBlockStore.getState().getValue(blockId, 'webhookId')
|
|
||||||
const savedTriggerPath = useSubBlockStore.getState().getValue(blockId, 'triggerPath')
|
|
||||||
const savedTriggerId = useSubBlockStore.getState().getValue(blockId, 'triggerId')
|
|
||||||
const savedTriggerConfig = useSubBlockStore.getState().getValue(blockId, 'triggerConfig')
|
|
||||||
|
|
||||||
collaborativeSetSubblockValue(blockId, 'webhookId', savedWebhookId)
|
|
||||||
collaborativeSetSubblockValue(blockId, 'triggerPath', savedTriggerPath)
|
|
||||||
collaborativeSetSubblockValue(blockId, 'triggerId', savedTriggerId)
|
|
||||||
collaborativeSetSubblockValue(blockId, 'triggerConfig', savedTriggerConfig)
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
setSaveStatus('idle')
|
|
||||||
}, 2000)
|
|
||||||
|
|
||||||
logger.info('Trigger configuration saved successfully', {
|
|
||||||
blockId,
|
|
||||||
triggerId: effectiveTriggerId,
|
|
||||||
hasWebhookId: !!webhookId,
|
|
||||||
})
|
|
||||||
} catch (error: any) {
|
|
||||||
setSaveStatus('error')
|
|
||||||
setErrorMessage(error.message || 'An error occurred while saving.')
|
|
||||||
logger.error('Error saving trigger configuration', { error })
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
return saveConfig()
|
||||||
|
}, [blockId, effectiveTriggerId, saveConfig])
|
||||||
|
|
||||||
|
const handleSaveSuccess = useCallback(() => {
|
||||||
|
const savedWebhookId = useSubBlockStore.getState().getValue(blockId, 'webhookId')
|
||||||
|
const savedTriggerPath = useSubBlockStore.getState().getValue(blockId, 'triggerPath')
|
||||||
|
const savedTriggerId = useSubBlockStore.getState().getValue(blockId, 'triggerId')
|
||||||
|
const savedTriggerConfig = useSubBlockStore.getState().getValue(blockId, 'triggerConfig')
|
||||||
|
|
||||||
|
collaborativeSetSubblockValue(blockId, 'webhookId', savedWebhookId)
|
||||||
|
collaborativeSetSubblockValue(blockId, 'triggerPath', savedTriggerPath)
|
||||||
|
collaborativeSetSubblockValue(blockId, 'triggerId', savedTriggerId)
|
||||||
|
collaborativeSetSubblockValue(blockId, 'triggerConfig', savedTriggerConfig)
|
||||||
|
}, [blockId, collaborativeSetSubblockValue])
|
||||||
|
|
||||||
|
const {
|
||||||
|
saveStatus,
|
||||||
|
errorMessage,
|
||||||
|
retryCount,
|
||||||
|
maxRetries,
|
||||||
|
triggerSave,
|
||||||
|
onConfigChange,
|
||||||
|
markInitialLoadComplete,
|
||||||
|
} = useAutoSave({
|
||||||
|
disabled: isPreview || disabled || !triggerDef,
|
||||||
|
isExternallySaving: isLoading,
|
||||||
|
validate: validateRequiredFields,
|
||||||
|
onSave: handleSave,
|
||||||
|
onSaveSuccess: handleSaveSuccess,
|
||||||
|
loggerName: 'TriggerSave',
|
||||||
|
})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
onConfigChange(configFingerprint)
|
||||||
|
}, [configFingerprint, onConfigChange])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isLoading && webhookId) {
|
||||||
|
return markInitialLoadComplete(configFingerprint)
|
||||||
|
}
|
||||||
|
if (!webhookId && !isLoading) {
|
||||||
|
return markInitialLoadComplete(configFingerprint)
|
||||||
|
}
|
||||||
|
}, [isLoading, webhookId, configFingerprint, markInitialLoadComplete])
|
||||||
|
|
||||||
const generateTestUrl = async () => {
|
const generateTestUrl = async () => {
|
||||||
if (!webhookId) return
|
if (!webhookId) return
|
||||||
try {
|
try {
|
||||||
setIsGeneratingTestUrl(true)
|
setIsGeneratingTestUrl(true)
|
||||||
|
setTestUrlError(null)
|
||||||
const res = await fetch(`/api/webhooks/${webhookId}/test-url`, {
|
const res = await fetch(`/api/webhooks/${webhookId}/test-url`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
@@ -296,7 +202,7 @@ export function TriggerSave({
|
|||||||
collaborativeSetSubblockValue(blockId, 'testUrlExpiresAt', json.expiresAt)
|
collaborativeSetSubblockValue(blockId, 'testUrlExpiresAt', json.expiresAt)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error('Failed to generate test webhook URL', { error: e })
|
logger.error('Failed to generate test webhook URL', { error: e })
|
||||||
setErrorMessage(
|
setTestUrlError(
|
||||||
e instanceof Error ? e.message : 'Failed to generate test URL. Please try again.'
|
e instanceof Error ? e.message : 'Failed to generate test URL. Please try again.'
|
||||||
)
|
)
|
||||||
} finally {
|
} finally {
|
||||||
@@ -304,114 +210,49 @@ export function TriggerSave({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleDeleteClick = () => {
|
|
||||||
if (isPreview || disabled || !webhookId) return
|
|
||||||
setShowDeleteDialog(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleDeleteConfirm = async () => {
|
|
||||||
setShowDeleteDialog(false)
|
|
||||||
setDeleteStatus('deleting')
|
|
||||||
setErrorMessage(null)
|
|
||||||
|
|
||||||
try {
|
|
||||||
const success = await deleteConfig()
|
|
||||||
|
|
||||||
if (success) {
|
|
||||||
setDeleteStatus('idle')
|
|
||||||
setSaveStatus('idle')
|
|
||||||
setErrorMessage(null)
|
|
||||||
|
|
||||||
useSubBlockStore.getState().setValue(blockId, 'testUrl', null)
|
|
||||||
useSubBlockStore.getState().setValue(blockId, 'testUrlExpiresAt', null)
|
|
||||||
|
|
||||||
collaborativeSetSubblockValue(blockId, 'triggerPath', '')
|
|
||||||
collaborativeSetSubblockValue(blockId, 'webhookId', null)
|
|
||||||
collaborativeSetSubblockValue(blockId, 'triggerConfig', null)
|
|
||||||
collaborativeSetSubblockValue(blockId, 'testUrl', null)
|
|
||||||
collaborativeSetSubblockValue(blockId, 'testUrlExpiresAt', null)
|
|
||||||
|
|
||||||
logger.info('Trigger configuration deleted successfully', {
|
|
||||||
blockId,
|
|
||||||
triggerId: effectiveTriggerId,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
setDeleteStatus('idle')
|
|
||||||
setErrorMessage('Failed to delete trigger configuration.')
|
|
||||||
logger.error('Failed to delete trigger configuration')
|
|
||||||
}
|
|
||||||
} catch (error: any) {
|
|
||||||
setDeleteStatus('idle')
|
|
||||||
setErrorMessage(error.message || 'An error occurred while deleting.')
|
|
||||||
logger.error('Error deleting trigger configuration', { error })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isPreview) {
|
if (isPreview) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
const isProcessing = saveStatus === 'saving' || deleteStatus === 'deleting' || isLoading
|
const isProcessing = saveStatus === 'saving' || isLoading
|
||||||
|
const displayError = errorMessage || testUrlError
|
||||||
|
|
||||||
|
const hasStatusIndicator = isLoading || saveStatus === 'saving' || displayError
|
||||||
|
const hasTestUrlSection =
|
||||||
|
webhookId && hasWebhookUrlDisplay && !isLoading && saveStatus !== 'saving'
|
||||||
|
|
||||||
|
if (!hasStatusIndicator && !hasTestUrlSection) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id={`${blockId}-${subBlockId}`}>
|
<div id={`${blockId}-${subBlockId}`} className='space-y-2 pb-4'>
|
||||||
<div className='flex gap-2'>
|
<SaveStatusIndicator
|
||||||
<Button
|
status={saveStatus}
|
||||||
variant='default'
|
errorMessage={displayError}
|
||||||
onClick={handleSave}
|
savingText='Saving trigger...'
|
||||||
disabled={disabled || isProcessing}
|
loadingText='Loading trigger...'
|
||||||
className={cn(
|
isLoading={isLoading}
|
||||||
'h-[32px] flex-1 rounded-[8px] px-[12px] transition-all duration-200',
|
onRetry={testUrlError ? () => setTestUrlError(null) : triggerSave}
|
||||||
saveStatus === 'saved' && 'bg-green-600 hover:bg-green-700',
|
retryDisabled={isProcessing}
|
||||||
saveStatus === 'error' && 'bg-red-600 hover:bg-red-700'
|
retryCount={retryCount}
|
||||||
)}
|
maxRetries={maxRetries}
|
||||||
>
|
/>
|
||||||
{saveStatus === 'saving' && (
|
|
||||||
<>
|
|
||||||
<div className='mr-2 h-4 w-4 animate-spin rounded-full border-[1.5px] border-current border-t-transparent' />
|
|
||||||
Saving...
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{saveStatus === 'saved' && 'Saved'}
|
|
||||||
{saveStatus === 'error' && 'Error'}
|
|
||||||
{saveStatus === 'idle' && (webhookId ? 'Update Configuration' : 'Save Configuration')}
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
{webhookId && (
|
{/* Test webhook URL section */}
|
||||||
<Button
|
{webhookId && hasWebhookUrlDisplay && !isLoading && saveStatus !== 'saving' && (
|
||||||
variant='default'
|
<div className='space-y-1'>
|
||||||
onClick={handleDeleteClick}
|
|
||||||
disabled={disabled || isProcessing}
|
|
||||||
className='h-[32px] rounded-[8px] px-[12px]'
|
|
||||||
>
|
|
||||||
{deleteStatus === 'deleting' ? (
|
|
||||||
<div className='h-4 w-4 animate-spin rounded-full border-[1.5px] border-current border-t-transparent' />
|
|
||||||
) : (
|
|
||||||
<Trash className='h-[14px] w-[14px]' />
|
|
||||||
)}
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{errorMessage && (
|
|
||||||
<Alert variant='destructive' className='mt-2'>
|
|
||||||
<AlertDescription>{errorMessage}</AlertDescription>
|
|
||||||
</Alert>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{webhookId && hasWebhookUrlDisplay && (
|
|
||||||
<div className='mt-2 space-y-1'>
|
|
||||||
<div className='flex items-center justify-between'>
|
<div className='flex items-center justify-between'>
|
||||||
<span className='font-medium text-sm'>Test Webhook URL</span>
|
<span className='font-medium text-sm'>Test Webhook URL</span>
|
||||||
<Button
|
<Button
|
||||||
variant='outline'
|
variant='ghost'
|
||||||
onClick={generateTestUrl}
|
onClick={generateTestUrl}
|
||||||
disabled={isGeneratingTestUrl || isProcessing}
|
disabled={isGeneratingTestUrl || isProcessing}
|
||||||
className='h-[32px] rounded-[8px] px-[12px]'
|
className='h-6 px-2 py-1 text-[11px]'
|
||||||
>
|
>
|
||||||
{isGeneratingTestUrl ? (
|
{isGeneratingTestUrl ? (
|
||||||
<>
|
<>
|
||||||
<div className='mr-2 h-3 w-3 animate-spin rounded-full border-[1.5px] border-current border-t-transparent' />
|
<div className='mr-1.5 h-2.5 w-2.5 animate-spin rounded-full border-[1.5px] border-current border-t-transparent' />
|
||||||
Generating…
|
Generating…
|
||||||
</>
|
</>
|
||||||
) : testUrl ? (
|
) : testUrl ? (
|
||||||
@@ -450,31 +291,6 @@ export function TriggerSave({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Modal open={showDeleteDialog} onOpenChange={setShowDeleteDialog}>
|
|
||||||
<ModalContent size='sm'>
|
|
||||||
<ModalHeader>Delete Trigger</ModalHeader>
|
|
||||||
<ModalBody>
|
|
||||||
<p className='text-[12px] text-[var(--text-tertiary)]'>
|
|
||||||
Are you sure you want to delete this trigger configuration? This will remove the
|
|
||||||
webhook and stop all incoming triggers.{' '}
|
|
||||||
<span className='text-[var(--text-error)]'>This action cannot be undone.</span>
|
|
||||||
</p>
|
|
||||||
</ModalBody>
|
|
||||||
<ModalFooter>
|
|
||||||
<Button variant='active' onClick={() => setShowDeleteDialog(false)}>
|
|
||||||
Cancel
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
variant='primary'
|
|
||||||
onClick={handleDeleteConfirm}
|
|
||||||
className='!bg-[var(--text-error)] !text-white hover:!bg-[var(--text-error)]/90'
|
|
||||||
>
|
|
||||||
Delete
|
|
||||||
</Button>
|
|
||||||
</ModalFooter>
|
|
||||||
</ModalContent>
|
|
||||||
</Modal>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -293,7 +293,6 @@ function SubBlockComponent({
|
|||||||
setIsValidJson(isValid)
|
setIsValidJson(isValid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if wand is enabled for this sub-block
|
|
||||||
const isWandEnabled = config.wandConfig?.enabled ?? false
|
const isWandEnabled = config.wandConfig?.enabled ?? false
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -816,6 +815,13 @@ function SubBlockComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Render without wrapper for components that may return null
|
||||||
|
const noWrapper =
|
||||||
|
config.noWrapper || config.type === 'trigger-save' || config.type === 'schedule-save'
|
||||||
|
if (noWrapper) {
|
||||||
|
return renderInput()
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div onMouseDown={handleMouseDown} className='flex flex-col gap-[10px]'>
|
<div onMouseDown={handleMouseDown} className='flex flex-col gap-[10px]'>
|
||||||
{renderLabel(
|
{renderLabel(
|
||||||
|
|||||||
@@ -336,6 +336,26 @@ export function Editor() {
|
|||||||
subBlockState
|
subBlockState
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const isNoWrapper =
|
||||||
|
subBlock.noWrapper ||
|
||||||
|
subBlock.type === 'trigger-save' ||
|
||||||
|
subBlock.type === 'schedule-save'
|
||||||
|
|
||||||
|
if (isNoWrapper) {
|
||||||
|
return (
|
||||||
|
<SubBlock
|
||||||
|
key={stableKey}
|
||||||
|
blockId={currentBlockId}
|
||||||
|
config={subBlock}
|
||||||
|
isPreview={false}
|
||||||
|
subBlockValues={subBlockState}
|
||||||
|
disabled={!userPermissions.canEdit}
|
||||||
|
fieldDiffStatus={undefined}
|
||||||
|
allowExpandInPreview={false}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={stableKey}>
|
<div key={stableKey}>
|
||||||
<SubBlock
|
<SubBlock
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { useCallback, useEffect, useState } from 'react'
|
import { useCallback, useEffect, useState } from 'react'
|
||||||
import { createLogger } from '@/lib/logs/console/logger'
|
import { createLogger } from '@/lib/logs/console/logger'
|
||||||
import { parseCronToHumanReadable } from '@/lib/workflows/schedules/utils'
|
import { parseCronToHumanReadable } from '@/lib/workflows/schedules/utils'
|
||||||
|
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
|
||||||
|
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
|
||||||
import type { ScheduleInfo } from '../types'
|
import type { ScheduleInfo } from '../types'
|
||||||
|
|
||||||
const logger = createLogger('useScheduleInfo')
|
const logger = createLogger('useScheduleInfo')
|
||||||
@@ -32,9 +34,20 @@ export function useScheduleInfo(
|
|||||||
blockType: string,
|
blockType: string,
|
||||||
workflowId: string
|
workflowId: string
|
||||||
): UseScheduleInfoReturn {
|
): UseScheduleInfoReturn {
|
||||||
|
const activeWorkflowId = useWorkflowRegistry((state) => state.activeWorkflowId)
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
const [scheduleInfo, setScheduleInfo] = useState<ScheduleInfo | null>(null)
|
const [scheduleInfo, setScheduleInfo] = useState<ScheduleInfo | null>(null)
|
||||||
|
|
||||||
|
const scheduleIdFromStore = useSubBlockStore(
|
||||||
|
useCallback(
|
||||||
|
(state) => {
|
||||||
|
if (!activeWorkflowId) return null
|
||||||
|
return state.workflowValues[activeWorkflowId]?.[blockId]?.scheduleId as string | null
|
||||||
|
},
|
||||||
|
[activeWorkflowId, blockId]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
const fetchScheduleInfo = useCallback(
|
const fetchScheduleInfo = useCallback(
|
||||||
async (wfId: string) => {
|
async (wfId: string) => {
|
||||||
if (!wfId) return
|
if (!wfId) return
|
||||||
@@ -143,22 +156,10 @@ export function useScheduleInfo(
|
|||||||
setIsLoading(false)
|
setIsLoading(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleScheduleUpdate = (event: CustomEvent) => {
|
|
||||||
if (event.detail?.workflowId === workflowId && event.detail?.blockId === blockId) {
|
|
||||||
logger.debug('Schedule update event received, refetching schedule info')
|
|
||||||
if (blockType === 'schedule') {
|
|
||||||
fetchScheduleInfo(workflowId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener('schedule-updated', handleScheduleUpdate as EventListener)
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
setIsLoading(false)
|
setIsLoading(false)
|
||||||
window.removeEventListener('schedule-updated', handleScheduleUpdate as EventListener)
|
|
||||||
}
|
}
|
||||||
}, [blockType, workflowId, blockId, fetchScheduleInfo])
|
}, [blockType, workflowId, blockId, scheduleIdFromStore, fetchScheduleInfo])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
scheduleInfo,
|
scheduleInfo,
|
||||||
|
|||||||
@@ -44,7 +44,11 @@ export function useWebhookInfo(blockId: string, workflowId: string): UseWebhookI
|
|||||||
useCallback(
|
useCallback(
|
||||||
(state) => {
|
(state) => {
|
||||||
const blockValues = state.workflowValues[activeWorkflowId || '']?.[blockId]
|
const blockValues = state.workflowValues[activeWorkflowId || '']?.[blockId]
|
||||||
return !!(blockValues?.webhookProvider && blockValues?.webhookPath)
|
// Check for webhookId (set by trigger auto-save) or webhookProvider+webhookPath (legacy)
|
||||||
|
return !!(
|
||||||
|
blockValues?.webhookId ||
|
||||||
|
(blockValues?.webhookProvider && blockValues?.webhookPath)
|
||||||
|
)
|
||||||
},
|
},
|
||||||
[activeWorkflowId, blockId]
|
[activeWorkflowId, blockId]
|
||||||
)
|
)
|
||||||
@@ -72,6 +76,16 @@ export function useWebhookInfo(blockId: string, workflowId: string): UseWebhookI
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const webhookIdFromStore = useSubBlockStore(
|
||||||
|
useCallback(
|
||||||
|
(state) => {
|
||||||
|
if (!activeWorkflowId) return null
|
||||||
|
return state.workflowValues[activeWorkflowId]?.[blockId]?.webhookId as string | null
|
||||||
|
},
|
||||||
|
[activeWorkflowId, blockId]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
const fetchWebhookStatus = useCallback(async () => {
|
const fetchWebhookStatus = useCallback(async () => {
|
||||||
if (!workflowId || !blockId || !isWebhookConfigured) {
|
if (!workflowId || !blockId || !isWebhookConfigured) {
|
||||||
setWebhookStatus({ isDisabled: false, webhookId: undefined })
|
setWebhookStatus({ isDisabled: false, webhookId: undefined })
|
||||||
@@ -114,7 +128,7 @@ export function useWebhookInfo(blockId: string, workflowId: string): UseWebhookI
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchWebhookStatus()
|
fetchWebhookStatus()
|
||||||
}, [fetchWebhookStatus])
|
}, [fetchWebhookStatus, webhookIdFromStore])
|
||||||
|
|
||||||
const reactivateWebhook = useCallback(
|
const reactivateWebhook = useCallback(
|
||||||
async (webhookId: string) => {
|
async (webhookId: string) => {
|
||||||
|
|||||||
@@ -550,9 +550,6 @@ export const WorkflowBlock = memo(function WorkflowBlock({
|
|||||||
|
|
||||||
const currentStoreBlock = currentWorkflow.getBlockById(id)
|
const currentStoreBlock = currentWorkflow.getBlockById(id)
|
||||||
|
|
||||||
const isStarterBlock = type === 'starter'
|
|
||||||
const isWebhookTriggerBlock = type === 'webhook' || type === 'generic_webhook'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subscribe to this block's subblock values to track changes for conditional rendering
|
* Subscribe to this block's subblock values to track changes for conditional rendering
|
||||||
* of subblocks based on their conditions.
|
* of subblocks based on their conditions.
|
||||||
@@ -808,7 +805,7 @@ export const WorkflowBlock = memo(function WorkflowBlock({
|
|||||||
updateNodeInternals(id)
|
updateNodeInternals(id)
|
||||||
}, [horizontalHandles, id, updateNodeInternals])
|
}, [horizontalHandles, id, updateNodeInternals])
|
||||||
|
|
||||||
const showWebhookIndicator = (isStarterBlock || isWebhookTriggerBlock) && isWebhookConfigured
|
const showWebhookIndicator = displayTriggerMode && isWebhookConfigured
|
||||||
const shouldShowScheduleBadge =
|
const shouldShowScheduleBadge =
|
||||||
type === 'schedule' && !isLoadingScheduleInfo && scheduleInfo !== null
|
type === 'schedule' && !isLoadingScheduleInfo && scheduleInfo !== null
|
||||||
const userPermissions = useUserPermissionsContext()
|
const userPermissions = useUserPermissionsContext()
|
||||||
@@ -909,28 +906,30 @@ export const WorkflowBlock = memo(function WorkflowBlock({
|
|||||||
)}
|
)}
|
||||||
{!isEnabled && <Badge>disabled</Badge>}
|
{!isEnabled && <Badge>disabled</Badge>}
|
||||||
|
|
||||||
{type === 'schedule' && shouldShowScheduleBadge && scheduleInfo?.isDisabled && (
|
{type === 'schedule' && shouldShowScheduleBadge && (
|
||||||
<Tooltip.Root>
|
<Tooltip.Root>
|
||||||
<Tooltip.Trigger asChild>
|
<Tooltip.Trigger asChild>
|
||||||
<Badge
|
<Badge
|
||||||
variant='outline'
|
variant='outline'
|
||||||
className='cursor-pointer'
|
className={scheduleInfo?.isDisabled ? 'cursor-pointer' : ''}
|
||||||
style={{
|
style={{
|
||||||
borderColor: 'var(--warning)',
|
borderColor: scheduleInfo?.isDisabled ? 'var(--warning)' : 'var(--success)',
|
||||||
color: 'var(--warning)',
|
color: scheduleInfo?.isDisabled ? 'var(--warning)' : 'var(--success)',
|
||||||
}}
|
}}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
if (scheduleInfo?.id) {
|
if (scheduleInfo?.isDisabled && scheduleInfo?.id) {
|
||||||
reactivateSchedule(scheduleInfo.id)
|
reactivateSchedule(scheduleInfo.id)
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
disabled
|
{scheduleInfo?.isDisabled ? 'disabled' : 'active'}
|
||||||
</Badge>
|
</Badge>
|
||||||
</Tooltip.Trigger>
|
</Tooltip.Trigger>
|
||||||
<Tooltip.Content>
|
<Tooltip.Content>
|
||||||
<span className='text-sm'>Click to reactivate</span>
|
{scheduleInfo?.isDisabled
|
||||||
|
? 'Click to reactivate'
|
||||||
|
: scheduleInfo?.scheduleTiming || 'Schedule is active'}
|
||||||
</Tooltip.Content>
|
</Tooltip.Content>
|
||||||
</Tooltip.Root>
|
</Tooltip.Root>
|
||||||
)}
|
)}
|
||||||
@@ -940,47 +939,27 @@ export const WorkflowBlock = memo(function WorkflowBlock({
|
|||||||
<Tooltip.Trigger asChild>
|
<Tooltip.Trigger asChild>
|
||||||
<Badge
|
<Badge
|
||||||
variant='outline'
|
variant='outline'
|
||||||
className='bg-[var(--brand-tertiary)] text-[var(--brand-tertiary)]'
|
className={isWebhookDisabled && webhookId ? 'cursor-pointer' : ''}
|
||||||
>
|
style={{
|
||||||
<div className='relative flex items-center justify-center'>
|
borderColor: isWebhookDisabled ? 'var(--warning)' : 'var(--success)',
|
||||||
<div className='197, 94, 0.2)] absolute h-3 w-3 rounded-full bg-[rgba(34,' />
|
color: isWebhookDisabled ? 'var(--warning)' : 'var(--success)',
|
||||||
<div className='relative h-2 w-2 rounded-full bg-[var(--brand-tertiary)]' />
|
}}
|
||||||
</div>
|
|
||||||
Webhook
|
|
||||||
</Badge>
|
|
||||||
</Tooltip.Trigger>
|
|
||||||
<Tooltip.Content side='top' className='max-w-[300px] p-4'>
|
|
||||||
{webhookProvider && webhookPath ? (
|
|
||||||
<>
|
|
||||||
<p className='text-sm'>{getProviderName(webhookProvider)} Webhook</p>
|
|
||||||
<p className='mt-1 text-muted-foreground text-xs'>Path: {webhookPath}</p>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<p className='text-muted-foreground text-sm'>
|
|
||||||
This workflow is triggered by a webhook.
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</Tooltip.Content>
|
|
||||||
</Tooltip.Root>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{isWebhookConfigured && isWebhookDisabled && webhookId && (
|
|
||||||
<Tooltip.Root>
|
|
||||||
<Tooltip.Trigger asChild>
|
|
||||||
<Badge
|
|
||||||
variant='outline'
|
|
||||||
className='cursor-pointer'
|
|
||||||
style={{ borderColor: 'var(--warning)', color: 'var(--warning)' }}
|
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
reactivateWebhook(webhookId)
|
if (isWebhookDisabled && webhookId) {
|
||||||
|
reactivateWebhook(webhookId)
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
disabled
|
{isWebhookDisabled ? 'disabled' : 'active'}
|
||||||
</Badge>
|
</Badge>
|
||||||
</Tooltip.Trigger>
|
</Tooltip.Trigger>
|
||||||
<Tooltip.Content>
|
<Tooltip.Content>
|
||||||
<span className='text-sm'>Click to reactivate</span>
|
{isWebhookDisabled
|
||||||
|
? 'Click to reactivate'
|
||||||
|
: webhookProvider
|
||||||
|
? `${getProviderName(webhookProvider)} Webhook`
|
||||||
|
: 'Trigger is active'}
|
||||||
</Tooltip.Content>
|
</Tooltip.Content>
|
||||||
</Tooltip.Root>
|
</Tooltip.Root>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -215,6 +215,7 @@ export interface SubBlockConfig {
|
|||||||
connectionDroppable?: boolean
|
connectionDroppable?: boolean
|
||||||
hidden?: boolean
|
hidden?: boolean
|
||||||
hideFromPreview?: boolean // Hide this subblock from the workflow block preview
|
hideFromPreview?: boolean // Hide this subblock from the workflow block preview
|
||||||
|
noWrapper?: boolean // Render the input directly without wrapper div
|
||||||
requiresFeature?: string // Environment variable name that must be truthy for this subblock to be visible
|
requiresFeature?: string // Environment variable name that must be truthy for this subblock to be visible
|
||||||
description?: string
|
description?: string
|
||||||
value?: (params: Record<string, any>) => string
|
value?: (params: Record<string, any>) => string
|
||||||
|
|||||||
236
apps/sim/hooks/use-auto-save.ts
Normal file
236
apps/sim/hooks/use-auto-save.ts
Normal file
@@ -0,0 +1,236 @@
|
|||||||
|
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||||
|
import { createLogger } from '@/lib/logs/console/logger'
|
||||||
|
|
||||||
|
const logger = createLogger('useAutoSave')
|
||||||
|
|
||||||
|
/** Auto-save debounce delay in milliseconds */
|
||||||
|
const AUTO_SAVE_DEBOUNCE_MS = 1500
|
||||||
|
|
||||||
|
/** Delay before enabling auto-save after initial load */
|
||||||
|
const INITIAL_LOAD_DELAY_MS = 500
|
||||||
|
|
||||||
|
/** Default maximum retry attempts */
|
||||||
|
const DEFAULT_MAX_RETRIES = 3
|
||||||
|
|
||||||
|
/** Delay before resetting save status to idle after successful save */
|
||||||
|
const SAVED_STATUS_DISPLAY_MS = 2000
|
||||||
|
|
||||||
|
export type SaveStatus = 'idle' | 'saving' | 'saved' | 'error'
|
||||||
|
|
||||||
|
export interface SaveConfigResult {
|
||||||
|
success: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UseAutoSaveOptions<T extends SaveConfigResult = SaveConfigResult> {
|
||||||
|
/** Whether auto-save is disabled (e.g., in preview mode) */
|
||||||
|
disabled?: boolean
|
||||||
|
/** Whether a save operation is already in progress externally */
|
||||||
|
isExternallySaving?: boolean
|
||||||
|
/** Maximum retry attempts (default: 3) */
|
||||||
|
maxRetries?: number
|
||||||
|
/** Validate config before saving, return true if valid */
|
||||||
|
validate: () => boolean
|
||||||
|
/** Perform the save operation */
|
||||||
|
onSave: () => Promise<T>
|
||||||
|
/** Optional callback after successful save */
|
||||||
|
onSaveSuccess?: (result: T) => void
|
||||||
|
/** Optional callback after failed save */
|
||||||
|
onSaveError?: (error: Error) => void
|
||||||
|
/** Logger name for debugging */
|
||||||
|
loggerName?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UseAutoSaveReturn {
|
||||||
|
/** Current save status */
|
||||||
|
saveStatus: SaveStatus
|
||||||
|
/** Error message if save failed */
|
||||||
|
errorMessage: string | null
|
||||||
|
/** Current retry count */
|
||||||
|
retryCount: number
|
||||||
|
/** Maximum retries allowed */
|
||||||
|
maxRetries: number
|
||||||
|
/** Whether max retries has been reached */
|
||||||
|
maxRetriesReached: boolean
|
||||||
|
/** Trigger an immediate save attempt (for retry button) */
|
||||||
|
triggerSave: () => Promise<void>
|
||||||
|
/** Call this when config changes to trigger debounced save */
|
||||||
|
onConfigChange: (configFingerprint: string) => void
|
||||||
|
/** Call this when initial load completes to enable auto-save */
|
||||||
|
markInitialLoadComplete: (currentFingerprint: string) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shared hook for auto-saving configuration with debouncing, retry limits, and status management.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```tsx
|
||||||
|
* const { saveStatus, errorMessage, triggerSave, onConfigChange, markInitialLoadComplete } = useAutoSave({
|
||||||
|
* disabled: isPreview,
|
||||||
|
* isExternallySaving: isSaving,
|
||||||
|
* validate: () => validateRequiredFields(),
|
||||||
|
* onSave: async () => saveConfig(),
|
||||||
|
* onSaveSuccess: (result) => { ... },
|
||||||
|
* })
|
||||||
|
*
|
||||||
|
* // When config fingerprint changes
|
||||||
|
* useEffect(() => {
|
||||||
|
* onConfigChange(configFingerprint)
|
||||||
|
* }, [configFingerprint, onConfigChange])
|
||||||
|
*
|
||||||
|
* // When initial data loads
|
||||||
|
* useEffect(() => {
|
||||||
|
* if (!isLoading && dataId) {
|
||||||
|
* markInitialLoadComplete(configFingerprint)
|
||||||
|
* }
|
||||||
|
* }, [isLoading, dataId, configFingerprint, markInitialLoadComplete])
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export function useAutoSave<T extends SaveConfigResult = SaveConfigResult>({
|
||||||
|
disabled = false,
|
||||||
|
isExternallySaving = false,
|
||||||
|
maxRetries = DEFAULT_MAX_RETRIES,
|
||||||
|
validate,
|
||||||
|
onSave,
|
||||||
|
onSaveSuccess,
|
||||||
|
onSaveError,
|
||||||
|
loggerName,
|
||||||
|
}: UseAutoSaveOptions<T>): UseAutoSaveReturn {
|
||||||
|
const [saveStatus, setSaveStatus] = useState<SaveStatus>('idle')
|
||||||
|
const [errorMessage, setErrorMessage] = useState<string | null>(null)
|
||||||
|
const [retryCount, setRetryCount] = useState(0)
|
||||||
|
|
||||||
|
const autoSaveTimeoutRef = useRef<NodeJS.Timeout | null>(null)
|
||||||
|
const lastSavedConfigRef = useRef<string | null>(null)
|
||||||
|
const isInitialLoadRef = useRef(true)
|
||||||
|
const currentFingerprintRef = useRef<string | null>(null)
|
||||||
|
|
||||||
|
// Clear any pending timeout on unmount
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
if (autoSaveTimeoutRef.current) {
|
||||||
|
clearTimeout(autoSaveTimeoutRef.current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const performSave = useCallback(async () => {
|
||||||
|
if (disabled || isExternallySaving) return
|
||||||
|
|
||||||
|
// Final validation check before saving
|
||||||
|
if (!validate()) {
|
||||||
|
setSaveStatus('idle')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setSaveStatus('saving')
|
||||||
|
setErrorMessage(null)
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await onSave()
|
||||||
|
|
||||||
|
if (!result.success) {
|
||||||
|
throw new Error('Save operation returned unsuccessful result')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update last saved config to current
|
||||||
|
lastSavedConfigRef.current = currentFingerprintRef.current
|
||||||
|
setSaveStatus('saved')
|
||||||
|
setErrorMessage(null)
|
||||||
|
setRetryCount(0) // Reset retry count on success
|
||||||
|
|
||||||
|
if (onSaveSuccess) {
|
||||||
|
onSaveSuccess(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset to idle after display duration
|
||||||
|
setTimeout(() => {
|
||||||
|
setSaveStatus('idle')
|
||||||
|
}, SAVED_STATUS_DISPLAY_MS)
|
||||||
|
|
||||||
|
if (loggerName) {
|
||||||
|
logger.info(`${loggerName}: Auto-save completed successfully`)
|
||||||
|
}
|
||||||
|
} catch (error: unknown) {
|
||||||
|
setSaveStatus('error')
|
||||||
|
const message = error instanceof Error ? error.message : 'An error occurred while saving.'
|
||||||
|
setErrorMessage(message)
|
||||||
|
setRetryCount((prev) => prev + 1)
|
||||||
|
|
||||||
|
if (onSaveError && error instanceof Error) {
|
||||||
|
onSaveError(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loggerName) {
|
||||||
|
logger.error(`${loggerName}: Auto-save failed`, { error })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [disabled, isExternallySaving, validate, onSave, onSaveSuccess, onSaveError, loggerName])
|
||||||
|
|
||||||
|
const onConfigChange = useCallback(
|
||||||
|
(configFingerprint: string) => {
|
||||||
|
currentFingerprintRef.current = configFingerprint
|
||||||
|
|
||||||
|
if (disabled) return
|
||||||
|
|
||||||
|
// Clear any existing timeout
|
||||||
|
if (autoSaveTimeoutRef.current) {
|
||||||
|
clearTimeout(autoSaveTimeoutRef.current)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip if initial load hasn't completed
|
||||||
|
if (isInitialLoadRef.current) return
|
||||||
|
|
||||||
|
// Skip if already saving
|
||||||
|
if (saveStatus === 'saving' || isExternallySaving) return
|
||||||
|
|
||||||
|
// Clear error if validation now passes
|
||||||
|
if (saveStatus === 'error' && validate()) {
|
||||||
|
setErrorMessage(null)
|
||||||
|
setSaveStatus('idle')
|
||||||
|
setRetryCount(0) // Reset retry count when config changes
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip if config hasn't changed
|
||||||
|
if (configFingerprint === lastSavedConfigRef.current) return
|
||||||
|
|
||||||
|
// Skip if validation fails
|
||||||
|
if (!validate()) return
|
||||||
|
|
||||||
|
// Schedule debounced save
|
||||||
|
autoSaveTimeoutRef.current = setTimeout(() => {
|
||||||
|
if (loggerName) {
|
||||||
|
logger.debug(`${loggerName}: Triggering debounced auto-save`)
|
||||||
|
}
|
||||||
|
performSave()
|
||||||
|
}, AUTO_SAVE_DEBOUNCE_MS)
|
||||||
|
},
|
||||||
|
[disabled, saveStatus, isExternallySaving, validate, performSave, loggerName]
|
||||||
|
)
|
||||||
|
|
||||||
|
const markInitialLoadComplete = useCallback((currentFingerprint: string) => {
|
||||||
|
// Delay before enabling auto-save to prevent immediate trigger
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
isInitialLoadRef.current = false
|
||||||
|
lastSavedConfigRef.current = currentFingerprint
|
||||||
|
currentFingerprintRef.current = currentFingerprint
|
||||||
|
}, INITIAL_LOAD_DELAY_MS)
|
||||||
|
|
||||||
|
return () => clearTimeout(timer)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const triggerSave = useCallback(async () => {
|
||||||
|
// Allow retry even if max retries reached (manual trigger)
|
||||||
|
await performSave()
|
||||||
|
}, [performSave])
|
||||||
|
|
||||||
|
return {
|
||||||
|
saveStatus,
|
||||||
|
errorMessage,
|
||||||
|
retryCount,
|
||||||
|
maxRetries,
|
||||||
|
maxRetriesReached: retryCount >= maxRetries,
|
||||||
|
triggerSave,
|
||||||
|
onConfigChange,
|
||||||
|
markInitialLoadComplete,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,15 +23,10 @@ interface ScheduleManagementState {
|
|||||||
isLoading: boolean
|
isLoading: boolean
|
||||||
isSaving: boolean
|
isSaving: boolean
|
||||||
saveConfig: () => Promise<SaveConfigResult>
|
saveConfig: () => Promise<SaveConfigResult>
|
||||||
deleteConfig: () => Promise<boolean>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook to manage schedule lifecycle for schedule blocks
|
* Hook to manage schedule lifecycle for schedule blocks
|
||||||
* Handles:
|
|
||||||
* - Loading existing schedules from the API
|
|
||||||
* - Saving schedule configurations
|
|
||||||
* - Deleting schedule configurations
|
|
||||||
*/
|
*/
|
||||||
export function useScheduleManagement({
|
export function useScheduleManagement({
|
||||||
blockId,
|
blockId,
|
||||||
@@ -45,8 +40,6 @@ export function useScheduleManagement({
|
|||||||
)
|
)
|
||||||
|
|
||||||
const isLoading = useSubBlockStore((state) => state.loadingSchedules.has(blockId))
|
const isLoading = useSubBlockStore((state) => state.loadingSchedules.has(blockId))
|
||||||
const isChecked = useSubBlockStore((state) => state.checkedSchedules.has(blockId))
|
|
||||||
|
|
||||||
const [isSaving, setIsSaving] = useState(false)
|
const [isSaving, setIsSaving] = useState(false)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -183,49 +176,10 @@ export function useScheduleManagement({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const deleteConfig = async (): Promise<boolean> => {
|
|
||||||
if (isPreview || !scheduleId) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
setIsSaving(true)
|
|
||||||
|
|
||||||
const response = await fetch(`/api/schedules/${scheduleId}`, {
|
|
||||||
method: 'DELETE',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
body: JSON.stringify({
|
|
||||||
workspaceId: params.workspaceId as string,
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
logger.error('Failed to delete schedule')
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
useSubBlockStore.getState().setValue(blockId, 'scheduleId', null)
|
|
||||||
useSubBlockStore.setState((state) => {
|
|
||||||
const newSet = new Set(state.checkedSchedules)
|
|
||||||
newSet.delete(blockId)
|
|
||||||
return { checkedSchedules: newSet }
|
|
||||||
})
|
|
||||||
|
|
||||||
logger.info('Schedule deleted successfully')
|
|
||||||
return true
|
|
||||||
} catch (error) {
|
|
||||||
logger.error('Error deleting schedule:', error)
|
|
||||||
return false
|
|
||||||
} finally {
|
|
||||||
setIsSaving(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
scheduleId,
|
scheduleId,
|
||||||
isLoading,
|
isLoading,
|
||||||
isSaving,
|
isSaving,
|
||||||
saveConfig,
|
saveConfig,
|
||||||
deleteConfig,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { useSubBlockStore } from '@/stores/workflows/subblock/store'
|
|||||||
import { getTrigger, isTriggerValid } from '@/triggers'
|
import { getTrigger, isTriggerValid } from '@/triggers'
|
||||||
import { SYSTEM_SUBBLOCK_IDS } from '@/triggers/constants'
|
import { SYSTEM_SUBBLOCK_IDS } from '@/triggers/constants'
|
||||||
|
|
||||||
const logger = createLogger('useTriggerConfigAggregation')
|
const logger = createLogger('getTriggerConfigAggregation')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maps old trigger config field names to new subblock IDs for backward compatibility.
|
* Maps old trigger config field names to new subblock IDs for backward compatibility.
|
||||||
@@ -34,7 +34,7 @@ function mapOldFieldNameToNewSubBlockId(oldFieldName: string): string {
|
|||||||
* @returns The aggregated config object, or null if no valid config
|
* @returns The aggregated config object, or null if no valid config
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function useTriggerConfigAggregation(
|
export function getTriggerConfigAggregation(
|
||||||
blockId: string,
|
blockId: string,
|
||||||
triggerId: string | undefined
|
triggerId: string | undefined
|
||||||
): Record<string, any> | null {
|
): Record<string, any> | null {
|
||||||
|
|||||||
@@ -16,14 +16,18 @@ interface UseWebhookManagementProps {
|
|||||||
isPreview?: boolean
|
isPreview?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface SaveConfigResult {
|
||||||
|
success: boolean
|
||||||
|
webhookId?: string
|
||||||
|
}
|
||||||
|
|
||||||
interface WebhookManagementState {
|
interface WebhookManagementState {
|
||||||
webhookUrl: string
|
webhookUrl: string
|
||||||
webhookPath: string
|
webhookPath: string
|
||||||
webhookId: string | null
|
webhookId: string | null
|
||||||
isLoading: boolean
|
isLoading: boolean
|
||||||
isSaving: boolean
|
isSaving: boolean
|
||||||
saveConfig: () => Promise<boolean>
|
saveConfig: () => Promise<SaveConfigResult>
|
||||||
deleteConfig: () => Promise<boolean>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -81,10 +85,6 @@ function resolveEffectiveTriggerId(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook to manage webhook lifecycle for trigger blocks
|
* Hook to manage webhook lifecycle for trigger blocks
|
||||||
* Handles:
|
|
||||||
* - Pre-generating webhook URLs based on blockId (without creating webhook)
|
|
||||||
* - Loading existing webhooks from the API
|
|
||||||
* - Saving and deleting webhook configurations
|
|
||||||
*/
|
*/
|
||||||
export function useWebhookManagement({
|
export function useWebhookManagement({
|
||||||
blockId,
|
blockId,
|
||||||
@@ -103,7 +103,6 @@ export function useWebhookManagement({
|
|||||||
useCallback((state) => state.getValue(blockId, 'triggerPath') as string | null, [blockId])
|
useCallback((state) => state.getValue(blockId, 'triggerPath') as string | null, [blockId])
|
||||||
)
|
)
|
||||||
const isLoading = useSubBlockStore((state) => state.loadingWebhooks.has(blockId))
|
const isLoading = useSubBlockStore((state) => state.loadingWebhooks.has(blockId))
|
||||||
const isChecked = useSubBlockStore((state) => state.checkedWebhooks.has(blockId))
|
|
||||||
|
|
||||||
const webhookUrl = useMemo(() => {
|
const webhookUrl = useMemo(() => {
|
||||||
if (!webhookPath) {
|
if (!webhookPath) {
|
||||||
@@ -211,9 +210,9 @@ export function useWebhookManagement({
|
|||||||
const createWebhook = async (
|
const createWebhook = async (
|
||||||
effectiveTriggerId: string | undefined,
|
effectiveTriggerId: string | undefined,
|
||||||
selectedCredentialId: string | null
|
selectedCredentialId: string | null
|
||||||
): Promise<boolean> => {
|
): Promise<SaveConfigResult> => {
|
||||||
if (!triggerDef || !effectiveTriggerId) {
|
if (!triggerDef || !effectiveTriggerId) {
|
||||||
return false
|
return { success: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
const triggerConfig = useSubBlockStore.getState().getValue(blockId, 'triggerConfig')
|
const triggerConfig = useSubBlockStore.getState().getValue(blockId, 'triggerConfig')
|
||||||
@@ -266,14 +265,14 @@ export function useWebhookManagement({
|
|||||||
blockId,
|
blockId,
|
||||||
})
|
})
|
||||||
|
|
||||||
return true
|
return { success: true, webhookId: savedWebhookId }
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateWebhook = async (
|
const updateWebhook = async (
|
||||||
webhookIdToUpdate: string,
|
webhookIdToUpdate: string,
|
||||||
effectiveTriggerId: string | undefined,
|
effectiveTriggerId: string | undefined,
|
||||||
selectedCredentialId: string | null
|
selectedCredentialId: string | null
|
||||||
): Promise<boolean> => {
|
): Promise<SaveConfigResult> => {
|
||||||
const triggerConfig = useSubBlockStore.getState().getValue(blockId, 'triggerConfig')
|
const triggerConfig = useSubBlockStore.getState().getValue(blockId, 'triggerConfig')
|
||||||
|
|
||||||
const response = await fetch(`/api/webhooks/${webhookIdToUpdate}`, {
|
const response = await fetch(`/api/webhooks/${webhookIdToUpdate}`, {
|
||||||
@@ -310,12 +309,12 @@ export function useWebhookManagement({
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger.info('Trigger config saved successfully', { blockId, webhookId: webhookIdToUpdate })
|
logger.info('Trigger config saved successfully', { blockId, webhookId: webhookIdToUpdate })
|
||||||
return true
|
return { success: true, webhookId: webhookIdToUpdate }
|
||||||
}
|
}
|
||||||
|
|
||||||
const saveConfig = async (): Promise<boolean> => {
|
const saveConfig = async (): Promise<SaveConfigResult> => {
|
||||||
if (isPreview || !triggerDef) {
|
if (isPreview || !triggerDef) {
|
||||||
return false
|
return { success: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
const effectiveTriggerId = resolveEffectiveTriggerId(blockId, triggerId)
|
const effectiveTriggerId = resolveEffectiveTriggerId(blockId, triggerId)
|
||||||
@@ -339,41 +338,6 @@ export function useWebhookManagement({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const deleteConfig = async (): Promise<boolean> => {
|
|
||||||
if (isPreview || !webhookId) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
setIsSaving(true)
|
|
||||||
|
|
||||||
const response = await fetch(`/api/webhooks/${webhookId}`, {
|
|
||||||
method: 'DELETE',
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
logger.error('Failed to delete webhook')
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
useSubBlockStore.getState().setValue(blockId, 'triggerPath', '')
|
|
||||||
useSubBlockStore.getState().setValue(blockId, 'webhookId', null)
|
|
||||||
useSubBlockStore.setState((state) => {
|
|
||||||
const newSet = new Set(state.checkedWebhooks)
|
|
||||||
newSet.delete(blockId)
|
|
||||||
return { checkedWebhooks: newSet }
|
|
||||||
})
|
|
||||||
|
|
||||||
logger.info('Webhook deleted successfully')
|
|
||||||
return true
|
|
||||||
} catch (error) {
|
|
||||||
logger.error('Error deleting webhook:', error)
|
|
||||||
return false
|
|
||||||
} finally {
|
|
||||||
setIsSaving(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
webhookUrl,
|
webhookUrl,
|
||||||
webhookPath: webhookPath || blockId,
|
webhookPath: webhookPath || blockId,
|
||||||
@@ -381,6 +345,5 @@ export function useWebhookManagement({
|
|||||||
isLoading,
|
isLoading,
|
||||||
isSaving,
|
isSaving,
|
||||||
saveConfig,
|
saveConfig,
|
||||||
deleteConfig,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,14 @@ export const airtableWebhookTrigger: TriggerConfig = {
|
|||||||
defaultValue: false,
|
defaultValue: false,
|
||||||
mode: 'trigger',
|
mode: 'trigger',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
hideFromPreview: true,
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'airtable_webhook',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -67,14 +75,6 @@ export const airtableWebhookTrigger: TriggerConfig = {
|
|||||||
.join(''),
|
.join(''),
|
||||||
mode: 'trigger',
|
mode: 'trigger',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
hideFromPreview: true,
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'airtable_webhook',
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: {
|
outputs: {
|
||||||
|
|||||||
@@ -38,6 +38,18 @@ export const calendlyInviteeCanceledTrigger: TriggerConfig = {
|
|||||||
value: 'calendly_invitee_canceled',
|
value: 'calendly_invitee_canceled',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
hideFromPreview: true,
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'calendly_invitee_canceled',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'calendly_invitee_canceled',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -47,7 +59,7 @@ export const calendlyInviteeCanceledTrigger: TriggerConfig = {
|
|||||||
'<strong>Note:</strong> This trigger requires a paid Calendly subscription (Professional, Teams, or Enterprise plan).',
|
'<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.',
|
'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.',
|
'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 save this trigger.',
|
'The webhook will be automatically created in Calendly once you complete the configuration above.',
|
||||||
'This webhook triggers when an invitee cancels an event. The payload includes cancellation details and reason.',
|
'This webhook triggers when an invitee cancels an event. The payload includes cancellation details and reason.',
|
||||||
]
|
]
|
||||||
.map(
|
.map(
|
||||||
@@ -61,18 +73,6 @@ export const calendlyInviteeCanceledTrigger: TriggerConfig = {
|
|||||||
value: 'calendly_invitee_canceled',
|
value: 'calendly_invitee_canceled',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
hideFromPreview: true,
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'calendly_invitee_canceled',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'calendly_invitee_canceled',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: buildInviteeOutputs(),
|
outputs: buildInviteeOutputs(),
|
||||||
|
|||||||
@@ -47,6 +47,18 @@ export const calendlyInviteeCreatedTrigger: TriggerConfig = {
|
|||||||
value: 'calendly_invitee_created',
|
value: 'calendly_invitee_created',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
hideFromPreview: true,
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'calendly_invitee_created',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'calendly_invitee_created',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -56,7 +68,7 @@ export const calendlyInviteeCreatedTrigger: TriggerConfig = {
|
|||||||
'<strong>Note:</strong> This trigger requires a paid Calendly subscription (Professional, Teams, or Enterprise plan).',
|
'<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.',
|
'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.',
|
'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 save this trigger.',
|
'The webhook will be automatically created in Calendly once you complete the configuration above.',
|
||||||
'This webhook triggers when an invitee schedules a new event. Rescheduling triggers both cancellation and creation events.',
|
'This webhook triggers when an invitee schedules a new event. Rescheduling triggers both cancellation and creation events.',
|
||||||
]
|
]
|
||||||
.map(
|
.map(
|
||||||
@@ -70,18 +82,6 @@ export const calendlyInviteeCreatedTrigger: TriggerConfig = {
|
|||||||
value: 'calendly_invitee_created',
|
value: 'calendly_invitee_created',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
hideFromPreview: true,
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'calendly_invitee_created',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'calendly_invitee_created',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: buildInviteeOutputs(),
|
outputs: buildInviteeOutputs(),
|
||||||
|
|||||||
@@ -38,6 +38,18 @@ export const calendlyRoutingFormSubmittedTrigger: TriggerConfig = {
|
|||||||
value: 'calendly_routing_form_submitted',
|
value: 'calendly_routing_form_submitted',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
hideFromPreview: true,
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'calendly_routing_form_submitted',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'calendly_routing_form_submitted',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -47,7 +59,7 @@ export const calendlyRoutingFormSubmittedTrigger: TriggerConfig = {
|
|||||||
'<strong>Note:</strong> This trigger requires a paid Calendly subscription (Professional, Teams, or Enterprise plan).',
|
'<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.',
|
'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.',
|
'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 save this trigger.',
|
'The webhook will be automatically created in Calendly once you complete the configuration above.',
|
||||||
'This webhook triggers when someone submits a routing form, regardless of whether they book an event.',
|
'This webhook triggers when someone submits a routing form, regardless of whether they book an event.',
|
||||||
]
|
]
|
||||||
.map(
|
.map(
|
||||||
@@ -61,18 +73,6 @@ export const calendlyRoutingFormSubmittedTrigger: TriggerConfig = {
|
|||||||
value: 'calendly_routing_form_submitted',
|
value: 'calendly_routing_form_submitted',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
hideFromPreview: true,
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'calendly_routing_form_submitted',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'calendly_routing_form_submitted',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: buildRoutingFormOutputs(),
|
outputs: buildRoutingFormOutputs(),
|
||||||
|
|||||||
@@ -37,6 +37,18 @@ export const calendlyWebhookTrigger: TriggerConfig = {
|
|||||||
value: 'calendly_webhook',
|
value: 'calendly_webhook',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
hideFromPreview: true,
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'calendly_webhook',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'calendly_webhook',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -46,7 +58,7 @@ export const calendlyWebhookTrigger: TriggerConfig = {
|
|||||||
'<strong>Note:</strong> This trigger requires a paid Calendly subscription (Professional, Teams, or Enterprise plan).',
|
'<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.',
|
'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.',
|
'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 save this trigger.',
|
'The webhook will be automatically created in Calendly once you complete the configuration above.',
|
||||||
'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.',
|
'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(
|
.map(
|
||||||
@@ -60,18 +72,6 @@ export const calendlyWebhookTrigger: TriggerConfig = {
|
|||||||
value: 'calendly_webhook',
|
value: 'calendly_webhook',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
hideFromPreview: true,
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'calendly_webhook',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'calendly_webhook',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: {
|
outputs: {
|
||||||
|
|||||||
@@ -56,6 +56,14 @@ export const genericWebhookTrigger: TriggerConfig = {
|
|||||||
'Define the expected JSON input schema for this webhook (optional). Use type "files" for file uploads.',
|
'Define the expected JSON input schema for this webhook (optional). Use type "files" for file uploads.',
|
||||||
mode: 'trigger',
|
mode: 'trigger',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
hideFromPreview: true,
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'generic_webhook',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -76,14 +84,6 @@ export const genericWebhookTrigger: TriggerConfig = {
|
|||||||
.join(''),
|
.join(''),
|
||||||
mode: 'trigger',
|
mode: 'trigger',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
hideFromPreview: true,
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'generic_webhook',
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: {},
|
outputs: {},
|
||||||
|
|||||||
@@ -75,6 +75,18 @@ export const githubIssueClosedTrigger: TriggerConfig = {
|
|||||||
value: 'github_issue_closed',
|
value: 'github_issue_closed',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
hideFromPreview: true,
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'github_issue_closed',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'github_issue_closed',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -101,18 +113,6 @@ export const githubIssueClosedTrigger: TriggerConfig = {
|
|||||||
value: 'github_issue_closed',
|
value: 'github_issue_closed',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
hideFromPreview: true,
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'github_issue_closed',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'github_issue_closed',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: {
|
outputs: {
|
||||||
|
|||||||
@@ -75,6 +75,18 @@ export const githubIssueCommentTrigger: TriggerConfig = {
|
|||||||
value: 'github_issue_comment',
|
value: 'github_issue_comment',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
hideFromPreview: true,
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'github_issue_comment',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'github_issue_comment',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -102,18 +114,6 @@ export const githubIssueCommentTrigger: TriggerConfig = {
|
|||||||
value: 'github_issue_comment',
|
value: 'github_issue_comment',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
hideFromPreview: true,
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'github_issue_comment',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'github_issue_comment',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: {
|
outputs: {
|
||||||
|
|||||||
@@ -96,6 +96,18 @@ export const githubIssueOpenedTrigger: TriggerConfig = {
|
|||||||
value: 'github_issue_opened',
|
value: 'github_issue_opened',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
hideFromPreview: true,
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'github_issue_opened',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'github_issue_opened',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -122,18 +134,6 @@ export const githubIssueOpenedTrigger: TriggerConfig = {
|
|||||||
value: 'github_issue_opened',
|
value: 'github_issue_opened',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
hideFromPreview: true,
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'github_issue_opened',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'github_issue_opened',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: {
|
outputs: {
|
||||||
|
|||||||
@@ -76,6 +76,18 @@ export const githubPRClosedTrigger: TriggerConfig = {
|
|||||||
value: 'github_pr_closed',
|
value: 'github_pr_closed',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
hideFromPreview: true,
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'github_pr_closed',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'github_pr_closed',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -102,18 +114,6 @@ export const githubPRClosedTrigger: TriggerConfig = {
|
|||||||
value: 'github_pr_closed',
|
value: 'github_pr_closed',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
hideFromPreview: true,
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'github_pr_closed',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'github_pr_closed',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: {
|
outputs: {
|
||||||
|
|||||||
@@ -75,6 +75,18 @@ export const githubPRCommentTrigger: TriggerConfig = {
|
|||||||
value: 'github_pr_comment',
|
value: 'github_pr_comment',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
hideFromPreview: true,
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'github_pr_comment',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'github_pr_comment',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -102,18 +114,6 @@ export const githubPRCommentTrigger: TriggerConfig = {
|
|||||||
value: 'github_pr_comment',
|
value: 'github_pr_comment',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
hideFromPreview: true,
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'github_pr_comment',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'github_pr_comment',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: {
|
outputs: {
|
||||||
|
|||||||
@@ -75,6 +75,18 @@ export const githubPRMergedTrigger: TriggerConfig = {
|
|||||||
value: 'github_pr_merged',
|
value: 'github_pr_merged',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
hideFromPreview: true,
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'github_pr_merged',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'github_pr_merged',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -101,18 +113,6 @@ export const githubPRMergedTrigger: TriggerConfig = {
|
|||||||
value: 'github_pr_merged',
|
value: 'github_pr_merged',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
hideFromPreview: true,
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'github_pr_merged',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'github_pr_merged',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: {
|
outputs: {
|
||||||
|
|||||||
@@ -75,6 +75,18 @@ export const githubPROpenedTrigger: TriggerConfig = {
|
|||||||
value: 'github_pr_opened',
|
value: 'github_pr_opened',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
hideFromPreview: true,
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'github_pr_opened',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'github_pr_opened',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -101,18 +113,6 @@ export const githubPROpenedTrigger: TriggerConfig = {
|
|||||||
value: 'github_pr_opened',
|
value: 'github_pr_opened',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
hideFromPreview: true,
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'github_pr_opened',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'github_pr_opened',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: {
|
outputs: {
|
||||||
|
|||||||
@@ -76,6 +76,18 @@ export const githubPRReviewedTrigger: TriggerConfig = {
|
|||||||
value: 'github_pr_reviewed',
|
value: 'github_pr_reviewed',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
hideFromPreview: true,
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'github_pr_reviewed',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'github_pr_reviewed',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -102,18 +114,6 @@ export const githubPRReviewedTrigger: TriggerConfig = {
|
|||||||
value: 'github_pr_reviewed',
|
value: 'github_pr_reviewed',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
hideFromPreview: true,
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'github_pr_reviewed',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'github_pr_reviewed',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: {
|
outputs: {
|
||||||
|
|||||||
@@ -75,6 +75,18 @@ export const githubPushTrigger: TriggerConfig = {
|
|||||||
value: 'github_push',
|
value: 'github_push',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
hideFromPreview: true,
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'github_push',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'github_push',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -101,18 +113,6 @@ export const githubPushTrigger: TriggerConfig = {
|
|||||||
value: 'github_push',
|
value: 'github_push',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
hideFromPreview: true,
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'github_push',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'github_push',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: {
|
outputs: {
|
||||||
|
|||||||
@@ -75,6 +75,18 @@ export const githubReleasePublishedTrigger: TriggerConfig = {
|
|||||||
value: 'github_release_published',
|
value: 'github_release_published',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
hideFromPreview: true,
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'github_release_published',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'github_release_published',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -101,18 +113,6 @@ export const githubReleasePublishedTrigger: TriggerConfig = {
|
|||||||
value: 'github_release_published',
|
value: 'github_release_published',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
hideFromPreview: true,
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'github_release_published',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'github_release_published',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: {
|
outputs: {
|
||||||
|
|||||||
@@ -72,6 +72,18 @@ export const githubWebhookTrigger: TriggerConfig = {
|
|||||||
value: 'github_webhook',
|
value: 'github_webhook',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
hideFromPreview: true,
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'github_webhook',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'github_webhook',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -98,18 +110,6 @@ export const githubWebhookTrigger: TriggerConfig = {
|
|||||||
value: 'github_webhook',
|
value: 'github_webhook',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
hideFromPreview: true,
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'github_webhook',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'github_webhook',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: {
|
outputs: {
|
||||||
|
|||||||
@@ -76,6 +76,18 @@ export const githubWorkflowRunTrigger: TriggerConfig = {
|
|||||||
value: 'github_workflow_run',
|
value: 'github_workflow_run',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
hideFromPreview: true,
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'github_workflow_run',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'github_workflow_run',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -102,18 +114,6 @@ export const githubWorkflowRunTrigger: TriggerConfig = {
|
|||||||
value: 'github_workflow_run',
|
value: 'github_workflow_run',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
hideFromPreview: true,
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'github_workflow_run',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'github_workflow_run',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: {
|
outputs: {
|
||||||
|
|||||||
@@ -104,6 +104,14 @@ export const gmailPollingTrigger: TriggerConfig = {
|
|||||||
required: false,
|
required: false,
|
||||||
mode: 'trigger',
|
mode: 'trigger',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
hideFromPreview: true,
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'gmail_poller',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -121,14 +129,6 @@ export const gmailPollingTrigger: TriggerConfig = {
|
|||||||
.join(''),
|
.join(''),
|
||||||
mode: 'trigger',
|
mode: 'trigger',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
hideFromPreview: true,
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'gmail_poller',
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: {
|
outputs: {
|
||||||
|
|||||||
@@ -59,6 +59,14 @@ export const googleFormsWebhookTrigger: TriggerConfig = {
|
|||||||
defaultValue: true,
|
defaultValue: true,
|
||||||
mode: 'trigger',
|
mode: 'trigger',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
hideFromPreview: true,
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'google_forms_webhook',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -86,12 +94,12 @@ export const googleFormsWebhookTrigger: TriggerConfig = {
|
|||||||
const script = `function onFormSubmit(e) {
|
const script = `function onFormSubmit(e) {
|
||||||
const WEBHOOK_URL = "{{WEBHOOK_URL}}";
|
const WEBHOOK_URL = "{{WEBHOOK_URL}}";
|
||||||
const SHARED_SECRET = "{{SHARED_SECRET}}";
|
const SHARED_SECRET = "{{SHARED_SECRET}}";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const form = FormApp.getActiveForm();
|
const form = FormApp.getActiveForm();
|
||||||
const formResponse = e.response;
|
const formResponse = e.response;
|
||||||
const itemResponses = formResponse.getItemResponses();
|
const itemResponses = formResponse.getItemResponses();
|
||||||
|
|
||||||
// Build answers object
|
// Build answers object
|
||||||
const answers = {};
|
const answers = {};
|
||||||
for (var i = 0; i < itemResponses.length; i++) {
|
for (var i = 0; i < itemResponses.length; i++) {
|
||||||
@@ -100,7 +108,7 @@ export const googleFormsWebhookTrigger: TriggerConfig = {
|
|||||||
const answer = itemResponse.getResponse();
|
const answer = itemResponse.getResponse();
|
||||||
answers[question] = answer;
|
answers[question] = answer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build payload
|
// Build payload
|
||||||
const payload = {
|
const payload = {
|
||||||
provider: "google_forms",
|
provider: "google_forms",
|
||||||
@@ -110,7 +118,7 @@ export const googleFormsWebhookTrigger: TriggerConfig = {
|
|||||||
lastSubmittedTime: formResponse.getTimestamp().toISOString(),
|
lastSubmittedTime: formResponse.getTimestamp().toISOString(),
|
||||||
answers: answers
|
answers: answers
|
||||||
};
|
};
|
||||||
|
|
||||||
// Send to webhook
|
// Send to webhook
|
||||||
const options = {
|
const options = {
|
||||||
method: "post",
|
method: "post",
|
||||||
@@ -121,9 +129,9 @@ export const googleFormsWebhookTrigger: TriggerConfig = {
|
|||||||
payload: JSON.stringify(payload),
|
payload: JSON.stringify(payload),
|
||||||
muteHttpExceptions: true
|
muteHttpExceptions: true
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = UrlFetchApp.fetch(WEBHOOK_URL, options);
|
const response = UrlFetchApp.fetch(WEBHOOK_URL, options);
|
||||||
|
|
||||||
if (response.getResponseCode() !== 200) {
|
if (response.getResponseCode() !== 200) {
|
||||||
Logger.log("Webhook failed: " + response.getContentText());
|
Logger.log("Webhook failed: " + response.getContentText());
|
||||||
} else {
|
} else {
|
||||||
@@ -145,14 +153,6 @@ export const googleFormsWebhookTrigger: TriggerConfig = {
|
|||||||
description: 'Copy this code and paste it into your Google Forms Apps Script editor',
|
description: 'Copy this code and paste it into your Google Forms Apps Script editor',
|
||||||
mode: 'trigger',
|
mode: 'trigger',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
hideFromPreview: true,
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'google_forms_webhook',
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: {
|
outputs: {
|
||||||
|
|||||||
@@ -93,6 +93,17 @@ export const hubspotCompanyCreatedTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_company_created',
|
value: 'hubspot_company_created',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'hubspot_company_created',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'hubspot_company_created',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -156,17 +167,6 @@ export const hubspotCompanyCreatedTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_company_created',
|
value: 'hubspot_company_created',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'hubspot_company_created',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'hubspot_company_created',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'samplePayload',
|
id: 'samplePayload',
|
||||||
title: 'Event Payload Example',
|
title: 'Event Payload Example',
|
||||||
|
|||||||
@@ -93,6 +93,17 @@ export const hubspotCompanyDeletedTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_company_deleted',
|
value: 'hubspot_company_deleted',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'hubspot_company_deleted',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'hubspot_company_deleted',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -156,17 +167,6 @@ export const hubspotCompanyDeletedTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_company_deleted',
|
value: 'hubspot_company_deleted',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'hubspot_company_deleted',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'hubspot_company_deleted',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'samplePayload',
|
id: 'samplePayload',
|
||||||
title: 'Event Payload Example',
|
title: 'Event Payload Example',
|
||||||
|
|||||||
@@ -107,6 +107,17 @@ export const hubspotCompanyPropertyChangedTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_company_property_changed',
|
value: 'hubspot_company_property_changed',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'hubspot_company_property_changed',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'hubspot_company_property_changed',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -170,17 +181,6 @@ export const hubspotCompanyPropertyChangedTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_company_property_changed',
|
value: 'hubspot_company_property_changed',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'hubspot_company_property_changed',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'hubspot_company_property_changed',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'samplePayload',
|
id: 'samplePayload',
|
||||||
title: 'Event Payload Example',
|
title: 'Event Payload Example',
|
||||||
|
|||||||
@@ -93,6 +93,17 @@ export const hubspotContactCreatedTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_contact_created',
|
value: 'hubspot_contact_created',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'hubspot_contact_created',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'hubspot_contact_created',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -156,17 +167,6 @@ export const hubspotContactCreatedTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_contact_created',
|
value: 'hubspot_contact_created',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'hubspot_contact_created',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'hubspot_contact_created',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'samplePayload',
|
id: 'samplePayload',
|
||||||
title: 'Event Payload Example',
|
title: 'Event Payload Example',
|
||||||
|
|||||||
@@ -93,6 +93,17 @@ export const hubspotContactDeletedTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_contact_deleted',
|
value: 'hubspot_contact_deleted',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'hubspot_contact_deleted',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'hubspot_contact_deleted',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -156,17 +167,6 @@ export const hubspotContactDeletedTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_contact_deleted',
|
value: 'hubspot_contact_deleted',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'hubspot_contact_deleted',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'hubspot_contact_deleted',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'samplePayload',
|
id: 'samplePayload',
|
||||||
title: 'Event Payload Example',
|
title: 'Event Payload Example',
|
||||||
|
|||||||
@@ -94,6 +94,17 @@ export const hubspotContactPrivacyDeletedTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_contact_privacy_deleted',
|
value: 'hubspot_contact_privacy_deleted',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'hubspot_contact_privacy_deleted',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'hubspot_contact_privacy_deleted',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -157,17 +168,6 @@ export const hubspotContactPrivacyDeletedTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_contact_privacy_deleted',
|
value: 'hubspot_contact_privacy_deleted',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'hubspot_contact_privacy_deleted',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'hubspot_contact_privacy_deleted',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'samplePayload',
|
id: 'samplePayload',
|
||||||
title: 'Event Payload Example',
|
title: 'Event Payload Example',
|
||||||
|
|||||||
@@ -107,6 +107,17 @@ export const hubspotContactPropertyChangedTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_contact_property_changed',
|
value: 'hubspot_contact_property_changed',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'hubspot_contact_property_changed',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'hubspot_contact_property_changed',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -170,17 +181,6 @@ export const hubspotContactPropertyChangedTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_contact_property_changed',
|
value: 'hubspot_contact_property_changed',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'hubspot_contact_property_changed',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'hubspot_contact_property_changed',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'samplePayload',
|
id: 'samplePayload',
|
||||||
title: 'Event Payload Example',
|
title: 'Event Payload Example',
|
||||||
|
|||||||
@@ -93,6 +93,17 @@ export const hubspotConversationCreationTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_conversation_creation',
|
value: 'hubspot_conversation_creation',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'hubspot_conversation_creation',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'hubspot_conversation_creation',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -156,17 +167,6 @@ export const hubspotConversationCreationTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_conversation_creation',
|
value: 'hubspot_conversation_creation',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'hubspot_conversation_creation',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'hubspot_conversation_creation',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'samplePayload',
|
id: 'samplePayload',
|
||||||
title: 'Event Payload Example',
|
title: 'Event Payload Example',
|
||||||
|
|||||||
@@ -93,6 +93,17 @@ export const hubspotConversationDeletionTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_conversation_deletion',
|
value: 'hubspot_conversation_deletion',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'hubspot_conversation_deletion',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'hubspot_conversation_deletion',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -156,17 +167,6 @@ export const hubspotConversationDeletionTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_conversation_deletion',
|
value: 'hubspot_conversation_deletion',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'hubspot_conversation_deletion',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'hubspot_conversation_deletion',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'samplePayload',
|
id: 'samplePayload',
|
||||||
title: 'Event Payload Example',
|
title: 'Event Payload Example',
|
||||||
|
|||||||
@@ -93,6 +93,17 @@ export const hubspotConversationNewMessageTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_conversation_new_message',
|
value: 'hubspot_conversation_new_message',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'hubspot_conversation_new_message',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'hubspot_conversation_new_message',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -156,17 +167,6 @@ export const hubspotConversationNewMessageTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_conversation_new_message',
|
value: 'hubspot_conversation_new_message',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'hubspot_conversation_new_message',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'hubspot_conversation_new_message',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'samplePayload',
|
id: 'samplePayload',
|
||||||
title: 'Event Payload Example',
|
title: 'Event Payload Example',
|
||||||
|
|||||||
@@ -94,6 +94,17 @@ export const hubspotConversationPrivacyDeletionTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_conversation_privacy_deletion',
|
value: 'hubspot_conversation_privacy_deletion',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'hubspot_conversation_privacy_deletion',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'hubspot_conversation_privacy_deletion',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -157,17 +168,6 @@ export const hubspotConversationPrivacyDeletionTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_conversation_privacy_deletion',
|
value: 'hubspot_conversation_privacy_deletion',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'hubspot_conversation_privacy_deletion',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'hubspot_conversation_privacy_deletion',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'samplePayload',
|
id: 'samplePayload',
|
||||||
title: 'Event Payload Example',
|
title: 'Event Payload Example',
|
||||||
|
|||||||
@@ -107,6 +107,17 @@ export const hubspotConversationPropertyChangedTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_conversation_property_changed',
|
value: 'hubspot_conversation_property_changed',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'hubspot_conversation_property_changed',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'hubspot_conversation_property_changed',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -170,17 +181,6 @@ export const hubspotConversationPropertyChangedTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_conversation_property_changed',
|
value: 'hubspot_conversation_property_changed',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'hubspot_conversation_property_changed',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'hubspot_conversation_property_changed',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'samplePayload',
|
id: 'samplePayload',
|
||||||
title: 'Event Payload Example',
|
title: 'Event Payload Example',
|
||||||
|
|||||||
@@ -93,6 +93,17 @@ export const hubspotDealCreatedTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_deal_created',
|
value: 'hubspot_deal_created',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'hubspot_deal_created',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'hubspot_deal_created',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -156,17 +167,6 @@ export const hubspotDealCreatedTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_deal_created',
|
value: 'hubspot_deal_created',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'hubspot_deal_created',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'hubspot_deal_created',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'samplePayload',
|
id: 'samplePayload',
|
||||||
title: 'Event Payload Example',
|
title: 'Event Payload Example',
|
||||||
|
|||||||
@@ -93,6 +93,17 @@ export const hubspotDealDeletedTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_deal_deleted',
|
value: 'hubspot_deal_deleted',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'hubspot_deal_deleted',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'hubspot_deal_deleted',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -156,17 +167,6 @@ export const hubspotDealDeletedTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_deal_deleted',
|
value: 'hubspot_deal_deleted',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'hubspot_deal_deleted',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'hubspot_deal_deleted',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'samplePayload',
|
id: 'samplePayload',
|
||||||
title: 'Event Payload Example',
|
title: 'Event Payload Example',
|
||||||
|
|||||||
@@ -107,6 +107,17 @@ export const hubspotDealPropertyChangedTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_deal_property_changed',
|
value: 'hubspot_deal_property_changed',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'hubspot_deal_property_changed',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'hubspot_deal_property_changed',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -170,17 +181,6 @@ export const hubspotDealPropertyChangedTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_deal_property_changed',
|
value: 'hubspot_deal_property_changed',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'hubspot_deal_property_changed',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'hubspot_deal_property_changed',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'samplePayload',
|
id: 'samplePayload',
|
||||||
title: 'Event Payload Example',
|
title: 'Event Payload Example',
|
||||||
|
|||||||
@@ -93,6 +93,17 @@ export const hubspotTicketCreatedTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_ticket_created',
|
value: 'hubspot_ticket_created',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'hubspot_ticket_created',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'hubspot_ticket_created',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -156,17 +167,6 @@ export const hubspotTicketCreatedTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_ticket_created',
|
value: 'hubspot_ticket_created',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'hubspot_ticket_created',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'hubspot_ticket_created',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'samplePayload',
|
id: 'samplePayload',
|
||||||
title: 'Event Payload Example',
|
title: 'Event Payload Example',
|
||||||
|
|||||||
@@ -93,6 +93,17 @@ export const hubspotTicketDeletedTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_ticket_deleted',
|
value: 'hubspot_ticket_deleted',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'hubspot_ticket_deleted',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'hubspot_ticket_deleted',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -156,17 +167,6 @@ export const hubspotTicketDeletedTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_ticket_deleted',
|
value: 'hubspot_ticket_deleted',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'hubspot_ticket_deleted',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'hubspot_ticket_deleted',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'samplePayload',
|
id: 'samplePayload',
|
||||||
title: 'Event Payload Example',
|
title: 'Event Payload Example',
|
||||||
|
|||||||
@@ -107,6 +107,17 @@ export const hubspotTicketPropertyChangedTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_ticket_property_changed',
|
value: 'hubspot_ticket_property_changed',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'hubspot_ticket_property_changed',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'hubspot_ticket_property_changed',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -170,17 +181,6 @@ export const hubspotTicketPropertyChangedTrigger: TriggerConfig = {
|
|||||||
value: 'hubspot_ticket_property_changed',
|
value: 'hubspot_ticket_property_changed',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'hubspot_ticket_property_changed',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'hubspot_ticket_property_changed',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'samplePayload',
|
id: 'samplePayload',
|
||||||
title: 'Event Payload Example',
|
title: 'Event Payload Example',
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ export function hubspotSetupInstructions(eventType: string, additionalNotes?: st
|
|||||||
'<strong>Step 3: Configure OAuth Settings</strong><br/>After creating your app via CLI, configure it to add the OAuth Redirect URL: <code>https://www.sim.ai/api/auth/oauth2/callback/hubspot</code>. Then retrieve your <strong>Client ID</strong> and <strong>Client Secret</strong> from your app configuration and enter them in the fields above.',
|
'<strong>Step 3: Configure OAuth Settings</strong><br/>After creating your app via CLI, configure it to add the OAuth Redirect URL: <code>https://www.sim.ai/api/auth/oauth2/callback/hubspot</code>. Then retrieve your <strong>Client ID</strong> and <strong>Client Secret</strong> from your app configuration and enter them in the fields above.',
|
||||||
"<strong>Step 4: Get App ID and Developer API Key</strong><br/>In your HubSpot developer account, find your <strong>App ID</strong> (shown below your app name) and your <strong>Developer API Key</strong> (in app settings). You'll need both for the next steps.",
|
"<strong>Step 4: Get App ID and Developer API Key</strong><br/>In your HubSpot developer account, find your <strong>App ID</strong> (shown below your app name) and your <strong>Developer API Key</strong> (in app settings). You'll need both for the next steps.",
|
||||||
'<strong>Step 5: Set Required Scopes</strong><br/>Configure your app to include the required OAuth scope: <code>crm.objects.contacts.read</code>',
|
'<strong>Step 5: Set Required Scopes</strong><br/>Configure your app to include the required OAuth scope: <code>crm.objects.contacts.read</code>',
|
||||||
'<strong>Step 6: Save Configuration in Sim</strong><br/>Click the <strong>"Save Configuration"</strong> button below. This will generate your unique webhook URL.',
|
'<strong>Step 6: Save Configuration in Sim</strong><br/>Your unique webhook URL will be generated automatically once you complete the configuration above.',
|
||||||
'<strong>Step 7: Configure Webhook in HubSpot via API</strong><br/>After saving above, copy the <strong>Webhook URL</strong> and run the two curl commands below (replace <code>{YOUR_APP_ID}</code>, <code>{YOUR_DEVELOPER_API_KEY}</code>, and <code>{YOUR_WEBHOOK_URL_FROM_ABOVE}</code> with your actual values).',
|
'<strong>Step 7: Configure Webhook in HubSpot via API</strong><br/>After saving above, copy the <strong>Webhook URL</strong> and run the two curl commands below (replace <code>{YOUR_APP_ID}</code>, <code>{YOUR_DEVELOPER_API_KEY}</code>, and <code>{YOUR_WEBHOOK_URL_FROM_ABOVE}</code> with your actual values).',
|
||||||
"<strong>Step 8: Test Your Webhook</strong><br/>Create or modify a contact in HubSpot to trigger the webhook. Check your workflow execution logs in Sim to verify it's working.",
|
"<strong>Step 8: Test Your Webhook</strong><br/>Create or modify a contact in HubSpot to trigger the webhook. Check your workflow execution logs in Sim to verify it's working.",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -56,18 +56,6 @@ export const jiraIssueCommentedTrigger: TriggerConfig = {
|
|||||||
value: 'jira_issue_commented',
|
value: 'jira_issue_commented',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerInstructions',
|
|
||||||
title: 'Setup Instructions',
|
|
||||||
hideFromPreview: true,
|
|
||||||
type: 'text',
|
|
||||||
defaultValue: jiraSetupInstructions('comment_created'),
|
|
||||||
mode: 'trigger',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'jira_issue_commented',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'triggerSave',
|
id: 'triggerSave',
|
||||||
title: '',
|
title: '',
|
||||||
@@ -80,6 +68,18 @@ export const jiraIssueCommentedTrigger: TriggerConfig = {
|
|||||||
value: 'jira_issue_commented',
|
value: 'jira_issue_commented',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerInstructions',
|
||||||
|
title: 'Setup Instructions',
|
||||||
|
hideFromPreview: true,
|
||||||
|
type: 'text',
|
||||||
|
defaultValue: jiraSetupInstructions('comment_created'),
|
||||||
|
mode: 'trigger',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'jira_issue_commented',
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: buildCommentOutputs(),
|
outputs: buildCommentOutputs(),
|
||||||
|
|||||||
@@ -65,18 +65,6 @@ export const jiraIssueCreatedTrigger: TriggerConfig = {
|
|||||||
value: 'jira_issue_created',
|
value: 'jira_issue_created',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerInstructions',
|
|
||||||
title: 'Setup Instructions',
|
|
||||||
hideFromPreview: true,
|
|
||||||
type: 'text',
|
|
||||||
defaultValue: jiraSetupInstructions('jira:issue_created'),
|
|
||||||
mode: 'trigger',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'jira_issue_created',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'triggerSave',
|
id: 'triggerSave',
|
||||||
title: '',
|
title: '',
|
||||||
@@ -89,6 +77,18 @@ export const jiraIssueCreatedTrigger: TriggerConfig = {
|
|||||||
value: 'jira_issue_created',
|
value: 'jira_issue_created',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerInstructions',
|
||||||
|
title: 'Setup Instructions',
|
||||||
|
hideFromPreview: true,
|
||||||
|
type: 'text',
|
||||||
|
defaultValue: jiraSetupInstructions('jira:issue_created'),
|
||||||
|
mode: 'trigger',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'jira_issue_created',
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: buildIssueOutputs(),
|
outputs: buildIssueOutputs(),
|
||||||
|
|||||||
@@ -56,18 +56,6 @@ export const jiraIssueDeletedTrigger: TriggerConfig = {
|
|||||||
value: 'jira_issue_deleted',
|
value: 'jira_issue_deleted',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerInstructions',
|
|
||||||
title: 'Setup Instructions',
|
|
||||||
hideFromPreview: true,
|
|
||||||
type: 'text',
|
|
||||||
defaultValue: jiraSetupInstructions('jira:issue_deleted'),
|
|
||||||
mode: 'trigger',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'jira_issue_deleted',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'triggerSave',
|
id: 'triggerSave',
|
||||||
title: '',
|
title: '',
|
||||||
@@ -80,6 +68,18 @@ export const jiraIssueDeletedTrigger: TriggerConfig = {
|
|||||||
value: 'jira_issue_deleted',
|
value: 'jira_issue_deleted',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerInstructions',
|
||||||
|
title: 'Setup Instructions',
|
||||||
|
hideFromPreview: true,
|
||||||
|
type: 'text',
|
||||||
|
defaultValue: jiraSetupInstructions('jira:issue_deleted'),
|
||||||
|
mode: 'trigger',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'jira_issue_deleted',
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: buildIssueOutputs(),
|
outputs: buildIssueOutputs(),
|
||||||
|
|||||||
@@ -70,18 +70,6 @@ export const jiraIssueUpdatedTrigger: TriggerConfig = {
|
|||||||
value: 'jira_issue_updated',
|
value: 'jira_issue_updated',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerInstructions',
|
|
||||||
title: 'Setup Instructions',
|
|
||||||
hideFromPreview: true,
|
|
||||||
type: 'text',
|
|
||||||
defaultValue: jiraSetupInstructions('jira:issue_updated'),
|
|
||||||
mode: 'trigger',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'jira_issue_updated',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'triggerSave',
|
id: 'triggerSave',
|
||||||
title: '',
|
title: '',
|
||||||
@@ -94,6 +82,18 @@ export const jiraIssueUpdatedTrigger: TriggerConfig = {
|
|||||||
value: 'jira_issue_updated',
|
value: 'jira_issue_updated',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerInstructions',
|
||||||
|
title: 'Setup Instructions',
|
||||||
|
hideFromPreview: true,
|
||||||
|
type: 'text',
|
||||||
|
defaultValue: jiraSetupInstructions('jira:issue_updated'),
|
||||||
|
mode: 'trigger',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'jira_issue_updated',
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: buildIssueUpdatedOutputs(),
|
outputs: buildIssueUpdatedOutputs(),
|
||||||
|
|||||||
@@ -43,18 +43,6 @@ export const jiraWebhookTrigger: TriggerConfig = {
|
|||||||
value: 'jira_webhook',
|
value: 'jira_webhook',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerInstructions',
|
|
||||||
title: 'Setup Instructions',
|
|
||||||
hideFromPreview: true,
|
|
||||||
type: 'text',
|
|
||||||
defaultValue: jiraSetupInstructions('All Events'),
|
|
||||||
mode: 'trigger',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'jira_webhook',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'triggerSave',
|
id: 'triggerSave',
|
||||||
title: '',
|
title: '',
|
||||||
@@ -67,6 +55,18 @@ export const jiraWebhookTrigger: TriggerConfig = {
|
|||||||
value: 'jira_webhook',
|
value: 'jira_webhook',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerInstructions',
|
||||||
|
title: 'Setup Instructions',
|
||||||
|
hideFromPreview: true,
|
||||||
|
type: 'text',
|
||||||
|
defaultValue: jiraSetupInstructions('All Events'),
|
||||||
|
mode: 'trigger',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'jira_webhook',
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: {
|
outputs: {
|
||||||
|
|||||||
@@ -56,18 +56,6 @@ export const jiraWorklogCreatedTrigger: TriggerConfig = {
|
|||||||
value: 'jira_worklog_created',
|
value: 'jira_worklog_created',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerInstructions',
|
|
||||||
title: 'Setup Instructions',
|
|
||||||
hideFromPreview: true,
|
|
||||||
type: 'text',
|
|
||||||
defaultValue: jiraSetupInstructions('worklog_created'),
|
|
||||||
mode: 'trigger',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'jira_worklog_created',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'triggerSave',
|
id: 'triggerSave',
|
||||||
title: '',
|
title: '',
|
||||||
@@ -80,6 +68,18 @@ export const jiraWorklogCreatedTrigger: TriggerConfig = {
|
|||||||
value: 'jira_worklog_created',
|
value: 'jira_worklog_created',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerInstructions',
|
||||||
|
title: 'Setup Instructions',
|
||||||
|
hideFromPreview: true,
|
||||||
|
type: 'text',
|
||||||
|
defaultValue: jiraSetupInstructions('worklog_created'),
|
||||||
|
mode: 'trigger',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'jira_worklog_created',
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: buildWorklogOutputs(),
|
outputs: buildWorklogOutputs(),
|
||||||
|
|||||||
@@ -39,18 +39,6 @@ export const linearCommentCreatedTrigger: TriggerConfig = {
|
|||||||
value: 'linear_comment_created',
|
value: 'linear_comment_created',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerInstructions',
|
|
||||||
title: 'Setup Instructions',
|
|
||||||
hideFromPreview: true,
|
|
||||||
type: 'text',
|
|
||||||
defaultValue: linearSetupInstructions('Comment (create)'),
|
|
||||||
mode: 'trigger',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'linear_comment_created',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'triggerSave',
|
id: 'triggerSave',
|
||||||
title: '',
|
title: '',
|
||||||
@@ -63,6 +51,18 @@ export const linearCommentCreatedTrigger: TriggerConfig = {
|
|||||||
value: 'linear_comment_created',
|
value: 'linear_comment_created',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerInstructions',
|
||||||
|
title: 'Setup Instructions',
|
||||||
|
hideFromPreview: true,
|
||||||
|
type: 'text',
|
||||||
|
defaultValue: linearSetupInstructions('Comment (create)'),
|
||||||
|
mode: 'trigger',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'linear_comment_created',
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: buildCommentOutputs(),
|
outputs: buildCommentOutputs(),
|
||||||
|
|||||||
@@ -39,18 +39,6 @@ export const linearCommentUpdatedTrigger: TriggerConfig = {
|
|||||||
value: 'linear_comment_updated',
|
value: 'linear_comment_updated',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerInstructions',
|
|
||||||
title: 'Setup Instructions',
|
|
||||||
hideFromPreview: true,
|
|
||||||
type: 'text',
|
|
||||||
defaultValue: linearSetupInstructions('Comment (update)'),
|
|
||||||
mode: 'trigger',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'linear_comment_updated',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'triggerSave',
|
id: 'triggerSave',
|
||||||
title: '',
|
title: '',
|
||||||
@@ -63,6 +51,18 @@ export const linearCommentUpdatedTrigger: TriggerConfig = {
|
|||||||
value: 'linear_comment_updated',
|
value: 'linear_comment_updated',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerInstructions',
|
||||||
|
title: 'Setup Instructions',
|
||||||
|
hideFromPreview: true,
|
||||||
|
type: 'text',
|
||||||
|
defaultValue: linearSetupInstructions('Comment (update)'),
|
||||||
|
mode: 'trigger',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'linear_comment_updated',
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: buildCommentOutputs(),
|
outputs: buildCommentOutputs(),
|
||||||
|
|||||||
@@ -39,18 +39,6 @@ export const linearCustomerRequestCreatedTrigger: TriggerConfig = {
|
|||||||
value: 'linear_customer_request_created',
|
value: 'linear_customer_request_created',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerInstructions',
|
|
||||||
title: 'Setup Instructions',
|
|
||||||
hideFromPreview: true,
|
|
||||||
type: 'text',
|
|
||||||
defaultValue: linearSetupInstructions('Customer Requests'),
|
|
||||||
mode: 'trigger',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'linear_customer_request_created',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'triggerSave',
|
id: 'triggerSave',
|
||||||
title: '',
|
title: '',
|
||||||
@@ -63,6 +51,18 @@ export const linearCustomerRequestCreatedTrigger: TriggerConfig = {
|
|||||||
value: 'linear_customer_request_created',
|
value: 'linear_customer_request_created',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerInstructions',
|
||||||
|
title: 'Setup Instructions',
|
||||||
|
hideFromPreview: true,
|
||||||
|
type: 'text',
|
||||||
|
defaultValue: linearSetupInstructions('Customer Requests'),
|
||||||
|
mode: 'trigger',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'linear_customer_request_created',
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: buildCustomerRequestOutputs(),
|
outputs: buildCustomerRequestOutputs(),
|
||||||
|
|||||||
@@ -39,18 +39,6 @@ export const linearCustomerRequestUpdatedTrigger: TriggerConfig = {
|
|||||||
value: 'linear_customer_request_updated',
|
value: 'linear_customer_request_updated',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerInstructions',
|
|
||||||
title: 'Setup Instructions',
|
|
||||||
hideFromPreview: true,
|
|
||||||
type: 'text',
|
|
||||||
defaultValue: linearSetupInstructions('CustomerNeed (update)'),
|
|
||||||
mode: 'trigger',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'linear_customer_request_updated',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'triggerSave',
|
id: 'triggerSave',
|
||||||
title: '',
|
title: '',
|
||||||
@@ -63,6 +51,18 @@ export const linearCustomerRequestUpdatedTrigger: TriggerConfig = {
|
|||||||
value: 'linear_customer_request_updated',
|
value: 'linear_customer_request_updated',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerInstructions',
|
||||||
|
title: 'Setup Instructions',
|
||||||
|
hideFromPreview: true,
|
||||||
|
type: 'text',
|
||||||
|
defaultValue: linearSetupInstructions('CustomerNeed (update)'),
|
||||||
|
mode: 'trigger',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'linear_customer_request_updated',
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: buildCustomerRequestOutputs(),
|
outputs: buildCustomerRequestOutputs(),
|
||||||
|
|||||||
@@ -39,18 +39,6 @@ export const linearCycleCreatedTrigger: TriggerConfig = {
|
|||||||
value: 'linear_cycle_created',
|
value: 'linear_cycle_created',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerInstructions',
|
|
||||||
title: 'Setup Instructions',
|
|
||||||
hideFromPreview: true,
|
|
||||||
type: 'text',
|
|
||||||
defaultValue: linearSetupInstructions('Cycle (create)'),
|
|
||||||
mode: 'trigger',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'linear_cycle_created',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'triggerSave',
|
id: 'triggerSave',
|
||||||
title: '',
|
title: '',
|
||||||
@@ -63,6 +51,18 @@ export const linearCycleCreatedTrigger: TriggerConfig = {
|
|||||||
value: 'linear_cycle_created',
|
value: 'linear_cycle_created',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerInstructions',
|
||||||
|
title: 'Setup Instructions',
|
||||||
|
hideFromPreview: true,
|
||||||
|
type: 'text',
|
||||||
|
defaultValue: linearSetupInstructions('Cycle (create)'),
|
||||||
|
mode: 'trigger',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'linear_cycle_created',
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: buildCycleOutputs(),
|
outputs: buildCycleOutputs(),
|
||||||
|
|||||||
@@ -39,18 +39,6 @@ export const linearCycleUpdatedTrigger: TriggerConfig = {
|
|||||||
value: 'linear_cycle_updated',
|
value: 'linear_cycle_updated',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerInstructions',
|
|
||||||
title: 'Setup Instructions',
|
|
||||||
hideFromPreview: true,
|
|
||||||
type: 'text',
|
|
||||||
defaultValue: linearSetupInstructions('Cycle (update)'),
|
|
||||||
mode: 'trigger',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'linear_cycle_updated',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'triggerSave',
|
id: 'triggerSave',
|
||||||
title: '',
|
title: '',
|
||||||
@@ -63,6 +51,18 @@ export const linearCycleUpdatedTrigger: TriggerConfig = {
|
|||||||
value: 'linear_cycle_updated',
|
value: 'linear_cycle_updated',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerInstructions',
|
||||||
|
title: 'Setup Instructions',
|
||||||
|
hideFromPreview: true,
|
||||||
|
type: 'text',
|
||||||
|
defaultValue: linearSetupInstructions('Cycle (update)'),
|
||||||
|
mode: 'trigger',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'linear_cycle_updated',
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: buildCycleOutputs(),
|
outputs: buildCycleOutputs(),
|
||||||
|
|||||||
@@ -52,18 +52,6 @@ export const linearIssueCreatedTrigger: TriggerConfig = {
|
|||||||
value: 'linear_issue_created',
|
value: 'linear_issue_created',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerInstructions',
|
|
||||||
title: 'Setup Instructions',
|
|
||||||
hideFromPreview: true,
|
|
||||||
type: 'text',
|
|
||||||
defaultValue: linearSetupInstructions('Issue (create)'),
|
|
||||||
mode: 'trigger',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'linear_issue_created',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'triggerSave',
|
id: 'triggerSave',
|
||||||
title: '',
|
title: '',
|
||||||
@@ -76,6 +64,18 @@ export const linearIssueCreatedTrigger: TriggerConfig = {
|
|||||||
value: 'linear_issue_created',
|
value: 'linear_issue_created',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerInstructions',
|
||||||
|
title: 'Setup Instructions',
|
||||||
|
hideFromPreview: true,
|
||||||
|
type: 'text',
|
||||||
|
defaultValue: linearSetupInstructions('Issue (create)'),
|
||||||
|
mode: 'trigger',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'linear_issue_created',
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: buildIssueOutputs(),
|
outputs: buildIssueOutputs(),
|
||||||
|
|||||||
@@ -39,18 +39,6 @@ export const linearIssueRemovedTrigger: TriggerConfig = {
|
|||||||
value: 'linear_issue_removed',
|
value: 'linear_issue_removed',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerInstructions',
|
|
||||||
title: 'Setup Instructions',
|
|
||||||
hideFromPreview: true,
|
|
||||||
type: 'text',
|
|
||||||
defaultValue: linearSetupInstructions('Issue (remove)'),
|
|
||||||
mode: 'trigger',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'linear_issue_removed',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'triggerSave',
|
id: 'triggerSave',
|
||||||
title: '',
|
title: '',
|
||||||
@@ -63,6 +51,18 @@ export const linearIssueRemovedTrigger: TriggerConfig = {
|
|||||||
value: 'linear_issue_removed',
|
value: 'linear_issue_removed',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerInstructions',
|
||||||
|
title: 'Setup Instructions',
|
||||||
|
hideFromPreview: true,
|
||||||
|
type: 'text',
|
||||||
|
defaultValue: linearSetupInstructions('Issue (remove)'),
|
||||||
|
mode: 'trigger',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'linear_issue_removed',
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: buildIssueOutputs(),
|
outputs: buildIssueOutputs(),
|
||||||
|
|||||||
@@ -39,18 +39,6 @@ export const linearIssueUpdatedTrigger: TriggerConfig = {
|
|||||||
value: 'linear_issue_updated',
|
value: 'linear_issue_updated',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerInstructions',
|
|
||||||
title: 'Setup Instructions',
|
|
||||||
hideFromPreview: true,
|
|
||||||
type: 'text',
|
|
||||||
defaultValue: linearSetupInstructions('Issue (update)'),
|
|
||||||
mode: 'trigger',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'linear_issue_updated',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'triggerSave',
|
id: 'triggerSave',
|
||||||
title: '',
|
title: '',
|
||||||
@@ -63,6 +51,18 @@ export const linearIssueUpdatedTrigger: TriggerConfig = {
|
|||||||
value: 'linear_issue_updated',
|
value: 'linear_issue_updated',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerInstructions',
|
||||||
|
title: 'Setup Instructions',
|
||||||
|
hideFromPreview: true,
|
||||||
|
type: 'text',
|
||||||
|
defaultValue: linearSetupInstructions('Issue (update)'),
|
||||||
|
mode: 'trigger',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'linear_issue_updated',
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: buildIssueOutputs(),
|
outputs: buildIssueOutputs(),
|
||||||
|
|||||||
@@ -39,18 +39,6 @@ export const linearLabelCreatedTrigger: TriggerConfig = {
|
|||||||
value: 'linear_label_created',
|
value: 'linear_label_created',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerInstructions',
|
|
||||||
title: 'Setup Instructions',
|
|
||||||
hideFromPreview: true,
|
|
||||||
type: 'text',
|
|
||||||
defaultValue: linearSetupInstructions('IssueLabel (create)'),
|
|
||||||
mode: 'trigger',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'linear_label_created',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'triggerSave',
|
id: 'triggerSave',
|
||||||
title: '',
|
title: '',
|
||||||
@@ -63,6 +51,18 @@ export const linearLabelCreatedTrigger: TriggerConfig = {
|
|||||||
value: 'linear_label_created',
|
value: 'linear_label_created',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerInstructions',
|
||||||
|
title: 'Setup Instructions',
|
||||||
|
hideFromPreview: true,
|
||||||
|
type: 'text',
|
||||||
|
defaultValue: linearSetupInstructions('IssueLabel (create)'),
|
||||||
|
mode: 'trigger',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'linear_label_created',
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: buildLabelOutputs(),
|
outputs: buildLabelOutputs(),
|
||||||
|
|||||||
@@ -39,18 +39,6 @@ export const linearLabelUpdatedTrigger: TriggerConfig = {
|
|||||||
value: 'linear_label_updated',
|
value: 'linear_label_updated',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerInstructions',
|
|
||||||
title: 'Setup Instructions',
|
|
||||||
hideFromPreview: true,
|
|
||||||
type: 'text',
|
|
||||||
defaultValue: linearSetupInstructions('IssueLabel (update)'),
|
|
||||||
mode: 'trigger',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'linear_label_updated',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'triggerSave',
|
id: 'triggerSave',
|
||||||
title: '',
|
title: '',
|
||||||
@@ -63,6 +51,18 @@ export const linearLabelUpdatedTrigger: TriggerConfig = {
|
|||||||
value: 'linear_label_updated',
|
value: 'linear_label_updated',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerInstructions',
|
||||||
|
title: 'Setup Instructions',
|
||||||
|
hideFromPreview: true,
|
||||||
|
type: 'text',
|
||||||
|
defaultValue: linearSetupInstructions('IssueLabel (update)'),
|
||||||
|
mode: 'trigger',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'linear_label_updated',
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: buildLabelOutputs(),
|
outputs: buildLabelOutputs(),
|
||||||
|
|||||||
@@ -39,18 +39,6 @@ export const linearProjectCreatedTrigger: TriggerConfig = {
|
|||||||
value: 'linear_project_created',
|
value: 'linear_project_created',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerInstructions',
|
|
||||||
title: 'Setup Instructions',
|
|
||||||
hideFromPreview: true,
|
|
||||||
type: 'text',
|
|
||||||
defaultValue: linearSetupInstructions('Project (create)'),
|
|
||||||
mode: 'trigger',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'linear_project_created',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'triggerSave',
|
id: 'triggerSave',
|
||||||
title: '',
|
title: '',
|
||||||
@@ -63,6 +51,18 @@ export const linearProjectCreatedTrigger: TriggerConfig = {
|
|||||||
value: 'linear_project_created',
|
value: 'linear_project_created',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerInstructions',
|
||||||
|
title: 'Setup Instructions',
|
||||||
|
hideFromPreview: true,
|
||||||
|
type: 'text',
|
||||||
|
defaultValue: linearSetupInstructions('Project (create)'),
|
||||||
|
mode: 'trigger',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'linear_project_created',
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: buildProjectOutputs(),
|
outputs: buildProjectOutputs(),
|
||||||
|
|||||||
@@ -39,18 +39,6 @@ export const linearProjectUpdateCreatedTrigger: TriggerConfig = {
|
|||||||
value: 'linear_project_update_created',
|
value: 'linear_project_update_created',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerInstructions',
|
|
||||||
title: 'Setup Instructions',
|
|
||||||
hideFromPreview: true,
|
|
||||||
type: 'text',
|
|
||||||
defaultValue: linearSetupInstructions('ProjectUpdate (create)'),
|
|
||||||
mode: 'trigger',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'linear_project_update_created',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'triggerSave',
|
id: 'triggerSave',
|
||||||
title: '',
|
title: '',
|
||||||
@@ -63,6 +51,18 @@ export const linearProjectUpdateCreatedTrigger: TriggerConfig = {
|
|||||||
value: 'linear_project_update_created',
|
value: 'linear_project_update_created',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerInstructions',
|
||||||
|
title: 'Setup Instructions',
|
||||||
|
hideFromPreview: true,
|
||||||
|
type: 'text',
|
||||||
|
defaultValue: linearSetupInstructions('ProjectUpdate (create)'),
|
||||||
|
mode: 'trigger',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'linear_project_update_created',
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: buildProjectUpdateOutputs(),
|
outputs: buildProjectUpdateOutputs(),
|
||||||
|
|||||||
@@ -39,18 +39,6 @@ export const linearProjectUpdatedTrigger: TriggerConfig = {
|
|||||||
value: 'linear_project_updated',
|
value: 'linear_project_updated',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerInstructions',
|
|
||||||
title: 'Setup Instructions',
|
|
||||||
hideFromPreview: true,
|
|
||||||
type: 'text',
|
|
||||||
defaultValue: linearSetupInstructions('Project (update)'),
|
|
||||||
mode: 'trigger',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'linear_project_updated',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: 'triggerSave',
|
id: 'triggerSave',
|
||||||
title: '',
|
title: '',
|
||||||
@@ -63,6 +51,18 @@ export const linearProjectUpdatedTrigger: TriggerConfig = {
|
|||||||
value: 'linear_project_updated',
|
value: 'linear_project_updated',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerInstructions',
|
||||||
|
title: 'Setup Instructions',
|
||||||
|
hideFromPreview: true,
|
||||||
|
type: 'text',
|
||||||
|
defaultValue: linearSetupInstructions('Project (update)'),
|
||||||
|
mode: 'trigger',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'linear_project_updated',
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: buildProjectOutputs(),
|
outputs: buildProjectOutputs(),
|
||||||
|
|||||||
@@ -39,6 +39,18 @@ export const linearWebhookTrigger: TriggerConfig = {
|
|||||||
value: 'linear_webhook',
|
value: 'linear_webhook',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
hideFromPreview: true,
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'linear_webhook',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'linear_webhook',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -54,18 +66,6 @@ export const linearWebhookTrigger: TriggerConfig = {
|
|||||||
value: 'linear_webhook',
|
value: 'linear_webhook',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
hideFromPreview: true,
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'linear_webhook',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'linear_webhook',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: {
|
outputs: {
|
||||||
|
|||||||
@@ -72,6 +72,18 @@ export const microsoftTeamsChatSubscriptionTrigger: TriggerConfig = {
|
|||||||
value: 'microsoftteams_chat_subscription',
|
value: 'microsoftteams_chat_subscription',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
hideFromPreview: true,
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'microsoftteams_chat_subscription',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'microsoftteams_chat_subscription',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -93,18 +105,6 @@ export const microsoftTeamsChatSubscriptionTrigger: TriggerConfig = {
|
|||||||
value: 'microsoftteams_chat_subscription',
|
value: 'microsoftteams_chat_subscription',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
hideFromPreview: true,
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'microsoftteams_chat_subscription',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'microsoftteams_chat_subscription',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: {
|
outputs: {
|
||||||
|
|||||||
@@ -51,6 +51,18 @@ export const microsoftTeamsWebhookTrigger: TriggerConfig = {
|
|||||||
value: 'microsoftteams_webhook',
|
value: 'microsoftteams_webhook',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
hideFromPreview: true,
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'microsoftteams_webhook',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'microsoftteams_webhook',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -76,18 +88,6 @@ export const microsoftTeamsWebhookTrigger: TriggerConfig = {
|
|||||||
value: 'microsoftteams_webhook',
|
value: 'microsoftteams_webhook',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
hideFromPreview: true,
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'microsoftteams_webhook',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'microsoftteams_webhook',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: {
|
outputs: {
|
||||||
|
|||||||
@@ -93,6 +93,14 @@ export const outlookPollingTrigger: TriggerConfig = {
|
|||||||
required: false,
|
required: false,
|
||||||
mode: 'trigger',
|
mode: 'trigger',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
hideFromPreview: true,
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'outlook_poller',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -110,14 +118,6 @@ export const outlookPollingTrigger: TriggerConfig = {
|
|||||||
.join(''),
|
.join(''),
|
||||||
mode: 'trigger',
|
mode: 'trigger',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
hideFromPreview: true,
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'outlook_poller',
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: {
|
outputs: {
|
||||||
|
|||||||
@@ -19,6 +19,14 @@ export const rssPollingTrigger: TriggerConfig = {
|
|||||||
required: true,
|
required: true,
|
||||||
mode: 'trigger',
|
mode: 'trigger',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
hideFromPreview: true,
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'rss_poller',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -36,14 +44,6 @@ export const rssPollingTrigger: TriggerConfig = {
|
|||||||
.join(''),
|
.join(''),
|
||||||
mode: 'trigger',
|
mode: 'trigger',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
hideFromPreview: true,
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'rss_poller',
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: {
|
outputs: {
|
||||||
|
|||||||
@@ -30,6 +30,14 @@ export const slackWebhookTrigger: TriggerConfig = {
|
|||||||
required: true,
|
required: true,
|
||||||
mode: 'trigger',
|
mode: 'trigger',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
hideFromPreview: true,
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'slack_webhook',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -41,7 +49,7 @@ export const slackWebhookTrigger: TriggerConfig = {
|
|||||||
'Go to "OAuth & Permissions" and add bot token scopes:<br><ul class="mt-1 ml-5 list-disc"><li><code>app_mentions:read</code> - For viewing messages that tag your bot with an @</li><li><code>chat:write</code> - To send messages to channels your bot is a part of</li></ul>',
|
'Go to "OAuth & Permissions" and add bot token scopes:<br><ul class="mt-1 ml-5 list-disc"><li><code>app_mentions:read</code> - For viewing messages that tag your bot with an @</li><li><code>chat:write</code> - To send messages to channels your bot is a part of</li></ul>',
|
||||||
'Go to "Event Subscriptions":<br><ul class="mt-1 ml-5 list-disc"><li>Enable events</li><li>Under "Subscribe to Bot Events", add <code>app_mention</code> to listen to messages that mention your bot</li><li>Paste the Webhook URL above into the "Request URL" field</li></ul>',
|
'Go to "Event Subscriptions":<br><ul class="mt-1 ml-5 list-disc"><li>Enable events</li><li>Under "Subscribe to Bot Events", add <code>app_mention</code> to listen to messages that mention your bot</li><li>Paste the Webhook URL above into the "Request URL" field</li></ul>',
|
||||||
'Go to "Install App" in the left sidebar and install the app into your desired Slack workspace and channel.',
|
'Go to "Install App" in the left sidebar and install the app into your desired Slack workspace and channel.',
|
||||||
'Save changes in both Slack and here.',
|
'Save your changes in Slack. Your trigger will configure automatically once you complete the fields above.',
|
||||||
]
|
]
|
||||||
.map(
|
.map(
|
||||||
(instruction, index) =>
|
(instruction, index) =>
|
||||||
@@ -51,14 +59,6 @@ export const slackWebhookTrigger: TriggerConfig = {
|
|||||||
hideFromPreview: true,
|
hideFromPreview: true,
|
||||||
mode: 'trigger',
|
mode: 'trigger',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
hideFromPreview: true,
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'slack_webhook',
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: {
|
outputs: {
|
||||||
|
|||||||
@@ -165,6 +165,14 @@ export const stripeWebhookTrigger: TriggerConfig = {
|
|||||||
password: true,
|
password: true,
|
||||||
mode: 'trigger',
|
mode: 'trigger',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
hideFromPreview: true,
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'stripe_webhook',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -178,7 +186,7 @@ export const stripeWebhookTrigger: TriggerConfig = {
|
|||||||
'Click "Create Destination" to save',
|
'Click "Create Destination" to save',
|
||||||
'After creating the endpoint, click "Reveal" next to "Signing secret" and copy it',
|
'After creating the endpoint, click "Reveal" next to "Signing secret" and copy it',
|
||||||
'Paste the signing secret into the <strong>Webhook Signing Secret</strong> field above',
|
'Paste the signing secret into the <strong>Webhook Signing Secret</strong> field above',
|
||||||
'Click "Save" to activate your webhook trigger',
|
'Your webhook trigger will activate automatically once you complete the configuration above',
|
||||||
]
|
]
|
||||||
.map(
|
.map(
|
||||||
(instruction, index) =>
|
(instruction, index) =>
|
||||||
@@ -187,14 +195,6 @@ export const stripeWebhookTrigger: TriggerConfig = {
|
|||||||
.join(''),
|
.join(''),
|
||||||
mode: 'trigger',
|
mode: 'trigger',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
hideFromPreview: true,
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'stripe_webhook',
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: {
|
outputs: {
|
||||||
|
|||||||
@@ -30,6 +30,14 @@ export const telegramWebhookTrigger: TriggerConfig = {
|
|||||||
required: true,
|
required: true,
|
||||||
mode: 'trigger',
|
mode: 'trigger',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
hideFromPreview: true,
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'telegram_webhook',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -38,7 +46,7 @@ export const telegramWebhookTrigger: TriggerConfig = {
|
|||||||
defaultValue: [
|
defaultValue: [
|
||||||
'Message "/newbot" to <a href="https://t.me/BotFather" target="_blank" rel="noopener noreferrer" class="text-muted-foreground underline transition-colors hover:text-muted-foreground/80">@BotFather</a> in Telegram to create a bot and copy its token.',
|
'Message "/newbot" to <a href="https://t.me/BotFather" target="_blank" rel="noopener noreferrer" class="text-muted-foreground underline transition-colors hover:text-muted-foreground/80">@BotFather</a> in Telegram to create a bot and copy its token.',
|
||||||
'Enter your Bot Token above.',
|
'Enter your Bot Token above.',
|
||||||
'Save settings and any message sent to your bot will trigger the workflow.',
|
'Once configured, any message sent to your bot will trigger the workflow.',
|
||||||
]
|
]
|
||||||
.map(
|
.map(
|
||||||
(instruction, index) =>
|
(instruction, index) =>
|
||||||
@@ -47,14 +55,6 @@ export const telegramWebhookTrigger: TriggerConfig = {
|
|||||||
.join(''),
|
.join(''),
|
||||||
mode: 'trigger',
|
mode: 'trigger',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
hideFromPreview: true,
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'telegram_webhook',
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: {
|
outputs: {
|
||||||
|
|||||||
@@ -49,6 +49,14 @@ export const twilioVoiceWebhookTrigger: TriggerConfig = {
|
|||||||
required: false,
|
required: false,
|
||||||
mode: 'trigger',
|
mode: 'trigger',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
hideFromPreview: true,
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'twilio_voice_webhook',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -69,14 +77,6 @@ export const twilioVoiceWebhookTrigger: TriggerConfig = {
|
|||||||
.join('\n\n'),
|
.join('\n\n'),
|
||||||
mode: 'trigger',
|
mode: 'trigger',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
hideFromPreview: true,
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'twilio_voice_webhook',
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: {
|
outputs: {
|
||||||
|
|||||||
@@ -61,6 +61,14 @@ export const typeformWebhookTrigger: TriggerConfig = {
|
|||||||
defaultValue: false,
|
defaultValue: false,
|
||||||
mode: 'trigger',
|
mode: 'trigger',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
hideFromPreview: true,
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'typeform_webhook',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -71,7 +79,7 @@ export const typeformWebhookTrigger: TriggerConfig = {
|
|||||||
'Find your Form ID in the URL when editing your form (e.g., <code>https://admin.typeform.com/form/ABC123/create</code> → Form ID is <code>ABC123</code>)',
|
'Find your Form ID in the URL when editing your form (e.g., <code>https://admin.typeform.com/form/ABC123/create</code> → Form ID is <code>ABC123</code>)',
|
||||||
'Fill in the form above with your Form ID and Personal Access Token',
|
'Fill in the form above with your Form ID and Personal Access Token',
|
||||||
'Optionally add a Webhook Secret for enhanced security - Sim will verify all incoming webhooks match this secret',
|
'Optionally add a Webhook Secret for enhanced security - Sim will verify all incoming webhooks match this secret',
|
||||||
'Click "Save" below - Sim will automatically register the webhook with Typeform',
|
'Sim will automatically register the webhook with Typeform when you complete the configuration above',
|
||||||
'<strong>Note:</strong> Requires a Typeform PRO or PRO+ account to use webhooks',
|
'<strong>Note:</strong> Requires a Typeform PRO or PRO+ account to use webhooks',
|
||||||
]
|
]
|
||||||
.map(
|
.map(
|
||||||
@@ -81,14 +89,6 @@ export const typeformWebhookTrigger: TriggerConfig = {
|
|||||||
.join(''),
|
.join(''),
|
||||||
mode: 'trigger',
|
mode: 'trigger',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
hideFromPreview: true,
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'typeform_webhook',
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: {
|
outputs: {
|
||||||
|
|||||||
@@ -53,6 +53,18 @@ export const webflowCollectionItemChangedTrigger: TriggerConfig = {
|
|||||||
value: 'webflow_collection_item_changed',
|
value: 'webflow_collection_item_changed',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
hideFromPreview: true,
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'webflow_collection_item_changed',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'webflow_collection_item_changed',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -77,18 +89,6 @@ export const webflowCollectionItemChangedTrigger: TriggerConfig = {
|
|||||||
value: 'webflow_collection_item_changed',
|
value: 'webflow_collection_item_changed',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
hideFromPreview: true,
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'webflow_collection_item_changed',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'webflow_collection_item_changed',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: {
|
outputs: {
|
||||||
|
|||||||
@@ -66,6 +66,18 @@ export const webflowCollectionItemCreatedTrigger: TriggerConfig = {
|
|||||||
value: 'webflow_collection_item_created',
|
value: 'webflow_collection_item_created',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
hideFromPreview: true,
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'webflow_collection_item_created',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'webflow_collection_item_created',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -90,18 +102,6 @@ export const webflowCollectionItemCreatedTrigger: TriggerConfig = {
|
|||||||
value: 'webflow_collection_item_created',
|
value: 'webflow_collection_item_created',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
hideFromPreview: true,
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'webflow_collection_item_created',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'webflow_collection_item_created',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: {
|
outputs: {
|
||||||
|
|||||||
@@ -53,6 +53,18 @@ export const webflowCollectionItemDeletedTrigger: TriggerConfig = {
|
|||||||
value: 'webflow_collection_item_deleted',
|
value: 'webflow_collection_item_deleted',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
hideFromPreview: true,
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'webflow_collection_item_deleted',
|
||||||
|
condition: {
|
||||||
|
field: 'selectedTriggerId',
|
||||||
|
value: 'webflow_collection_item_deleted',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -78,18 +90,6 @@ export const webflowCollectionItemDeletedTrigger: TriggerConfig = {
|
|||||||
value: 'webflow_collection_item_deleted',
|
value: 'webflow_collection_item_deleted',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
hideFromPreview: true,
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'webflow_collection_item_deleted',
|
|
||||||
condition: {
|
|
||||||
field: 'selectedTriggerId',
|
|
||||||
value: 'webflow_collection_item_deleted',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: {
|
outputs: {
|
||||||
|
|||||||
@@ -40,6 +40,14 @@ export const webflowFormSubmissionTrigger: TriggerConfig = {
|
|||||||
required: false,
|
required: false,
|
||||||
mode: 'trigger',
|
mode: 'trigger',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
hideFromPreview: true,
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'webflow_form_submission',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -61,14 +69,6 @@ export const webflowFormSubmissionTrigger: TriggerConfig = {
|
|||||||
.join(''),
|
.join(''),
|
||||||
mode: 'trigger',
|
mode: 'trigger',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
hideFromPreview: true,
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'webflow_form_submission',
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: {
|
outputs: {
|
||||||
|
|||||||
@@ -31,6 +31,14 @@ export const whatsappWebhookTrigger: TriggerConfig = {
|
|||||||
required: true,
|
required: true,
|
||||||
mode: 'trigger',
|
mode: 'trigger',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'triggerSave',
|
||||||
|
title: '',
|
||||||
|
type: 'trigger-save',
|
||||||
|
hideFromPreview: true,
|
||||||
|
mode: 'trigger',
|
||||||
|
triggerId: 'whatsapp_webhook',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'triggerInstructions',
|
id: 'triggerInstructions',
|
||||||
title: 'Setup Instructions',
|
title: 'Setup Instructions',
|
||||||
@@ -53,14 +61,6 @@ export const whatsappWebhookTrigger: TriggerConfig = {
|
|||||||
.join(''),
|
.join(''),
|
||||||
mode: 'trigger',
|
mode: 'trigger',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: 'triggerSave',
|
|
||||||
title: '',
|
|
||||||
type: 'trigger-save',
|
|
||||||
hideFromPreview: true,
|
|
||||||
mode: 'trigger',
|
|
||||||
triggerId: 'whatsapp_webhook',
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
|
|
||||||
outputs: {
|
outputs: {
|
||||||
|
|||||||
Reference in New Issue
Block a user