Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
12dfc8d
Added scope that should allow posting as a custom name “chat:write.cu…
matt-aitken Jan 25, 2023
809ffe2
Added Slack blocks schemas
matt-aitken Jan 25, 2023
1843a2f
Created a zod helper that can parse from snake_case to camelCase and …
matt-aitken Jan 25, 2023
51c295f
Added type-fest to trigger-providers as a dev dependency
matt-aitken Jan 25, 2023
001cd81
Added Slack block schemas
matt-aitken Jan 25, 2023
2ab9b5f
Build the service request objects ahead of time so we can easily log …
matt-aitken Jan 25, 2023
972444d
Slack example with lots of blocks
matt-aitken Jan 25, 2023
109d81d
Slack blocks schemas are finally parsing properly…
matt-aitken Jan 25, 2023
e607281
Pass Zod issues back from HTTPService, so they can be displayed
matt-aitken Jan 25, 2023
bce1bd1
Example with a Slack post that looks like it’s from someone else
matt-aitken Jan 25, 2023
764f5c1
IntegrationRequest input code block has a max height on it
matt-aitken Jan 25, 2023
33128bc
Move Slack requests to a separate file
matt-aitken Jan 25, 2023
31a8e36
Edited YT iframe and added blurb to the resend examples box
D-K-P Jan 26, 2023
1a20d1b
Added explaination on how to send an event using cURL to the docs
matt-aitken Jan 26, 2023
518472f
Fix for page count being wrong on runs table
matt-aitken Jan 26, 2023
a4bd86f
Added a typeform to vote for integrations we don’t support
samejr Jan 26, 2023
e553029
Scope the test data to the correct organization
matt-aitken Jan 26, 2023
543589a
Merge remote-tracking branch 'origin/dev' into integrations/slack-blocks
matt-aitken Jan 26, 2023
86c543c
Fire off internal custom events for user.created and workflow.created
ericallam Jan 26, 2023
7e7c8da
Slack interactivity hook responds with 200
matt-aitken Jan 27, 2023
897724e
Merge branch 'integrations/slack-blocks' into dev
matt-aitken Jan 27, 2023
52d21ac
Added support for delaying delivery when sending custom events
ericallam Jan 27, 2023
057a13b
Slack integration improvements
ericallam Jan 27, 2023
e8a29dc
Added login and sign up buttons, changed logo to point to app.trigger…
D-K-P Jan 27, 2023
74df0b7
Fix for example workflow when mesage is undefined
matt-aitken Jan 27, 2023
b75ef02
Added schema for blocks
matt-aitken Jan 27, 2023
9f935cd
Use jsx-slack in the Slack example
matt-aitken Jan 27, 2023
ffacc2f
Added a static select dropdown and lots more schema work
matt-aitken Jan 27, 2023
617cc22
Added new slack integration workflow type
samejr Jan 27, 2023
75eca28
Added more dropdown support
matt-aitken Jan 27, 2023
128f3ba
Added way more action types
matt-aitken Jan 27, 2023
65b78f8
Small fix for overflowing username/email address in menu
samejr Jan 27, 2023
b327d1b
Fixed links to quick start guide
samejr Jan 28, 2023
719c2a6
Added contact to resend docs
D-K-P Jan 28, 2023
96ff7f1
Added more interactive elements
matt-aitken Jan 28, 2023
2d72c11
Fix for dropdown schema failure. Added nice example
matt-aitken Jan 28, 2023
dd62655
Added documentation for posting block Slack messages
matt-aitken Jan 28, 2023
f5b88ce
Deal with optional in Slack example
matt-aitken Jan 28, 2023
e1b26c8
Improved the Slack interaction trigger block style
matt-aitken Jan 28, 2023
b290410
Changeset added: Slack blocks support
matt-aitken Jan 28, 2023
28cc99b
Changeset version: Slack blocks support
matt-aitken Jan 28, 2023
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
4 changes: 3 additions & 1 deletion apps/docs/examples/examples.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,7 @@ You can use these workflows in your product by following the instructions on eac
<Card title="Slack" icon="slack" href="/examples/slack">
Post to Slack when a GitHub issue is created or modified.
</Card>
<Card title="Resend" icon="envelope" href="/examples/resend"></Card>
<Card title="Resend" icon="envelope" href="/examples/resend">
Create a welcome email drip campaign.
</Card>
</CardGroup>
5 changes: 5 additions & 0 deletions apps/docs/examples/resend.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ sidebarTitle: "Resend"
description: "Here are some example workflows you could create using the Resend integration."
---

<Tip>
Resend is in private beta, if you would like access please contact us at{" "}
<a href="mailto:help@trigger.dev">help@trigger.dev</a>
</Tip>

## Welcome email drip campaign

This workflow will get triggered and a Slack notification and welcom email will be sent straight away.
Expand Down
181 changes: 176 additions & 5 deletions apps/docs/functions/send-event.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ sidebarTitle: "Send event"
description: "Send events to trigger your custom events workflows."
---

## How to send an event
## Send an event

You can send an event from anywhere in your code, including from inside another workflow.
You can easily send an event from anywhere, including from inside another workflow. Events don't have to come from the same server as your workflow and can be sent as HTTP requests from any language (see our cURL example below for the format).

<Tabs>
<Tab title="Our Node.js SDK">

```ts
import { sendEvent } from "@trigger.dev/sdk";
Expand All @@ -19,12 +22,180 @@ await sendEvent("start-fire-2", {
});
```

</Tab>
<Tab title="cURL">

```bash
curl --request POST \
--url https://app.trigger.dev/api/v1/events \
--header 'Authorization: Bearer <insert_api_key_here>' \
--header 'Content-Type: application/json' \
--data '{
"id": "<optional unique event id>",
"event": {
"name": "user.created",
"payload": {
"userId": "123456"
}
}
}'
```

</Tab>
</Tabs>

If you are calling this from inside a workflow, ensure that the first parameter is unique inside your workflow.

## Sending events from other workflows

It is useful to send events from workflows because you can split your logic into smaller chunks and reuse them.
It is useful to send events from workflows because you can split your logic into smaller chunks and reuse them. The below example shows how a scheduled workflow delegates the work via sending a custom event:

<CodeGroup>

```ts check-scheduler.ts
new Trigger({
id: "check-scheduler",
name: "Check Scheduler",
on: scheduleEvent({ rateOf: { minutes: 10 } }),
run: async (event, context) => {
await context.sendEvent("health.check trigger.dev", {
name: "health.check",
payload: {
url: "https://trigger.dev",
host: "trigger.dev",
},
});

await context.sendEvent("health.check docs.trigger.dev", {
name: "health.check",
payload: {
url: "https://docs.trigger.dev",
host: "docs.trigger.dev",
},
});

await context.sendEvent("health.check app.trigger.dev", {
name: "health.check",
payload: {
url: "https://app.trigger.dev/healthcheck",
host: "app.trigger.dev",
},
});
},
}).listen();
```

```ts health-check.ts
export const healthCheck = new Trigger({
id: "health-check",
name: "Health Check",
on: customEvent({
name: "health.check",
schema: z.object({
url: z.string().url(),
host: z.string(),
}),
}),
run: async (event, context) => {
const response = await context.fetch("fetch site", event.url, {
method: "GET",
retry: {
enabled: false,
},
});

if (response.ok) {
await context.logger.info(`${event.host} is up!`);
return;
}

await slack.postMessage("Site is down", {
channelName: "health-checks",
text: `${event.host} is down: ${response.status}`,
});
},
}).listen();
```

</CodeGroup>

## Delaying event delivery

## Writing a workflow that is triggered by an event
Through both our Node.js SDK and our HTTP API, you can delay the delivery of an event. This is useful if you want to send an event to trigger a workflow, but you want to wait for a certain amount of time before the event is delivered.

You should read [the documentation on custom events](/triggers/custom-events) to learn how to write a workflow that is triggered by an event.
Using the health check example above, we can delay the delivery of the `health.check` event in various ways:

```ts
new Trigger({
id: "check-scheduler",
name: "Check Scheduler",
on: scheduleEvent({ rateOf: { minutes: 10 } }),
run: async (event, context) => {
await context.sendEvent("health.check trigger.dev", {
name: "health.check",
payload: {
url: "https://trigger.dev",
host: "trigger.dev",
},
delay: { until: new Date(Date.now() + 1000 * 60 * 5) }, // Delay until a specific date
});

await context.sendEvent("health.check docs.trigger.dev", {
name: "health.check",
payload: {
url: "https://docs.trigger.dev",
host: "docs.trigger.dev",
},
delay: { minutes: 5 }, // Delay for a specific amount of time
});

await context.sendEvent("health.check app.trigger.dev", {
name: "health.check",
payload: {
url: "https://app.trigger.dev/healthcheck",
host: "app.trigger.dev",
},
delay: { seconds: 30 }, // Delay for a specific amount of time
});
},
}).listen();
```

<Note>
When sending events in the context of a workflow run, adding a delay DOES NOT
add a delay to the workflow run, as sending a custom event is a
fire-and-forget action.
</Note>

You can add delays via the HTTP API by adding a `delay` object to the event:

```bash
curl --request POST \
--url https://app.trigger.dev/api/v1/events \
--header 'Authorization: Bearer <insert_api_key_here>' \
--header 'Content-Type: application/json' \
--data '{
"id": "<optional unique event id>",
"event": {
"name": "user.created",
"payload": {
"userId": "123456"
},
"delay": {
"seconds": 30
}
}
}'
```

## Event deduplication

When sending events, you can specify an `id` for the event. If you send an event with the same `id` multiple times, only the first event will be delivered. This is useful if you want to ensure that an event is only delivered once, even if you send it multiple times.

```ts
sendEvent({
id: "my-event-id",
name: "my-event",
payload: { foo: "bar" },
});
```
148 changes: 143 additions & 5 deletions apps/docs/integrations/apis/slack/actions/post-message.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ Publish slack messages to a public or private channel in your Slack Workspace as
The formatted text of the message to be published, formatted as [mrkdwn](https://api.slack.com/reference/surfaces/formatting#basics).
</ParamField>

<ParamField path="blocks" type="object" required={false}>
You can use blocks to create a rich message with images, buttons, and more.

You can either pass in a JavaScript object or use [JSX Slack](https://github.com/yhatt/jsx-slack/) to create blocks. We highly recommend using JSX Slack, it's much easier to read and write. See the [block example](#) to see it in action.

Full full detail on block see the [Slack API docs](https://api.slack.com/reference/block-kit/blocks).
</ParamField>

</Expandable>
</ParamField>

Expand Down Expand Up @@ -69,6 +77,8 @@ Publish slack messages to a public or private channel in your Slack Workspace as

## Example Workflows

### Notify Slack on New Star

<CodeGroup>

```typescript Notify Slack on New Star
Expand All @@ -89,11 +99,7 @@ new Trigger({
}).listen();
```

</CodeGroup>

## Example Response

```json
```json Example response
{
"ok": true,
"ts": "1673618429.084699",
Expand All @@ -107,3 +113,135 @@ new Trigger({
}
}
```

</CodeGroup>

### Blocks with interactivity

You can add interaction and richer visual elements using Blocks. The easiest way to add them is using `jsx-slack` (which is a separate npm package that you can install).

This example messages your team every minute (!) and asks them how they're doing. There are two buttons and a dropdown menu.

In this examples there are two workflows:

1. Messages your team every minute (!) and asks them how they're doing.
2. Receives the interaction from users. It adds reactions when the buttons are pressed and posts a message when a user selects from the dropdown menu.

<CodeGroup>

```typescript Blocks with interactivity
import { slack } from "@trigger.dev/integrations";
import JSXSlack, {
Actions,
Blocks,
Button,
Section,
Select,
Option,
} from "jsx-slack";
import { z } from "zod";

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: "test-integrations",
//text appears in Slack notifications on mobile/desktop
text: "How is your progress today?",
//import and use JSXSlack to make creating rich messages much easier
blocks: JSXSlack(
<Blocks>
<Section>How is your progress today?</Section>
<Actions blockId={BLOCK_ID}>
<Button value="blocked" actionId="status-blocked">
I'm blocked
</Button>
<Button
value="help"
actionId="status-help"
url="https://xkcd.com/1349/"
>
Get help
</Button>
<Select actionId="rating" placeholder="Rate it!">
<Option value="5">5 {":star:".repeat(5)}</Option>
<Option value="4">4 {":star:".repeat(4)}</Option>
<Option value="3">3 {":star:".repeat(3)}</Option>
<Option value="2">2 {":star:".repeat(2)}</Option>
<Option value="1">1 {":star:".repeat(1)}</Option>
</Select>
</Actions>
</Blocks>
),
});
},
}).listen();

//2. this workflow listens for Slack interactions filtered by the block id and actions we used above
new Trigger({
id: "slack-block-interaction",
name: "Slack Block Interaction",
on: slack.events.blockActionInteraction({
blockId: BLOCK_ID,
actionId: ["status-blocked", "status-help", "rating"],
}),
run: async (event, ctx) => {
//create promises from all the actions
const promises = event.actions.map((action) => {
switch (action.action_id) {
case "status-blocked": {
//the user is blocked so add a 😢 emoji as a reaction
if (event.message) {
return slack.addReaction("React to message", {
name: "cry",
timestamp: event.message.ts,
channelId: event.channel.id,
});
}
}
case "status-help": {
//the user needs help so add an 🆘 emoji as a reaction
if (event.message) {
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,
}
);
}
default:
return Promise.resolve();
}
});

await Promise.all(promises);
},
}).listen();
```

</CodeGroup>
Loading