diff --git a/apps/docs/examples/github.mdx b/apps/docs/examples/github.mdx index d7febe79c..26d7d0389 100644 --- a/apps/docs/examples/github.mdx +++ b/apps/docs/examples/github.mdx @@ -4,16 +4,16 @@ sidebarTitle: "GitHub" description: "Here are some example workflows you could create using the GitHub integration." --- - - You can explore all the supported GitHub functions [here](/integrations/apis/github/events/push). ### Example workflows: + ## When a GitHub repo is starred, post information about the user to Slack Integrations required: GitHub, Slack Packages required: + @@ -25,7 +25,7 @@ npm install @trigger.dev/github @trigger.dev/slack ```bash -pnpm install @trigger.dev/github @trigger.dev/slack +pnpm add @trigger.dev/github @trigger.dev/slack ``` @@ -61,12 +61,12 @@ new Trigger({ }).listen(); ``` - ## When a GitHub issue is created or modified, post to Slack Integrations required: GitHub, Slack Packages required: + @@ -78,7 +78,7 @@ npm install @trigger.dev/github @trigger.dev/slack ```bash -pnpm install @trigger.dev/github @trigger.dev/slack +pnpm add @trigger.dev/github @trigger.dev/slack ``` diff --git a/apps/docs/examples/resend.mdx b/apps/docs/examples/resend.mdx index 14f97dbc9..4ad4d8117 100644 --- a/apps/docs/examples/resend.mdx +++ b/apps/docs/examples/resend.mdx @@ -5,10 +5,12 @@ description: "Here are some example workflows you could create using the Resend --- -Resend.com is currently in private beta but you can request early access [here](https://resend.com/). + Resend.com is currently in private beta but you can request early access + [here](https://resend.com/). ### Example workflows: + ## Welcome email drip campaign This workflow will get triggered and a Slack notification and welcome email will be sent straight away. @@ -17,6 +19,7 @@ This workflow will get triggered and a Slack notification and welcome email will Integrations required: Resend, Slack Packages required: + @@ -28,7 +31,7 @@ npm install @trigger.dev/resend @trigger.dev/slack ```bash -pnpm install @trigger.dev/resend @trigger.dev/slack +pnpm add @trigger.dev/resend @trigger.dev/slack ``` @@ -116,4 +119,4 @@ new Trigger({ frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen -> \ No newline at end of file +> diff --git a/apps/docs/examples/shopify.mdx b/apps/docs/examples/shopify.mdx index 4c66154fa..4d43e2a5c 100644 --- a/apps/docs/examples/shopify.mdx +++ b/apps/docs/examples/shopify.mdx @@ -11,6 +11,7 @@ description: "Here are some example workflows you could create using the Shopify Integrations required: Shopify Packages required: + @@ -22,7 +23,7 @@ npm install @trigger.dev/shopify ```bash -pnpm install @trigger.dev/shopify +pnpm add @trigger.dev/shopify ``` diff --git a/apps/docs/examples/slack.mdx b/apps/docs/examples/slack.mdx index 17285f673..f4f8865f9 100644 --- a/apps/docs/examples/slack.mdx +++ b/apps/docs/examples/slack.mdx @@ -4,13 +4,14 @@ sidebarTitle: "Slack" description: "Here are some example workflows you could create using the Slack integration." --- - ### Example workflows: + ## Post to Slack when a GitHub issue is created or modified Integrations required: Slack, GitHub Packages required: + @@ -22,7 +23,7 @@ npm install @trigger.dev/slack @trigger.dev/github ```bash -pnpm install @trigger.dev/slack @trigger.dev/github +pnpm add @trigger.dev/slack @trigger.dev/github ``` @@ -37,7 +38,6 @@ yarn add @trigger.dev/slack @trigger.dev/github Workflow code: - ```ts import { Trigger, customEvent } from "@trigger.dev/sdk"; import * as slack from "@trigger.dev/slack"; diff --git a/apps/docs/examples/whatsapp.mdx b/apps/docs/examples/whatsapp.mdx index 33c7faefc..e279bc96e 100644 --- a/apps/docs/examples/whatsapp.mdx +++ b/apps/docs/examples/whatsapp.mdx @@ -13,6 +13,7 @@ For more information about the WhatsApp integration, check out the [integration Integrations required: WhatsApp Packages required: + @@ -24,7 +25,7 @@ npm install @trigger.dev/whatsapp ```bash -pnpm install @trigger.dev/whatsapp +pnpm add @trigger.dev/whatsapp ``` diff --git a/apps/docs/getting-started.mdx b/apps/docs/getting-started.mdx index 80f6d1b57..c1622298f 100644 --- a/apps/docs/getting-started.mdx +++ b/apps/docs/getting-started.mdx @@ -29,7 +29,7 @@ npm install @trigger.dev/sdk @trigger.dev/slack zod ```bash -pnpm install @trigger.dev/sdk @trigger.dev/slack zod +pnpm add @trigger.dev/sdk @trigger.dev/slack zod ``` diff --git a/apps/docs/integrations/apis/slack/events/block-action-interaction.mdx b/apps/docs/integrations/apis/slack/events/block-action-interaction.mdx index e845f28e4..3b59a7d26 100644 --- a/apps/docs/integrations/apis/slack/events/block-action-interaction.mdx +++ b/apps/docs/integrations/apis/slack/events/block-action-interaction.mdx @@ -106,6 +106,298 @@ new Trigger({ +## Passing custom data + +There are three ways to pass custom data to the workflow that is triggered by the event: + +1. Use the `value` field of the BlockKit component. This is the easiest way to pass data, but it is limited to 2000 characters. +2. Use the `metadata` option when sending the message. This is best for handling "context" data that relates to any possible action taken in a BlockKit message. + +An example of using the `value` field: + + + +```ts postMessage.ts +await slack.postMessage("New Issue", { + channelName: "github-issues", + //text appears in Slack notifications on mobile/desktop + text: "There is a new GitHub issue in the repo", + blocks: [ + { + type: "actions", + block_id: "new.issue", // this is the block_id that we'll use to identify the message + elements: [ + { + type: "button", + action_id: "reply", + text: { + type: "plain_text", + text: "Reply to Issue", + }, + value: githubIssueId, + }, + { + type: "button", + action_id: "close", + text: { + type: "plain_text", + text: "Close Issue", + }, + value: githubIssueId, + }, + ], + }, + ], +}); +``` + +```ts trigger.ts +new Trigger({ + id: "github-issue-slack-interaction", + name: "GitHub Issue Slack Interaction", + on: slack.events.blockActionInteraction({ + blockId: "new.issue", + }), + run: async (event, ctx) => { + const action = event.actions[0]; + + if (action.action_id === "reply") { + // action.value is the githubIssueId + } else if (action.action_id === "close") { + // action.value is the githubIssueId + } + }, +}).listen(); +``` + + + +And an example using the `metadata` option (which can be any JSON-serializable data): + + + +```ts postMessage.ts +await slack.postMessage("New Issue", { + channelName: "github-issues", + //text appears in Slack notifications on mobile/desktop + text: "There is a new GitHub issue in the repo", + metadata: { githubIssueId }, + blocks: [ + { + type: "actions", + block_id: "new.issue", // this is the block_id that we'll use to identify the message + elements: [ + { + type: "button", + action_id: "reply", + text: { + type: "plain_text", + text: "Reply to Issue", + }, + value: "reply", + }, + { + type: "button", + action_id: "close", + text: { + type: "plain_text", + text: "Close Issue", + }, + value: "close", + }, + ], + }, + ], +}); +``` + +```ts trigger.ts +new Trigger({ + id: "github-issue-slack-interaction", + name: "GitHub Issue Slack Interaction", + on: slack.events.blockActionInteraction({ + blockId: "new.issue", + }), + run: async (event, ctx) => { + const action = event.actions[0]; + + if (action.action_id === "reply") { + // event.message.metadata.event_payload.githubIssueId is the githubIssueId + } else if (action.action_id === "close") { + // event.message.metadata.event_payload.githubIssueId is the githubIssueId + } + }, +}).listen(); +``` + + + +## JSX Slack + +You can use the [JSX Slack](https://github.com/yhatt/jsx-slack/) project to build your BlockKit messages and trigger the `blockActionInteraction` event. + +### Step 1: Install and configure JSX Slack + + + + +```bash +npm install jsx-slack +``` + + + + +```bash +pnpm add jsx-slack +``` + + + + +```bash +yarn add jsx-slack +``` + + + + +If you aren't already using React in your project, you will need to update your `tsconfig.json` file to add the `compilerOptions.jsx` option: + +```json +{ + "compilerOptions": { + "jsx": "react-jsx" + } +} +``` + +### Step 2: Create your BlockKit message + +```tsx +/** @jsxImportSource jsx-slack */ +import JSXSlack, { + Actions, + Blocks, + Button, + Section, + Select, + Option, +} from "jsx-slack"; + +export function progressBlock(blockId: string) { + return JSXSlack( + +
How is your progress today?
+ + + + + +
+ ); +} +``` + +Please note, that to use `jsx-slack` you will need to add the `jsxImportSource` pragma to the top of your file. This is because `jsx-slack` is not a React library, but it uses the same syntax as React. The file also needs to be a `.jsx` or `.tsx` file (like when you use React). + +### Step 3: Use your BlockKit message in a `postMessage` call + + + +```typescript postMessage.ts +import * as slack from "@trigger.dev/slack"; +import { z } from "zod"; +import { progressBlock } from "./messages"; + +const BLOCK_ID = "issue.action.block"; + +//1. every minute see how your employees are doing, we don't recommend this frequency 😉 +new Trigger({ + id: "slack-interactivity", + name: "Testing Slack Interactivity", + on: scheduleEvent({ + rateOf: { + minutes: 1, + }, + }), + run: async (event, ctx) => { + await slack.postMessage("jsx-test", { + channelName: "employee-progress", + text: "How is your progress today?", + blocks: progressBlock(BLOCK_ID), // Pass in the block_id which we'll trigger on in the next step + }); + }, +}).listen(); +``` + +```typescript blockAction.ts +new Trigger({ + id: "slack-block-interaction", + name: "Slack Block Interaction", + on: slack.events.blockActionInteraction({ + blockId: BLOCK_ID, // trigger on the block_id we passed in the previous step + actionId: ["status-blocked", "status-help", "rating"], // we could have also left this blank to trigger on all actions + }), + run: async (event, ctx) => { + if (!event.message) { + return; + } + + const action = event.actions[0]; + + switch (action.action_id) { + case "status-blocked": { + return slack.addReaction("React to message", { + name: "cry", + timestamp: event.message.ts, + channelId: event.channel.id, + }); + } + case "status-help": { + return slack.addReaction("React to message", { + name: "sos", + timestamp: event.message.ts, + channelId: event.channel.id, + }); + } + case "rating": { + if (action.type != "static_select") { + throw new Error("This action should be a select"); + } + + //post the rating as a message that appears below the original, + //only the user pressing the button will see this message + return slack.postMessageResponse( + "Added a comment to the issue", + event.response_url, + { + text: `You rated your day ${action.selected_option?.value} stars`, + replace_original: false, + } + ); + } + } + }, +}).listen(); +``` + + + ## Params @@ -162,3 +454,24 @@ Please see the [Slack Block Actions event payload](https://api.slack.com/referen The channel where the interaction took place. + + + + + The type of container. This will always be `message`. + + + + The timestamp of the message that the user interacted with. + + + + The ID of the channel where the interaction took place. + + + + Whether the message is ephemeral. + + + + diff --git a/apps/docs/package.json b/apps/docs/package.json index 3d7f8b7b4..18824dc33 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -7,6 +7,6 @@ "dev": "mintlify dev --port 3050" }, "devDependencies": { - "mintlify": "^2.0.17" + "mintlify": "2.0.16" } -} +} \ No newline at end of file diff --git a/apps/webapp/app/components/CreateNewWorkflow.tsx b/apps/webapp/app/components/CreateNewWorkflow.tsx index 9c8d9ff71..f168bf751 100644 --- a/apps/webapp/app/components/CreateNewWorkflow.tsx +++ b/apps/webapp/app/components/CreateNewWorkflow.tsx @@ -53,7 +53,7 @@ export function InstallPackages({ packages }: { packages: string }) { =18.0.0'} + dependencies: + pretty: 2.0.0 + react-dom: 18.2.0 + transitivePeerDependencies: + - react + dev: false + /@react-email/render/0.0.3_react@18.2.0: resolution: {integrity: sha512-+4eOrLGdTCJjoJU3PunekErjo3PFnhSDFjVINBHrfJT+1wlVdhWfDo7hFdzXJx/JOOYqmnZTilU/umGLdRumKQ==} engines: {node: '>=18.0.0'} @@ -4922,7 +4931,7 @@ packages: eslint: 8.31.0 eslint-import-resolver-node: 0.3.6 eslint-import-resolver-typescript: 3.5.3_hnftvkj7qg3s6bbigj4pr6djxy - eslint-plugin-import: 2.27.4_qdjeohovcytra7xto5vgmxssaq + eslint-plugin-import: 2.27.4_2ac3tknkazjoq5fxmuugu665ny eslint-plugin-jest: 26.9.0_ohsifnwenhmxgcp7mend4dnv74 eslint-plugin-jest-dom: 4.0.3_eslint@8.31.0 eslint-plugin-jsx-a11y: 6.7.1_eslint@8.31.0 @@ -6046,18 +6055,17 @@ packages: eslint-visitor-keys: 3.3.0 dev: true - /@uiw/codemirror-extensions-basic-setup/4.19.5_tbeldtdcrf45b35pezgkzq2u4e: + /@uiw/codemirror-extensions-basic-setup/4.19.5_wd2tsis3in55bkaiwnc2c46tom: resolution: {integrity: sha512-1zt7ZPJ01xKkSW/KDy0FZNga0bngN1fC594wCVG7FBi60ehfcAucpooQ+JSPScKXopxcb+ugPKZvVLzr9/OfzA==} peerDependencies: '@codemirror/autocomplete': '>=6.0.0' '@codemirror/commands': '>=6.0.0' '@codemirror/language': '>=6.0.0' - '@codemirror/lint': '>=6.0.0' '@codemirror/search': '>=6.0.0' '@codemirror/state': '>=6.0.0' '@codemirror/view': '>=6.0.0' dependencies: - '@codemirror/autocomplete': 6.4.0_eo6pz6bvsllvatnnwfprpuflde + '@codemirror/autocomplete': 6.4.0_czcfkg2f66rxeiodoti7r2gulu '@codemirror/commands': 6.1.3 '@codemirror/language': 6.3.2 '@codemirror/lint': 6.1.0 @@ -6066,14 +6074,11 @@ packages: '@codemirror/view': 6.7.2 dev: false - /@uiw/react-codemirror/4.19.5_aguurb4bmecpxzejz52amioxne: + /@uiw/react-codemirror/4.19.5_k4ec5g7vuuzzonc3d6xbjnmmle: resolution: {integrity: sha512-ZCHh8d7beXbF8/t7F1+yHht6A9Y6CdKeOkZq4A09lxJEnyTQrj1FMf2zvfaqc7K23KNjkTCtSlbqKKbVDgrWaw==} peerDependencies: - '@babel/runtime': '>=7.11.0' '@codemirror/state': '>=6.0.0' - '@codemirror/theme-one-dark': '>=6.0.0' '@codemirror/view': '>=6.0.0' - codemirror: '>=6.0.0' react: '>=16.8.0' react-dom: '>=16.8.0' dependencies: @@ -6082,14 +6087,13 @@ packages: '@codemirror/state': 6.2.0 '@codemirror/theme-one-dark': 6.1.0 '@codemirror/view': 6.7.2 - '@uiw/codemirror-extensions-basic-setup': 4.19.5_tbeldtdcrf45b35pezgkzq2u4e - codemirror: 6.0.1_@lezer+common@1.0.2 + '@uiw/codemirror-extensions-basic-setup': 4.19.5_wd2tsis3in55bkaiwnc2c46tom + codemirror: 6.0.1 react: 18.2.0 react-dom: 18.2.0_react@18.2.0 transitivePeerDependencies: - '@codemirror/autocomplete' - '@codemirror/language' - - '@codemirror/lint' - '@codemirror/search' dev: false @@ -7426,18 +7430,16 @@ packages: engines: {node: '>=0.10.0'} dev: false - /codemirror/6.0.1_@lezer+common@1.0.2: + /codemirror/6.0.1: resolution: {integrity: sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==} dependencies: - '@codemirror/autocomplete': 6.4.0_eo6pz6bvsllvatnnwfprpuflde + '@codemirror/autocomplete': 6.4.0_czcfkg2f66rxeiodoti7r2gulu '@codemirror/commands': 6.1.3 '@codemirror/language': 6.3.2 '@codemirror/lint': 6.1.0 '@codemirror/search': 6.2.3 '@codemirror/state': 6.2.0 '@codemirror/view': 6.7.2 - transitivePeerDependencies: - - '@lezer/common' dev: false /collection-visit/1.0.0: @@ -8778,7 +8780,7 @@ packages: debug: 4.3.4 enhanced-resolve: 5.12.0 eslint: 8.31.0 - eslint-plugin-import: 2.27.4_qdjeohovcytra7xto5vgmxssaq + eslint-plugin-import: 2.27.4_2ac3tknkazjoq5fxmuugu665ny get-tsconfig: 4.3.0 globby: 13.1.3 is-core-module: 2.11.0 @@ -8788,7 +8790,7 @@ packages: - supports-color dev: true - /eslint-module-utils/2.7.4_sqt5xxn4ciiurbqrzlaarm6ama: + /eslint-module-utils/2.7.4_v73lhamtbyinynmwa5fn7kpmfq: resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} engines: {node: '>=4'} peerDependencies: @@ -8813,6 +8815,7 @@ packages: debug: 3.2.7 eslint: 8.31.0 eslint-import-resolver-node: 0.3.7 + eslint-import-resolver-typescript: 3.5.3_hnftvkj7qg3s6bbigj4pr6djxy transitivePeerDependencies: - supports-color dev: true @@ -8837,7 +8840,7 @@ packages: regexpp: 3.2.0 dev: true - /eslint-plugin-import/2.27.4_qdjeohovcytra7xto5vgmxssaq: + /eslint-plugin-import/2.27.4_2ac3tknkazjoq5fxmuugu665ny: resolution: {integrity: sha512-Z1jVt1EGKia1X9CnBCkpAOhWy8FgQ7OmJ/IblEkT82yrFU/xJaxwujaTzLWqigewwynRQ9mmHfX9MtAfhxm0sA==} engines: {node: '>=4'} peerDependencies: @@ -8855,7 +8858,7 @@ packages: doctrine: 2.1.0 eslint: 8.31.0 eslint-import-resolver-node: 0.3.7 - eslint-module-utils: 2.7.4_sqt5xxn4ciiurbqrzlaarm6ama + eslint-module-utils: 2.7.4_v73lhamtbyinynmwa5fn7kpmfq has: 1.0.3 is-core-module: 2.11.0 is-glob: 4.0.3 @@ -12552,8 +12555,8 @@ packages: yallist: 4.0.0 dev: true - /mintlify/2.0.17: - resolution: {integrity: sha512-W7pyIj0AGJYR+vR8E08E7BTMhANW2Kfe3NpfNRdMp+TL1ju50iN49U2T+MBCKQJAycCwXXX2nXf3Cve5sIDdzA==} + /mintlify/2.0.16: + resolution: {integrity: sha512-8SppN2c2F6rt2QlYkDIqZZV9S2jXuUUbWo75eDGURMRfWxpFKGCRxsueY0Oerq/yO/Mlzg5ZNHutJHRipCgLcg==} engines: {node: '>=18.0.0'} hasBin: true dependencies: @@ -14033,6 +14036,15 @@ packages: shallow-equal: 1.2.1 dev: false + /react-dom/18.2.0: + resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} + peerDependencies: + react: ^18.2.0 + dependencies: + loose-envify: 1.4.0 + scheduler: 0.23.0 + dev: false + /react-dom/18.2.0_react@18.2.0: resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} peerDependencies: