Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions integrations/trello/definitions/actions/card-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,11 @@ export const updateCard = {
'Labels to remove from the card (Optional). This should be a list of label IDs. Leave empty to keep the current labels.'
),
dueDate: cardSchema.shape.dueDate
.nullable()
.optional()
.title('Due Date')
.describe(
'The due date of the card in ISO 8601 format (Optional). Leave empty to keep the current due date.'
'The due date of the card in ISO 8601 format (Optional). Set to null to remove the due date or leave empty to keep the current due date.'
),
listId: listSchema.shape.id
.optional()
Expand All @@ -150,13 +151,13 @@ export const updateCard = {
/** Note: The validation for "verticalPosition" must be done in the action
* implementation, since studio does not support union types in inputs yet
* and the JSON schema generation does not support zod runtime validation
* like "refine" (at the time of writing, 2026-01-13). */
* like "refine" (at the time of writing, 2026-01-22). */
verticalPosition: z
.string()
.optional()
.title('Vertical Position')
.describe(
'The new position of the card in the list, either "top", "bottom", or a float (Optional). Leave empty to keep the current position.'
'The new position of the card in the list, either "top", "bottom", or a stringified float (Optional). Leave empty to keep the current position.'
),
})
.describe('Input schema for creating a new card'),
Expand Down Expand Up @@ -248,6 +249,17 @@ export const moveCardToList = {
newListId: listSchema.shape.id
.title('New List ID')
.describe('Unique identifier of the list in which the card will be moved to'),
/** Note: The validation for "newVerticalPosition" must be done in the action
* implementation, since studio does not support union types in inputs yet
* and the JSON schema generation does not support zod runtime validation
* like "refine" (at the time of writing, 2026-01-22). */
newVerticalPosition: z
.string()
.optional()
.title('New Vertical Position')
.describe(
'The new position of the card in the list, either "top", "bottom", or a stringified float (Optional). Leave empty to keep the current position.'
),
}),
},
output: {
Expand Down
10 changes: 9 additions & 1 deletion integrations/trello/definitions/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const configuration = {
trelloApiKey: z
.string()
.title('Trello API Key')
.describe('Can be obtained by creating an application on Trello')
.describe("Can be found in the app's settings within the Trello apps admin page")
.secret(),
trelloApiToken: z
.string()
Expand All @@ -21,5 +21,13 @@ export const configuration = {
.optional()
.title('Trello Board ID')
.describe('Unique identifier of the board to watch for events on Trello'),
trelloApiSecret: z
.string()
.secret()
.optional()
.title('Trello API Secret')
.describe(
"Can be found in the app's settings within the Trello apps admin page. (Only used if the Trello Board ID is provided)"
),
}),
} as const satisfies NonNullable<IntegrationDefinitionProps['configuration']>
1 change: 0 additions & 1 deletion integrations/trello/definitions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,5 @@ export { actions } from './actions'
export { channels } from './channels'
export { configuration } from './configuration'
export { events } from './events'
export { states } from './states'
export { user } from './user'
export { entities } from './entities'
16 changes: 0 additions & 16 deletions integrations/trello/definitions/states.ts

This file was deleted.

24 changes: 21 additions & 3 deletions integrations/trello/integration.definition.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { posthogHelper } from '@botpress/common'
import * as sdk from '@botpress/sdk'
import { trelloIdSchema } from 'definitions/schemas'

import { events, states, actions, channels, user, configuration, entities } from './definitions'
import { events, actions, channels, user, configuration, entities } from './definitions'

export const INTEGRATION_NAME = 'trello'
export const INTEGRATION_VERSION = '2.0.0'
export const INTEGRATION_VERSION = '2.1.0'

export default new sdk.IntegrationDefinition({
name: INTEGRATION_NAME,
Expand All @@ -17,10 +18,27 @@ export default new sdk.IntegrationDefinition({
channels,
user,
configuration,
states,
events,
entities,
secrets: {
...posthogHelper.COMMON_SECRET_NAMES,
},
/** The states are no longer being used, however, it is
* being left in, in order to prevent potential breaking changes.
*
* It should be removed next time we push a major release.
* @see https://github.com/botpress/botpress/pull/14849#pullrequestreview-3728680072 For more details. */
states: {
// TODO: Remove in next major release (v3.0.0)
webhook: {
type: 'integration',
schema: sdk.z.object({
trelloWebhookId: trelloIdSchema
.nullable()
.default(null)
.title('Trello Webhook ID')
.describe('Unique id of the webhook that is created by Trello upon integration registration'),
}),
},
},
})
18 changes: 15 additions & 3 deletions integrations/trello/src/actions/card-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ export const updateCard: bp.Integration['actions']['updateCard'] = async (props)
verticalPosition,
} = props.input

// When sending null for the due date, the Trello API ignores it. However, an empty string removes the due date.
// A blank string from a Botpress bot should be treated as undefined (no change), while null is converted to an
// empty string to should remove the due date.
let formattedDueDate = dueDate?.trim() !== '' ? dueDate : undefined
formattedDueDate = formattedDueDate !== null ? formattedDueDate : ''

const card = await trelloClient.getCardById({ cardId })
await trelloClient.updateCard({
partialCard: {
Expand All @@ -94,7 +100,7 @@ export const updateCard: bp.Integration['actions']['updateCard'] = async (props)
description: cardBody,
isClosed: lifecycleStatus ? lifecycleStatus === 'Archived' : undefined,
isCompleted: completionStatus ? completionStatus === 'Complete' : undefined,
dueDate,
dueDate: formattedDueDate,
labelIds: card.labelIds.concat(labelIdsToAdd ?? []).filter((labelId) => !labelIdsToRemove?.includes(labelId)),
memberIds: card.memberIds
.concat(memberIdsToAdd ?? [])
Expand Down Expand Up @@ -130,11 +136,17 @@ export const moveCardToList: bp.Integration['actions']['moveCardToList'] = async
printActionTriggeredMsg(props)
const { trelloClient } = getTools(props)

const { cardId, newListId } = props.input
const { cardId, newListId, newVerticalPosition } = props.input
const card = await trelloClient.getCardById({ cardId })
const newList = await trelloClient.getListById({ listId: newListId })

await trelloClient.updateCard({ partialCard: { id: card.id, listId: newList.id } })
await trelloClient.updateCard({
partialCard: {
id: card.id,
listId: newList.id,
verticalPosition: _validateVerticalPosition(newVerticalPosition),
},
})

return { message: 'Card successfully moved to the new list' }
}
Expand Down
11 changes: 0 additions & 11 deletions integrations/trello/src/tsconfig.json

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { TrelloEventType } from 'definitions/events'
import { CardAttachmentAddedWebhook, CardAttachmentRemovedWebhook } from '../schemas/card-attachment-webhook-schemas'
import { extractCommonEventData, extractIdAndName } from './helpers'
import { Expect, IsWebhookHandler } from './types'
import * as bp from '.botpress'

export const handleAttachmentAddedEvent = async (
Expand All @@ -19,6 +20,7 @@ export const handleAttachmentAddedEvent = async (
},
})
}
type _HandleAttachmentAddedEventTest = Expect<IsWebhookHandler<typeof handleAttachmentAddedEvent>>

export const handleAttachmentRemovedEvent = async (
props: bp.HandlerProps,
Expand All @@ -35,3 +37,4 @@ export const handleAttachmentRemovedEvent = async (
},
})
}
type _HandleAttachmentRemovedEventTest = Expect<IsWebhookHandler<typeof handleAttachmentRemovedEvent>>
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
CommentUpdatedWebhook,
} from '../schemas/card-comment-webhook-schemas'
import { extractCommonEventData, extractIdAndName } from './helpers'
import { Expect, IsWebhookHandler } from './types'
import * as bp from '.botpress'

export const handleCommentAddedEvent = async (
Expand All @@ -32,6 +33,7 @@ export const handleCommentAddedEvent = async (

return result[1].status === 'fulfilled' ? result[1].value : null
}
type _HandleCommentAddedEventTest = Expect<IsWebhookHandler<typeof handleCommentAddedEvent>>

export const handleCommentUpdatedEvent = async (
props: bp.HandlerProps,
Expand All @@ -54,6 +56,7 @@ export const handleCommentUpdatedEvent = async (
},
})
}
type _HandleCommentUpdatedEventTest = Expect<IsWebhookHandler<typeof handleCommentUpdatedEvent>>

export const handleCommentDeletedEvent = async (
props: bp.HandlerProps,
Expand All @@ -72,3 +75,4 @@ export const handleCommentDeletedEvent = async (
},
})
}
type _HandleCommentDeletedEventTest = Expect<IsWebhookHandler<typeof handleCommentDeletedEvent>>
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
CardVotesUpdatedWebhook,
} from '../schemas/card-webhook-schemas'
import { extractCommonEventData, extractIdAndName, extractIdAndNameIfExists } from './helpers'
import { Expect, IsWebhookHandler } from './types'
import * as bp from '.botpress'

export const handleCardCreatedEvent = async (
Expand All @@ -23,6 +24,7 @@ export const handleCardCreatedEvent = async (
},
})
}
type _HandleCardCreatedEventTest = Expect<IsWebhookHandler<typeof handleCardCreatedEvent>>

export const handleCardUpdatedEvent = async (
props: bp.HandlerProps,
Expand All @@ -42,6 +44,7 @@ export const handleCardUpdatedEvent = async (
},
})
}
type _HandleCardUpdatedEventTest = Expect<IsWebhookHandler<typeof handleCardUpdatedEvent>>

export const handleCardDeletedEvent = async (
props: bp.HandlerProps,
Expand All @@ -60,6 +63,7 @@ export const handleCardDeletedEvent = async (
},
})
}
type _HandleCardDeletedEventTest = Expect<IsWebhookHandler<typeof handleCardDeletedEvent>>

export const handleCardVotesUpdatedEvent = async (
props: bp.HandlerProps,
Expand All @@ -76,3 +80,4 @@ export const handleCardVotesUpdatedEvent = async (
},
})
}
type _HandleCardVotesUpdatedEventTest = Expect<IsWebhookHandler<typeof handleCardVotesUpdatedEvent>>
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { TrelloEventType } from 'definitions/events'
import { CardLabelAddedWebhook, CardLabelRemovedWebhook } from '../schemas/card-label-webhook-schemas'
import { extractCommonEventData, extractIdAndName } from './helpers'
import { Expect, IsWebhookHandler } from './types'
import * as bp from '.botpress'

const _handleLabelChangedEvent = async (
Expand All @@ -26,6 +27,7 @@ export const handleLabelAddedToCardEvent = async (
) => {
return await _handleLabelChangedEvent(props, eventType, webhookEvent)
}
type _HandleLabelAddedToCardEventTest = Expect<IsWebhookHandler<typeof handleLabelAddedToCardEvent>>

export const handleLabelRemovedFromCardEvent = async (
props: bp.HandlerProps,
Expand All @@ -34,3 +36,4 @@ export const handleLabelRemovedFromCardEvent = async (
) => {
return await _handleLabelChangedEvent(props, eventType, webhookEvent)
}
type _HandleLabelRemovedFromCardEventTest = Expect<IsWebhookHandler<typeof handleLabelRemovedFromCardEvent>>
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
ChecklistItemUpdatedWebhook,
} from '../schemas/checklist-webhook-schemas'
import { extractCommonEventData, extractIdAndName } from './helpers'
import { Expect, IsWebhookHandler } from './types'
import * as bp from '.botpress'

const _extractCommonChecklistItemPayload = (
Expand Down Expand Up @@ -39,6 +40,7 @@ export const handleChecklistAddedToCardEvent = async (
},
})
}
type _HandleChecklistAddedToCardEventTest = Expect<IsWebhookHandler<typeof handleChecklistAddedToCardEvent>>

export const handleChecklistItemCreatedEvent = async (
props: bp.HandlerProps,
Expand All @@ -50,6 +52,7 @@ export const handleChecklistItemCreatedEvent = async (
payload: _extractCommonChecklistItemPayload(webhookEvent),
})
}
type _HandleChecklistItemCreatedEventTest = Expect<IsWebhookHandler<typeof handleChecklistItemCreatedEvent>>

const _mapOldChecklistItemData = (oldData: ChecklistItemUpdatedWebhook['data']['old']) => {
const { name, state, textData, dueReminder, due } = oldData
Expand Down Expand Up @@ -86,6 +89,7 @@ export const handleChecklistItemUpdatedEvent = async (
},
})
}
type _HandleChecklistItemUpdatedEventTest = Expect<IsWebhookHandler<typeof handleChecklistItemUpdatedEvent>>

export const handleChecklistItemDeletedEvent = async (
props: bp.HandlerProps,
Expand All @@ -97,6 +101,7 @@ export const handleChecklistItemDeletedEvent = async (
payload: _extractCommonChecklistItemPayload(webhookEvent),
})
}
type _HandleChecklistItemDeletedEventTest = Expect<IsWebhookHandler<typeof handleChecklistItemDeletedEvent>>

export const handleChecklistItemStatusUpdatedEvent = async (
props: bp.HandlerProps,
Expand All @@ -108,3 +113,4 @@ export const handleChecklistItemStatusUpdatedEvent = async (
payload: _extractCommonChecklistItemPayload(webhookEvent),
})
}
type _HandleChecklistItemStatusUpdatedEventTest = Expect<IsWebhookHandler<typeof handleChecklistItemStatusUpdatedEvent>>
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { TrelloEventType } from 'definitions/events'
import { MemberAddedToCardWebhook, MemberRemovedFromCardWebhook } from '../schemas/member-webhook-schemas'
import { extractCommonEventData, extractIdAndName } from './helpers'
import { Expect, IsWebhookHandler } from './types'
import * as bp from '.botpress'

export const handleMemberAddedToCardEvent = async (
Expand All @@ -18,6 +19,7 @@ export const handleMemberAddedToCardEvent = async (
},
})
}
type _HandleMemberAddedToCardEventTest = Expect<IsWebhookHandler<typeof handleMemberAddedToCardEvent>>

export const handleMemberRemovedFromCardEvent = async (
props: bp.HandlerProps,
Expand All @@ -37,3 +39,4 @@ export const handleMemberRemovedFromCardEvent = async (
},
})
}
type _HandleMemberRemovedFromCardEventTest = Expect<IsWebhookHandler<typeof handleMemberRemovedFromCardEvent>>
18 changes: 18 additions & 0 deletions integrations/trello/src/webhook-events/event-handlers/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { TrelloWebhook } from '../schemas/common'
import * as bp from '.botpress'

/** Used to enforce the signature of a webhook event handler */
type WebhookEventHandler = (
props: bp.HandlerProps,
eventType: keyof typeof bp.events,
eventPayload: Required<TrelloWebhook>
) => Promise<Awaited<ReturnType<bp.Client['createEvent']>> | null>

// Type testing utils
export type IsWebhookHandler<Handler extends (...args: any) => any> =
Parameters<Handler> extends Parameters<WebhookEventHandler>
? ReturnType<Handler> extends ReturnType<WebhookEventHandler>
? true
: false
: false
export type Expect<_T extends true> = void
Loading
Loading