-
Notifications
You must be signed in to change notification settings - Fork 399
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
16 changed files
with
307 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
SLACK_BOT_TOKEN=xoxb-your-bot-token | ||
SLACK_SIGNING_SECRET=your-signing-secret |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
.env | ||
dist/ | ||
node_modules/ | ||
package-lock.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# Getting started with TypeScript ⚡️ Bolt for JavaScript | ||
> TypeScript equivalent for Slack app example from 📚 [Getting started with Bolt for JavaScript tutorial][1] | ||
This is a temporary example app intending to show how to work with Bolt's type system. Because the type system is currently lacking, | ||
this app will change in the future. See [#826][2] for more context. | ||
|
||
[1]: https://slack.dev/bolt-js/tutorial/getting-started | ||
[2]: https://github.com/slackapi/bolt-js/issues/826 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
{ | ||
"name": "getting-started-typescript", | ||
"version": "1.0.0", | ||
"description": "Bolt getting started app in TypeScript", | ||
"main": "dist/app.js", | ||
"scripts": { | ||
"build": "tsc -p .", | ||
"build:watch": "tsc -w -p ./src", | ||
"start": "npm run build && node dist/app.js" | ||
}, | ||
"license": "MIT", | ||
"dependencies": { | ||
"@slack/bolt": "^3.3.0", | ||
"dotenv": "^8.2.0" | ||
}, | ||
"devDependencies": { | ||
"@types/node": "^14.14.35", | ||
"ts-node": "^9.1.1", | ||
"typescript": "^4.2.3" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import "./utils/env"; | ||
import { App, LogLevel } from '@slack/bolt'; | ||
import { isGenericMessageEvent } from './utils/helpers' | ||
|
||
const app = new App({ | ||
token: process.env.SLACK_BOT_TOKEN, | ||
signingSecret: process.env.SLACK_SIGNING_SECRET, | ||
logLevel: LogLevel.DEBUG | ||
}); | ||
|
||
// Listens to incoming messages that contain "hello" | ||
app.message('hello', async ({ message, say }) => { | ||
// Filter out message events with subtypes (see https://api.slack.com/events/message) | ||
// Is there a way to do this in listener middleware with current type system? | ||
if (!isGenericMessageEvent(message)) return; | ||
// say() sends a message to the channel where the event was triggered | ||
|
||
await say({ | ||
blocks: [ | ||
{ | ||
type: 'section', | ||
text: { | ||
type: 'mrkdwn', | ||
text: `Hey there <@${message.user}>!` | ||
}, | ||
accessory: { | ||
type: 'button', | ||
text: { | ||
type: 'plain_text', | ||
text: 'Click Me' | ||
}, | ||
action_id: 'button_click' | ||
} | ||
} | ||
], | ||
text: `Hey there <@${message.user}>!` | ||
}); | ||
}); | ||
|
||
app.action('button_click', async ({ body, ack, say }) => { | ||
// Acknowledge the action | ||
await ack(); | ||
await say(`<@${body.user.id}> clicked the button`); | ||
}); | ||
|
||
(async () => { | ||
// Start your app | ||
await app.start(Number(process.env.PORT) || 3000); | ||
|
||
console.log('⚡️ Bolt app is running!'); | ||
})(); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
import "./utils/env"; | ||
import { App, LogLevel, subtype, BotMessageEvent, UsersSelectAction, BlockAction } from '@slack/bolt'; | ||
import { | ||
isGenericMessageEvent, | ||
isMessageItem | ||
} from './utils/helpers' | ||
|
||
const app = new App({ | ||
token: process.env.SLACK_BOT_TOKEN, | ||
signingSecret: process.env.SLACK_SIGNING_SECRET, | ||
logLevel: LogLevel.DEBUG | ||
}); | ||
|
||
/** | ||
* Listening to messages | ||
*/ | ||
// This will match any message that contains 👋 | ||
app.message(':wave:', async ({ message, say }) => { | ||
if (!isGenericMessageEvent(message)) return; | ||
|
||
await say(`Hello, <@${message.user}>`); | ||
}); | ||
|
||
/** | ||
* Sending messages | ||
*/ | ||
// Listens for messages containing "knock knock" and responds with an italicized "who's there?" | ||
app.message('knock knock', async ({ say }) => { | ||
await say(`_Who's there?_`); | ||
}); | ||
|
||
// Sends a section block with datepicker when someone reacts with a 📅 emoji | ||
app.event('reaction_added', async ({ event, client }) => { | ||
// Could be a file that was reacted upon | ||
if (event.reaction === 'calendar' && isMessageItem(event.item)) { | ||
await client.chat.postMessage({ | ||
text: 'Pick a reminder date', | ||
channel: event.item.channel, | ||
blocks: [{ | ||
type: 'section', | ||
text: { | ||
type: 'mrkdwn', | ||
text: 'Pick a date for me to remind you' | ||
}, | ||
accessory: { | ||
type: 'datepicker', | ||
action_id: 'datepicker_remind', | ||
initial_date: '2019-04-28', | ||
placeholder: { | ||
type: 'plain_text', | ||
text: 'Select a date' | ||
} | ||
} | ||
}] | ||
}); | ||
} | ||
}); | ||
|
||
/** | ||
* Listening to events | ||
*/ | ||
const welcomeChannelId = 'C12345'; | ||
|
||
// When a user joins the team, send a message in a predefined channel asking them to introduce themselves | ||
app.event('team_join', async ({ event, client }) => { | ||
try { | ||
// Call chat.postMessage with the built-in client | ||
const result = await client.chat.postMessage({ | ||
channel: welcomeChannelId, | ||
text: `Welcome to the team, <@${event.user}>! 🎉 You can introduce yourself in this channel.` | ||
}); | ||
console.log(result); | ||
} | ||
catch (error) { | ||
console.error(error); | ||
} | ||
}); | ||
|
||
app.message(subtype('bot_message'), async ({ message }) => { | ||
console.log(`The bot user ${(message as BotMessageEvent).user} said ${(message as BotMessageEvent).text}`); | ||
}); | ||
|
||
/** | ||
* Using the Web API | ||
*/ | ||
// Unix Epoch time for September 30, 2019 11:59:59 PM | ||
const whenSeptemberEnds = '1569887999'; | ||
|
||
app.message('wake me up', async ({ message, client }) => { | ||
try { | ||
// Call chat.scheduleMessage with the built-in client | ||
const result = await client.chat.scheduleMessage({ | ||
channel: message.channel, | ||
post_at: whenSeptemberEnds, | ||
text: 'Summer has come and passed' | ||
}); | ||
} | ||
catch (error) { | ||
console.error(error); | ||
} | ||
}); | ||
|
||
/** | ||
* Listening to actions | ||
*/ | ||
// Your listener function will be called every time an interactive component with the action_id "approve_button" is triggered | ||
app.action('approve_button', async ({ ack }) => { | ||
await ack(); | ||
// Update the message to reflect the action | ||
}); | ||
|
||
// Your listener function will only be called when the action_id matches 'select_user' AND the block_id matches 'assign_ticket' | ||
app.action({ action_id: 'select_user', block_id: 'assign_ticket' }, | ||
async ({ body, client, ack }) => { | ||
await ack(); | ||
// TODO | ||
body = body as BlockAction; | ||
try { | ||
// Make sure the event is not in a view | ||
if (body.message) { | ||
await client.reactions.add({ | ||
name: 'white_check_mark', | ||
timestamp: body.message?.ts, | ||
channel: body.channel?.id | ||
}); | ||
} | ||
} | ||
catch (error) { | ||
console.error(error); | ||
} | ||
}); | ||
|
||
// Your middleware will be called every time an interactive component with the action_id “approve_button” is triggered | ||
app.action('approve_button', async ({ ack, say }) => { | ||
// Acknowledge action request | ||
await ack(); | ||
await say('Request approved 👍'); | ||
}); | ||
|
||
(async () => { | ||
// Start your app | ||
await app.start(Number(process.env.PORT) || 3000); | ||
|
||
console.log('⚡️ Bolt app is running!'); | ||
})(); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
// for details see https://github.com/motdotla/dotenv/blob/master/examples/typescript/ | ||
import { resolve } from 'path' | ||
import { config } from 'dotenv' | ||
|
||
const pathToConfig = '../../.env'; | ||
config({ path: resolve(__dirname, pathToConfig) }); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { | ||
GenericMessageEvent, | ||
MessageEvent, | ||
ReactionAddedEvent, | ||
ReactionMessageItem | ||
} from '@slack/bolt'; | ||
|
||
|
||
export const isGenericMessageEvent = (msg: MessageEvent): msg is GenericMessageEvent => { | ||
return (msg as GenericMessageEvent).subtype === undefined; | ||
} | ||
|
||
export const isMessageItem = (item: ReactionAddedEvent["item"]): item is ReactionMessageItem => { | ||
return (item as ReactionMessageItem).type === 'message'; | ||
} |
Oops, something went wrong.