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
2 changes: 1 addition & 1 deletion integrations/slack/integration.definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export default new IntegrationDefinition({
name: 'slack',
title: 'Slack',
description: 'Automate interactions with your team.',
version: '3.1.3',
version: '3.2.0',
icon: 'icon.svg',
readme: 'hub.md',
configuration,
Expand Down
5 changes: 4 additions & 1 deletion integrations/slack/src/channels.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { RuntimeError } from '@botpress/client'
import { ChatPostMessageArguments } from '@slack/web-api'
import { textSchema } from '../definitions/channels/text-input-schema'
import { transformMarkdownForSlack } from './misc/markdown-to-slack'
import { replaceMentions } from './misc/replace-mentions'
import { isValidUrl } from './misc/utils'
import { SlackClient } from './slack-api'
Expand All @@ -10,7 +11,9 @@ import * as bp from '.botpress'
const defaultMessages = {
text: async ({ client, payload, ctx, conversation, ack, logger }) => {
const parsed = textSchema.parse(payload)
parsed.text = replaceMentions(parsed.text, parsed.mentions)
let transformedText = replaceMentions(parsed.text, parsed.mentions)
transformedText = transformMarkdownForSlack(transformedText)
parsed.text = transformedText
logger.forBot().debug('Sending text message to Slack chat:', payload)
await _sendSlackMessage(
{ ack, ctx, client, logger },
Expand Down
56 changes: 56 additions & 0 deletions integrations/slack/src/misc/markdown-to-slack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { transformMarkdown, MarkdownHandlers, stripAllHandlers } from '@botpress/common'

/** 'En space' yields better results for indentation */
const FIXED_SIZE_SPACE_CHAR = '\u2002'

/**
* Slack mrkdwn format handlers
* @see https://docs.slack.dev/messaging/formatting-message-text/
*/
const slackHandlers: MarkdownHandlers = {
...stripAllHandlers,
emphasis: (node, visit) => `_${visit(node)}_`,
delete: (node, visit) => `~${visit(node)}~`,
strong: (node, visit) => `*${visit(node)}*`,
break: () => '\n',
blockquote: (node, visit) => {
const content = visit(node).trim()
return (
content
.split('\n')
.map((line) => `>${line}`)
.join('\n') + '\n'
)
},
inlineCode: (node) => `\`${node.value}\``,
code: (node) => `\`\`\`\n${node.value}\n\`\`\`\n`,
list: (node, visit) => {
return `${node.listLevel !== 1 ? '\n' : ''}${visit(node)}`
},
listItem: (node, visit) => {
const { itemCount, checked, ownerList } = node
let prefix = FIXED_SIZE_SPACE_CHAR.repeat((ownerList.listLevel - 1) * 2)

if (checked !== null) {
prefix += checked ? '☑︎ ' : '☐ '
} else {
prefix += ownerList.ordered === true ? `${itemCount}. ` : '- '
}

const shouldBreak = ownerList.listLevel === 1 || itemCount < ownerList.children.length
return `${prefix}${visit(node)}${shouldBreak ? '\n' : ''}`
},
link: (node, visit) => {
const text = visit(node)
return text ? `<${node.url}|${text}>` : `<${node.url}>`
},
paragraph: (node, visit) => `${visit(node)}\n`,
}

export function transformMarkdownForSlack(text: string | undefined): string | undefined {
if (!text) {
return text
}

return transformMarkdown(text, slackHandlers)
}
2 changes: 1 addition & 1 deletion integrations/slack/src/misc/replace-mentions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export type Mention = {
}

export const replaceMentions = (text: string | undefined, mentions: Mention[] | undefined): string | undefined => {
if (!text || !mentions) {
if (!mentions || !text) {
return text
}

Expand Down
2 changes: 1 addition & 1 deletion integrations/zendesk/integration.definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { actions, events, configuration, channels, states, user } from './src/de
export default new sdk.IntegrationDefinition({
name: 'zendesk',
title: 'Zendesk',
version: '3.0.4',
version: '3.0.5',
icon: 'icon.svg',
description:
'Optimize your support workflow. Trigger workflows from ticket updates as well as manage tickets, access conversations, and engage with customers.',
Expand Down
11 changes: 5 additions & 6 deletions integrations/zendesk/src/actions/call-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@ import { AxiosRequestConfig } from 'axios'
import { getZendeskClient } from '../client'
import * as bp from '.botpress'

export const callApi: bp.IntegrationProps['actions']['callApi'] = async ({
ctx,
client,
input,
}): Promise<bp.actions.callApi.output.Output> => {
export const callApi: bp.IntegrationProps['actions']['callApi'] = async (
props
): Promise<bp.actions.callApi.output.Output> => {
const { client, ctx, input, logger } = props
const { method, path, headers, params, requestBody } = input
const zendeskClient = await getZendeskClient(client, ctx)
const zendeskClient = await getZendeskClient(client, ctx, logger)

try {
const requestConfig: AxiosRequestConfig = {
Expand Down
5 changes: 3 additions & 2 deletions integrations/zendesk/src/actions/close-ticket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { transformTicket } from 'src/definitions/schemas'
import { getZendeskClient } from '../client'
import * as bp from '.botpress'

export const closeTicket: bp.IntegrationProps['actions']['closeTicket'] = async ({ client: bpClient, ctx, input }) => {
const zendeskClient = await getZendeskClient(bpClient, ctx)
export const closeTicket: bp.IntegrationProps['actions']['closeTicket'] = async (props) => {
const { client: bpClient, ctx, input, logger } = props
const zendeskClient = await getZendeskClient(bpClient, ctx, logger)
const originalTicket = await zendeskClient.getTicket(input.ticketId)

const { ticket } = await zendeskClient.updateTicket(input.ticketId, {
Expand Down
9 changes: 3 additions & 6 deletions integrations/zendesk/src/actions/create-ticket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,9 @@ import { transformTicket } from 'src/definitions/schemas'
import { getZendeskClient } from '../client'
import * as bp from '.botpress'

export const createTicket: bp.IntegrationProps['actions']['createTicket'] = async ({
client: bpClient,
ctx,
input,
}) => {
const zendeskClient = await getZendeskClient(bpClient, ctx)
export const createTicket: bp.IntegrationProps['actions']['createTicket'] = async (props) => {
const { client: bpClient, ctx, input, logger } = props
const zendeskClient = await getZendeskClient(bpClient, ctx, logger)
const ticket = await zendeskClient.createTicket(input.subject, input.comment, {
name: input.requesterName,
email: input.requesterEmail,
Expand Down
10 changes: 3 additions & 7 deletions integrations/zendesk/src/actions/create-user.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import { getZendeskClient } from '../client'
import * as bp from '.botpress'

export const createUser: bp.IntegrationProps['actions']['createUser'] = async ({
ctx,
client: bpClient,
input,
logger,
}) => {
const zendeskClient = await getZendeskClient(bpClient, ctx)
export const createUser: bp.IntegrationProps['actions']['createUser'] = async (props) => {
const { client: bpClient, ctx, input, logger } = props
const zendeskClient = await getZendeskClient(bpClient, ctx, logger)

const { name, email, pictureUrl } = input

Expand Down
9 changes: 3 additions & 6 deletions integrations/zendesk/src/actions/find-customer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,9 @@ import { transformUser } from 'src/definitions/schemas'
import { getZendeskClient } from '../client'
import * as bp from '.botpress'

export const findCustomer: bp.IntegrationProps['actions']['findCustomer'] = async ({
client: bpClient,
ctx,
input,
}) => {
const zendeskClient = await getZendeskClient(bpClient, ctx)
export const findCustomer: bp.IntegrationProps['actions']['findCustomer'] = async (props) => {
const { client: bpClient, ctx, input, logger } = props
const zendeskClient = await getZendeskClient(bpClient, ctx, logger)
const customers = await zendeskClient.findCustomers(input.query)
return { customers: customers.map(transformUser) }
}
5 changes: 3 additions & 2 deletions integrations/zendesk/src/actions/get-ticket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { transformTicket } from 'src/definitions/schemas'
import { getZendeskClient } from '../client'
import * as bp from '.botpress'

export const getTicket: bp.IntegrationProps['actions']['getTicket'] = async ({ client: bpClient, ctx, input }) => {
const zendeskClient = await getZendeskClient(bpClient, ctx)
export const getTicket: bp.IntegrationProps['actions']['getTicket'] = async (props) => {
const { client: bpClient, ctx, input, logger } = props
const zendeskClient = await getZendeskClient(bpClient, ctx, logger)
const ticket = await zendeskClient.getTicket(input.ticketId)
return { ticket: transformTicket(ticket) }
}
9 changes: 5 additions & 4 deletions integrations/zendesk/src/actions/hitl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { getZendeskClient, type ZendeskClient } from '../client'
import * as bp from '.botpress'

export const startHitl: bp.IntegrationProps['actions']['startHitl'] = async (props) => {
const { ctx, input, client: bpClient } = props
const { ctx, input, client: bpClient, logger } = props

const downstreamBotpressUser = await bpClient.getUser({ id: ctx.botUserId })
const chatbotName = input.hitlSession?.chatbotName ?? downstreamBotpressUser.user.name ?? 'Botpress'
Expand All @@ -23,7 +23,7 @@ export const startHitl: bp.IntegrationProps['actions']['startHitl'] = async (pro
throw new sdk.RuntimeError(`User ${user.id} not linked in Zendesk`)
}

const zendeskClient = await getZendeskClient(bpClient, ctx)
const zendeskClient = await getZendeskClient(bpClient, ctx, logger)
await _updateZendeskBotpressUser(props, {
zendeskClient,
chatbotName,
Expand Down Expand Up @@ -94,7 +94,8 @@ const _buildTicketBody = async (
return description + (messageHistory.length ? `\n\n---\n\n${messageHistory}` : '')
}

export const stopHitl: bp.IntegrationProps['actions']['stopHitl'] = async ({ ctx, input, client: bpClient }) => {
export const stopHitl: bp.IntegrationProps['actions']['stopHitl'] = async (props) => {
const { client: bpClient, ctx, input, logger } = props
const { conversation } = await bpClient.getConversation({
id: input.conversationId,
})
Expand All @@ -104,7 +105,7 @@ export const stopHitl: bp.IntegrationProps['actions']['stopHitl'] = async ({ ctx
return {}
}

const zendeskClient = await getZendeskClient(bpClient, ctx)
const zendeskClient = await getZendeskClient(bpClient, ctx, logger)

try {
await zendeskClient.updateTicket(ticketId, {
Expand Down
5 changes: 3 additions & 2 deletions integrations/zendesk/src/actions/list-agents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { transformUser } from 'src/definitions/schemas'
import { getZendeskClient } from '../client'
import * as bp from '.botpress'

export const listAgents: bp.IntegrationProps['actions']['listAgents'] = async ({ client: bpClient, ctx, input }) => {
const zendeskClient = await getZendeskClient(bpClient, ctx)
export const listAgents: bp.IntegrationProps['actions']['listAgents'] = async (props) => {
const { client: bpClient, ctx, input, logger } = props
const zendeskClient = await getZendeskClient(bpClient, ctx, logger)
const agents = await zendeskClient.getAgents(input.isOnline)

return {
Expand Down
3 changes: 2 additions & 1 deletion integrations/zendesk/src/actions/sync-kb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import { uploadArticlesToKb } from 'src/misc/upload-articles-to-kb'
import { deleteKbArticles } from 'src/misc/utils'
import * as bp from '.botpress'

export const syncKb: bp.IntegrationProps['actions']['syncKb'] = async ({ ctx, input, client, logger }) => {
export const syncKb: bp.IntegrationProps['actions']['syncKb'] = async (props) => {
try {
const { client, ctx, input, logger } = props
const kbId = input.knowledgeBaseId

await deleteKbArticles(kbId, client)
Expand Down
2 changes: 1 addition & 1 deletion integrations/zendesk/src/channels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const wrapChannel = bpCommon.createChannelWrapper<bp.IntegrationProps>()({
ticketId: ({ conversation, logger }) => Tags.of(conversation, logger).get('id'),
zendeskAuthorId: async ({ client, logger, payload, user }) =>
Tags.of((await client.getUser({ id: payload.userId ?? user.id })).user, logger).get('id'),
zendeskClient: async ({ client, ctx }) => await getZendeskClient(client, ctx),
zendeskClient: async ({ client, ctx, logger }) => await getZendeskClient(client, ctx, logger),
},
})

Expand Down
Loading
Loading