Skip to content
Merged
22 changes: 17 additions & 5 deletions apps/sim/app/(landing)/integrations/data/integrations.json
Original file line number Diff line number Diff line change
Expand Up @@ -4015,8 +4015,14 @@
}
],
"operationCount": 12,
"triggers": [],
"triggerCount": 0,
"triggers": [
{
"id": "gmail_poller",
"name": "Gmail Email Trigger",
"description": "Triggers when new emails are received in Gmail (requires Gmail credentials)"
}
],
"triggerCount": 1,
"authType": "oauth",
"category": "tools",
"integrationType": "email",
Expand Down Expand Up @@ -7256,7 +7262,7 @@
{
"id": "linear_webhook_v2",
"name": "Linear Webhook",
"description": "Trigger workflow from Linear data-change events included in this webhook subscription (Issues, Comments, Projects, etc.—not every Linear model)."
"description": "Trigger workflow from Linear events you select when creating the webhook in Linear (not guaranteed to be every model or event type)."
}
],
"triggerCount": 15,
Expand Down Expand Up @@ -8580,8 +8586,14 @@
}
],
"operationCount": 9,
"triggers": [],
"triggerCount": 0,
"triggers": [
{
"id": "outlook_poller",
"name": "Outlook Email Trigger",
"description": "Triggers when new emails are received in Outlook (requires Microsoft credentials)"
}
],
"triggerCount": 1,
"authType": "oauth",
"category": "tools",
"integrationType": "email",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client'

import { useCallback, useEffect, useLayoutEffect, useRef } from 'react'
import { useCallback, useLayoutEffect, useRef } from 'react'
import { cn } from '@/lib/core/utils/cn'
import { MessageActions } from '@/app/workspace/[workspaceId]/components'
import { ChatMessageAttachments } from '@/app/workspace/[workspaceId]/home/components/chat-message-attachments'
Expand Down Expand Up @@ -99,41 +99,16 @@ export function MothershipChat({
const hasMessages = messages.length > 0
const initialScrollDoneRef = useRef(false)

const primedQueueIdRef = useRef<string | null>(null)
const primeTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
const messageQueueRef = useRef(messageQueue)
messageQueueRef.current = messageQueue
const onSendQueuedMessageRef = useRef(onSendQueuedMessage)
onSendQueuedMessageRef.current = onSendQueuedMessage

const clearPrimed = useCallback(() => {
primedQueueIdRef.current = null
if (primeTimerRef.current) {
clearTimeout(primeTimerRef.current)
primeTimerRef.current = null
}
}, [])

const handleEnterWhileEmpty = useCallback(() => {
const topMessage = messageQueueRef.current[0]
if (!topMessage) return false

if (primedQueueIdRef.current === topMessage.id) {
clearPrimed()
void onSendQueuedMessageRef.current(topMessage.id)
return true
}

primedQueueIdRef.current = topMessage.id
if (primeTimerRef.current) clearTimeout(primeTimerRef.current)
primeTimerRef.current = setTimeout(clearPrimed, 3000)
void onSendQueuedMessageRef.current(topMessage.id)
return true
}, [clearPrimed])

useEffect(() => {
return () => {
if (primeTimerRef.current) clearTimeout(primeTimerRef.current)
}
}, [])

useLayoutEffect(() => {
Expand Down Expand Up @@ -235,7 +210,6 @@ export function MothershipChat({
editValue={editValue}
onEditValueConsumed={onEditValueConsumed}
onEnterWhileEmpty={handleEnterWhileEmpty}
onPrimedDismiss={clearPrimed}
/>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@ interface UserInputProps {
userId?: string
onContextAdd?: (context: ChatContext) => void
onEnterWhileEmpty?: () => boolean
onPrimedDismiss?: () => void
}

export function UserInput({
Expand All @@ -123,7 +122,6 @@ export function UserInput({
userId,
onContextAdd,
onEnterWhileEmpty,
onPrimedDismiss,
}: UserInputProps) {
const { workspaceId } = useParams<{ workspaceId: string }>()
const { data: workflowsById = {} } = useWorkflowMap(workspaceId)
Expand Down Expand Up @@ -456,7 +454,8 @@ export function UserInput({
(e: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (e.key === 'Enter' && !e.shiftKey && !e.nativeEvent.isComposing) {
e.preventDefault()
if (isSendingRef.current && !valueRef.current.trim() && onEnterWhileEmptyRef.current?.()) {
if (isSendingRef.current && !valueRef.current.trim()) {
onEnterWhileEmptyRef.current?.()
return
}
handleSubmit()
Expand Down Expand Up @@ -551,9 +550,8 @@ export function UserInput({

setValue(newValue)
restartRecognition(newValue)
if (newValue.trim()) onPrimedDismiss?.()
},
[restartRecognition, onPrimedDismiss]
[restartRecognition]
)

const handleSelectAdjust = useCallback(() => {
Expand Down
4 changes: 3 additions & 1 deletion apps/sim/lib/core/idempotency/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,9 @@ export class IdempotencyService {
normalizedHeaders?.['x-teams-notification-id'] ||
normalizedHeaders?.['svix-id'] ||
normalizedHeaders?.['linear-delivery'] ||
normalizedHeaders?.['greenhouse-event-id']
normalizedHeaders?.['greenhouse-event-id'] ||
normalizedHeaders?.['x-zm-request-id'] ||
normalizedHeaders?.['idempotency-key']

if (webhookIdHeader) {
return `${webhookId}:${webhookIdHeader}`
Expand Down
9 changes: 9 additions & 0 deletions apps/sim/lib/webhooks/providers/ashby.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,15 @@ function validateAshbySignature(secretToken: string, signature: string, body: st
}

export const ashbyHandler: WebhookProviderHandler = {
extractIdempotencyId(body: unknown): string | null {
const obj = body as Record<string, unknown>
const webhookActionId = obj.webhookActionId
if (typeof webhookActionId === 'string' && webhookActionId) {
return `ashby:${webhookActionId}`
}
return null
},

async formatInput({ body }: FormatInputContext): Promise<FormatInputResult> {
const b = body as Record<string, unknown>
return {
Expand Down
14 changes: 14 additions & 0 deletions apps/sim/lib/webhooks/providers/gong.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,20 @@ export async function verifyGongJwtAuth(ctx: AuthContext): Promise<NextResponse
export const gongHandler: WebhookProviderHandler = {
verifyAuth: verifyGongJwtAuth,

extractIdempotencyId(body: unknown): string | null {
const obj = body as Record<string, unknown>
const callData = obj.callData as Record<string, unknown> | undefined
const metaData = callData?.metaData as Record<string, unknown> | undefined
const id = metaData?.id
if (typeof id === 'string' && id) {
return `gong:${id}`
}
if (typeof id === 'number') {
return `gong:${id}`
}
return null
},

async formatInput({ body }: FormatInputContext): Promise<FormatInputResult> {
const b = body as Record<string, unknown>
const callData = b.callData as Record<string, unknown> | undefined
Expand Down
9 changes: 9 additions & 0 deletions apps/sim/lib/webhooks/providers/telegram.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@ export const telegramHandler: WebhookProviderHandler = {
return null
},

extractIdempotencyId(body: unknown): string | null {
const obj = body as Record<string, unknown>
const updateId = obj.update_id
if (typeof updateId === 'number') {
return `telegram:${updateId}`
}
return null
},

async formatInput({ body }: FormatInputContext): Promise<FormatInputResult> {
const b = body as Record<string, unknown>
const rawMessage = (b?.message ||
Expand Down
30 changes: 0 additions & 30 deletions apps/sim/lib/webhooks/providers/zoom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,36 +128,6 @@ export const zoomHandler: WebhookProviderHandler = {
return null
},

extractIdempotencyId(body: unknown): string | null {
const obj = body as Record<string, unknown>
const event = obj.event
const ts = obj.event_ts
if (typeof event !== 'string' || ts === undefined || ts === null) {
return null
}
const payload = obj.payload as Record<string, unknown> | undefined
const inner = payload?.object as Record<string, unknown> | undefined
const participant =
inner?.participant &&
typeof inner.participant === 'object' &&
!Array.isArray(inner.participant)
? (inner.participant as Record<string, unknown>)
: null
const participantStable =
(typeof participant?.user_id === 'string' && participant.user_id) ||
(typeof participant?.id === 'string' && participant.id) ||
(typeof participant?.email === 'string' && participant.email) ||
(typeof participant?.join_time === 'string' && participant.join_time) ||
(typeof participant?.leave_time === 'string' && participant.leave_time) ||
''
const stable =
participantStable ||
(typeof inner?.uuid === 'string' && inner.uuid) ||
(inner?.id !== undefined && inner.id !== null ? String(inner.id) : '') ||
''
return `zoom:${event}:${String(ts)}:${stable}`
},

async matchEvent({ webhook: wh, workflow, body, requestId, providerConfig }: EventMatchContext) {
const triggerId = providerConfig.triggerId as string | undefined
const obj = body as Record<string, unknown>
Expand Down
30 changes: 29 additions & 1 deletion apps/sim/triggers/linear/comment_created.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { LinearIcon } from '@/components/icons'
import { buildCommentOutputs, linearSetupInstructions } from '@/triggers/linear/utils'
import {
buildCommentOutputs,
buildLinearV2SubBlocks,
linearSetupInstructions,
} from '@/triggers/linear/utils'
import type { TriggerConfig } from '@/triggers/types'

export const linearCommentCreatedTrigger: TriggerConfig = {
Expand Down Expand Up @@ -78,3 +82,27 @@ export const linearCommentCreatedTrigger: TriggerConfig = {
},
},
}

export const linearCommentCreatedV2Trigger: TriggerConfig = {
id: 'linear_comment_created_v2',
name: 'Linear Comment Created',
provider: 'linear',
description: 'Trigger workflow when a new comment is created in Linear',
version: '2.0.0',
icon: LinearIcon,
subBlocks: buildLinearV2SubBlocks({
triggerId: 'linear_comment_created_v2',
eventType: 'Comment (create)',
}),
outputs: buildCommentOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Linear-Event': 'Comment',
'Linear-Delivery': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'Linear-Signature': 'sha256...',
'User-Agent': 'Linear-Webhook',
},
},
}
30 changes: 0 additions & 30 deletions apps/sim/triggers/linear/comment_created_v2.ts

This file was deleted.

30 changes: 29 additions & 1 deletion apps/sim/triggers/linear/comment_updated.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { LinearIcon } from '@/components/icons'
import { buildCommentOutputs, linearSetupInstructions } from '@/triggers/linear/utils'
import {
buildCommentOutputs,
buildLinearV2SubBlocks,
linearSetupInstructions,
} from '@/triggers/linear/utils'
import type { TriggerConfig } from '@/triggers/types'

export const linearCommentUpdatedTrigger: TriggerConfig = {
Expand Down Expand Up @@ -78,3 +82,27 @@ export const linearCommentUpdatedTrigger: TriggerConfig = {
},
},
}

export const linearCommentUpdatedV2Trigger: TriggerConfig = {
id: 'linear_comment_updated_v2',
name: 'Linear Comment Updated',
provider: 'linear',
description: 'Trigger workflow when a comment is updated in Linear',
version: '2.0.0',
icon: LinearIcon,
subBlocks: buildLinearV2SubBlocks({
triggerId: 'linear_comment_updated_v2',
eventType: 'Comment (update)',
}),
outputs: buildCommentOutputs(),
webhook: {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Linear-Event': 'Comment',
'Linear-Delivery': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'Linear-Signature': 'sha256...',
'User-Agent': 'Linear-Webhook',
},
},
}
30 changes: 0 additions & 30 deletions apps/sim/triggers/linear/comment_updated_v2.ts

This file was deleted.

Loading
Loading